<commit_before>use std::io::{Read, Write};
use std::net::TcpStream;
use std::{io, thread};
use std::os::unix::io::{AsRawFd};
use std::sync::mpsc::{channel, Sender};

use pty;
use libc;
use libc_ext;
use nix::sys::signal;
use termios::*;

use pty_spawn;
use winsize;
use message;

pub fn execute(host: String, port: i32, channel_name: String) {
    let mut stream         = TcpStream::connect(&format!("{}:{}", host, port)[..]).unwrap();
    let (child, termios)   = pty_spawn::pty_spawn();
    let (sender, receiver) = channel();

    let request = message::JoinRequest::Broadcast(channel_name.clone());
    request.send(&mut stream).unwrap();
    message::JoinResponse::receive(&stream).unwrap();

    InputHandler::spawn(io::stdin(), &child);
    OutputHandler::spawn(io::stdout(), &child, &sender);
    ResizeHandler::spawn(&child, &sender);
    NotificationHandler::spawn(&stream, &sender);

    sender.send(build_winsize_notification()).unwrap();

    for message in receiver {
        match message {
            Some(notification) => notification.send(&mut stream).unwrap(),
            None => break
        };
    }

    child.wait().unwrap();
    tcsetattr(libc::STDIN_FILENO, TCSANOW, &termios).unwrap();
}

fn build_winsize_notification() -> Option<message::Notification> {
    let winsize      = winsize::from_fd(libc::STDIN_FILENO).unwrap();
    let notification = message::Notification::Output(format!("\x1b[8;{};{}t", winsize.ws_row, winsize.ws_col));

    Some(notification)
}

static mut sigwinch_count: i32 = 0;
extern fn handle_sigwinch(_: i32) {
    unsafe { sigwinch_count += 1; };
}

struct InputHandler {
    input: io::Stdin,
    child: pty::Child,
}

struct OutputHandler {
    output: io::Stdout,
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct ResizeHandler {
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct NotificationHandler {
    stream: TcpStream,
    sender: Sender<Option<message::Notification>>,
}

impl InputHandler {
    fn spawn(input: io::Stdin, child: &pty::Child) {
        let mut handler = InputHandler { input: input, child: child.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();

        loop {
            let mut buf = vec![0; 128];
            let nread   = self.input.read(&mut buf[..]).unwrap();

            buf.truncate(nread as usize);
            pty.write(&buf).unwrap();
        }
    }
}

impl OutputHandler {
    fn spawn(output: io::Stdout, child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let mut handler = OutputHandler { output: output, child: child.clone(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();

        loop {
            let mut buf = vec![0; 128];

            if pty.read(&mut buf).unwrap() <= 0 {
                break;
            } else {
                let string = String::from_utf8_lossy(&buf[..]).into_owned();

                self.handle_output(&string);
            }
        }

        self.handle_terminate();
    }

    fn handle_output(&mut self, string: &String) {
        let notification = message::Notification::Output(string.clone());

        print!("{}", string);
        self.output.flush().unwrap();

        self.sender.send(Some(notification)).unwrap();
    }

    fn handle_terminate(&self) {
        self.sender.send(None).unwrap();
    }
}

impl ResizeHandler {
    fn spawn(child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let handler = ResizeHandler { child: child.clone(), sender: sender.clone() };

        Self::register_sigwinch_handler();

        thread::spawn(move || {
            handler.process();
        });
    }

    fn register_sigwinch_handler() {
        let sig_action = signal::SigAction::new(
            handle_sigwinch,
            signal::signal::SA_RESTART,
            signal::SigSet::empty()
        );

        unsafe { signal::sigaction(signal::SIGWINCH, &sig_action).unwrap(); };
    }

    fn process(&self) {
        let mut count = unsafe { sigwinch_count };

        loop {
            let last_count = unsafe { sigwinch_count };

            if last_count > count {
                let winsize = winsize::from_fd(libc::STDIN_FILENO).unwrap();

                self.handle_resize(&winsize);

                count = last_count;
            }

            thread::sleep_ms(1000);
        }
    }

    fn handle_resize(&self, winsize: &libc_ext::Winsize) {
        let pty = self.child.pty().unwrap();

        self.sender.send(build_winsize_notification()).unwrap();
        winsize::set(pty.as_raw_fd(), winsize);
    }
}

impl NotificationHandler {
    fn spawn(stream: &TcpStream, sender: &Sender<Option<message::Notification>>) {
        let mut handler = NotificationHandler { stream: stream.try_clone().unwrap(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        loop {
            let notification = message::Notification::receive(&self.stream).unwrap();

            match notification {
                message::Notification::Closed(reason) => {
                    self.handle_closed(&reason);

                    break;
                },
                message::Notification::WatcherJoined(_) => {
                    self.sender.send(build_winsize_notification()).unwrap();
                },
                _ => ()
            }
        }
    }

    fn handle_closed(&self, reason: &String) {
        self.sender.send(None).unwrap();

        println!("Broadcast has stopped: {}", reason);
    }
}
<commit_msg>Initialize a buffer before out of the loop<commit_after>use std::io::{Read, Write};
use std::net::TcpStream;
use std::{io, thread};
use std::os::unix::io::{AsRawFd};
use std::sync::mpsc::{channel, Sender};

use pty;
use libc;
use libc_ext;
use nix::sys::signal;
use termios::*;

use pty_spawn;
use winsize;
use message;

pub fn execute(host: String, port: i32, channel_name: String) {
    let mut stream         = TcpStream::connect(&format!("{}:{}", host, port)[..]).unwrap();
    let (child, termios)   = pty_spawn::pty_spawn();
    let (sender, receiver) = channel();

    let request = message::JoinRequest::Broadcast(channel_name.clone());
    request.send(&mut stream).unwrap();
    message::JoinResponse::receive(&stream).unwrap();

    InputHandler::spawn(io::stdin(), &child);
    OutputHandler::spawn(io::stdout(), &child, &sender);
    ResizeHandler::spawn(&child, &sender);
    NotificationHandler::spawn(&stream, &sender);

    sender.send(build_winsize_notification()).unwrap();

    for message in receiver {
        match message {
            Some(notification) => notification.send(&mut stream).unwrap(),
            None => break
        };
    }

    child.wait().unwrap();
    tcsetattr(libc::STDIN_FILENO, TCSANOW, &termios).unwrap();
}

fn build_winsize_notification() -> Option<message::Notification> {
    let winsize      = winsize::from_fd(libc::STDIN_FILENO).unwrap();
    let notification = message::Notification::Output(format!("\x1b[8;{};{}t", winsize.ws_row, winsize.ws_col));

    Some(notification)
}

static mut sigwinch_count: i32 = 0;
extern fn handle_sigwinch(_: i32) {
    unsafe { sigwinch_count += 1; };
}

struct InputHandler {
    input: io::Stdin,
    child: pty::Child,
}

struct OutputHandler {
    output: io::Stdout,
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct ResizeHandler {
    child:  pty::Child,
    sender: Sender<Option<message::Notification>>,
}

struct NotificationHandler {
    stream: TcpStream,
    sender: Sender<Option<message::Notification>>,
}

impl InputHandler {
    fn spawn(input: io::Stdin, child: &pty::Child) {
        let mut handler = InputHandler { input: input, child: child.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = self.input.read(&mut buf).unwrap();

            pty.write(&buf[..nread]).unwrap();
        }
    }
}

impl OutputHandler {
    fn spawn(output: io::Stdout, child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let mut handler = OutputHandler { output: output, child: child.clone(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        let mut pty = self.child.pty().unwrap();
        let mut buf = [0; 128];

        loop {
            let nread = pty.read(&mut buf).unwrap();

            if nread <= 0 {
                break;
            } else {
                let string = String::from_utf8_lossy(&buf[..nread]).into_owned();

                self.handle_output(string);
            }
        }

        self.handle_terminate();
    }

    fn handle_output(&mut self, string: String) {
        print!("{}", string);
        self.output.flush().unwrap();

        self.sender.send(Some(message::Notification::Output(string))).unwrap();
    }

    fn handle_terminate(&self) {
        self.sender.send(None).unwrap();
    }
}

impl ResizeHandler {
    fn spawn(child: &pty::Child, sender: &Sender<Option<message::Notification>>) {
        let handler = ResizeHandler { child: child.clone(), sender: sender.clone() };

        Self::register_sigwinch_handler();

        thread::spawn(move || {
            handler.process();
        });
    }

    fn register_sigwinch_handler() {
        let sig_action = signal::SigAction::new(
            handle_sigwinch,
            signal::signal::SA_RESTART,
            signal::SigSet::empty()
        );

        unsafe { signal::sigaction(signal::SIGWINCH, &sig_action).unwrap(); };
    }

    fn process(&self) {
        let mut count = unsafe { sigwinch_count };

        loop {
            let last_count = unsafe { sigwinch_count };

            if last_count > count {
                let winsize = winsize::from_fd(libc::STDIN_FILENO).unwrap();

                self.handle_resize(&winsize);

                count = last_count;
            }

            thread::sleep_ms(1000);
        }
    }

    fn handle_resize(&self, winsize: &libc_ext::Winsize) {
        let pty = self.child.pty().unwrap();

        self.sender.send(build_winsize_notification()).unwrap();
        winsize::set(pty.as_raw_fd(), winsize);
    }
}

impl NotificationHandler {
    fn spawn(stream: &TcpStream, sender: &Sender<Option<message::Notification>>) {
        let mut handler = NotificationHandler { stream: stream.try_clone().unwrap(), sender: sender.clone() };

        thread::spawn(move || {
            handler.process();
        });
    }

    fn process(&mut self) {
        loop {
            let notification = message::Notification::receive(&self.stream).unwrap();

            match notification {
                message::Notification::Closed(reason) => {
                    self.handle_closed(&reason);

                    break;
                },
                message::Notification::WatcherJoined(_) => {
                    self.sender.send(build_winsize_notification()).unwrap();
                },
                _ => ()
            }
        }
    }

    fn handle_closed(&self, reason: &String) {
        self.sender.send(None).unwrap();

        println!("Broadcast has stopped: {}", reason);
    }
}
<|endoftext|>


<commit_before>//! ES response for various ES queries, these only serialize the fields that we use,
/// which can be prone to change in the future
use serde::{Deserialize, Deserializer};
use serde_json::Value;

/// ES response for a search query.
#[derive(Deserialize)]
pub struct ElasticsearchSearchResponse<D> {
    pub pit_id: Option<String>,
    pub hits: ElasticsearchHits<D>,
}

#[derive(Deserialize)]
pub struct ElasticsearchHits<D> {
    pub hits: Vec<ElasticsearchHit<D>>,
}

#[derive(Deserialize)]
pub struct ElasticsearchHit<D> {
    #[serde(rename = "_source")]
    pub source: D,
    #[serde(default)]
    pub sort: Vec<Value>,
}

impl<D> ElasticsearchSearchResponse<D> {
    /// Consume the response into an iterator over the responded documents.
    pub fn into_hits(self) -> impl Iterator<Item = D> {
        self.hits.hits.into_iter().map(|hit| hit.source)
    }
}

/// ES response for a get query.
#[derive(Deserialize)]
pub struct ElasticsearchGetResponse<D> {
    pub docs: Vec<ElasticsearchDocs<D>>,
}

#[derive(Deserialize)]
pub struct ElasticsearchDocs<D> {
    #[serde(rename = "_source")]
    pub source: Option<D>,
}

impl<D> ElasticsearchGetResponse<D> {
    /// Consume the response into an iterator over the responded documents.
    pub fn into_docs(self) -> impl Iterator<Item = D> {
        self.docs.into_iter().filter_map(|doc| doc.source)
    }
}

/// ES response for bulk insert queries.
#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkResponse {
    pub items: Vec<ElasticsearchBulkItem>,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElasticsearchBulkItem {
    Index(ElasticsearchBulkStatus),
    Update(ElasticsearchBulkStatus),
}

impl ElasticsearchBulkItem {
    pub fn inner(self) -> ElasticsearchBulkStatus {
        match self {
            ElasticsearchBulkItem::Index(inner) => inner,
            ElasticsearchBulkItem::Update(inner) => inner,
        }
    }
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkStatus {
    pub status: u16,
    #[serde(flatten, deserialize_with = "deserialize_bulk_result")]
    pub result: Result<ElasticsearchBulkResult, ElasticsearchBulkError>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElasticsearchBulkResult {
    Created,
    Updated,
    Deleted,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticSearchBulkErrorCausedBy {
    #[serde(rename = "type")]
    pub caused_by_type: String,
    pub reason: String,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkError {
    #[serde(rename = "type")]
    pub err_type: String,
    pub reason: String,
    pub index: Option<String>,
    pub index_uuid: Option<String>,
    pub shard: Option<String>,
    pub caused_by: Option<ElasticSearchBulkErrorCausedBy>,
}

// Custom deserializers

/// Serialize { "result": T, "error": E } into a Result<T, E>
pub fn deserialize_bulk_result<'de, D, T: Deserialize<'de>, E: Deserialize<'de>>(
    deserializer: D,
) -> Result<Result<T, E>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(rename_all = "lowercase")]
    pub enum ElasticsearchResult<T, E> {
        Result(T),
        Error(E),
    }

    Ok({
        match Deserialize::deserialize(deserializer)? {
            ElasticsearchResult::Result(x) => Ok(x),
            ElasticsearchResult::Error(err) => Err(err),
        }
    })
}

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

    /// Build a sample response for Bulk API adapted from documentation:
    /// https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk-api-example
    fn sample() -> serde_json::Value {
        json!({
            "took": 486,
            "errors": true,
            "items": [
                {
                    "index": {
                        "_index": "index1",
                        "_type" : "_doc",
                        "_id": "5",
                        "status": 404,
                        "error": {
                            "type": "document_missing_exception",
                            "reason": "[_doc][5]: document missing",
                            "index_uuid": "aAsFqTI0Tc2W0LCWgPNrOA",
                            "shard": "0",
                            "index": "index1"
                        }
                    }
                },
                {
                    "update": {
                        "_index": "index1",
                        "_type" : "_doc",
                        "_id": "7",
                        "_version": 1,
                        "result": "created",
                        "_shards": {
                            "total": 2,
                            "successful": 1,
                            "failed": 0
                        },
                        "_seq_no": 0,
                        "_primary_term": 1,
                        "status": 201
                    }
                }
            ]
        })
    }

    #[test]
    fn test_elasticsearch_bulk_response_model() {
        let response: ElasticsearchBulkResponse = serde_json::from_value(sample()).unwrap();

        assert_eq!(
            response,
            ElasticsearchBulkResponse {
                items: vec![
                    ElasticsearchBulkItem::Index(ElasticsearchBulkStatus {
                        status: 404,
                        result: Err(ElasticsearchBulkError {
                            err_type: "document_missing_exception".to_string(),
                            reason: "[_doc][5]: document missing".to_string(),
                            index: "index1".to_string().into(),
                            index_uuid: "aAsFqTI0Tc2W0LCWgPNrOA".to_string().into(),
                            shard: "0".to_string().into(),
                        })
                    }),
                    ElasticsearchBulkItem::Update(ElasticsearchBulkStatus {
                        status: 201,
                        result: Ok(ElasticsearchBulkResult::Created)
                    })
                ]
            }
        )
    }
}
<commit_msg>tests added<commit_after>//! ES response for various ES queries, these only serialize the fields that we use,
/// which can be prone to change in the future
use serde::{Deserialize, Deserializer};
use serde_json::Value;

/// ES response for a search query.
#[derive(Deserialize)]
pub struct ElasticsearchSearchResponse<D> {
    pub pit_id: Option<String>,
    pub hits: ElasticsearchHits<D>,
}

#[derive(Deserialize)]
pub struct ElasticsearchHits<D> {
    pub hits: Vec<ElasticsearchHit<D>>,
}

#[derive(Deserialize)]
pub struct ElasticsearchHit<D> {
    #[serde(rename = "_source")]
    pub source: D,
    #[serde(default)]
    pub sort: Vec<Value>,
}

impl<D> ElasticsearchSearchResponse<D> {
    /// Consume the response into an iterator over the responded documents.
    pub fn into_hits(self) -> impl Iterator<Item = D> {
        self.hits.hits.into_iter().map(|hit| hit.source)
    }
}

/// ES response for a get query.
#[derive(Deserialize)]
pub struct ElasticsearchGetResponse<D> {
    pub docs: Vec<ElasticsearchDocs<D>>,
}

#[derive(Deserialize)]
pub struct ElasticsearchDocs<D> {
    #[serde(rename = "_source")]
    pub source: Option<D>,
}

impl<D> ElasticsearchGetResponse<D> {
    /// Consume the response into an iterator over the responded documents.
    pub fn into_docs(self) -> impl Iterator<Item = D> {
        self.docs.into_iter().filter_map(|doc| doc.source)
    }
}

/// ES response for bulk insert queries.
#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkResponse {
    pub items: Vec<ElasticsearchBulkItem>,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElasticsearchBulkItem {
    Index(ElasticsearchBulkStatus),
    Update(ElasticsearchBulkStatus),
}

impl ElasticsearchBulkItem {
    pub fn inner(self) -> ElasticsearchBulkStatus {
        match self {
            ElasticsearchBulkItem::Index(inner) => inner,
            ElasticsearchBulkItem::Update(inner) => inner,
        }
    }
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkStatus {
    pub status: u16,
    #[serde(flatten, deserialize_with = "deserialize_bulk_result")]
    pub result: Result<ElasticsearchBulkResult, ElasticsearchBulkError>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElasticsearchBulkResult {
    Created,
    Updated,
    Deleted,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticSearchBulkErrorCausedBy {
    #[serde(rename = "type")]
    pub caused_by_type: String,
    pub reason: String,
}

#[derive(Debug, Eq, PartialEq, Deserialize)]
pub struct ElasticsearchBulkError {
    #[serde(rename = "type")]
    pub err_type: String,
    pub reason: String,
    pub index: Option<String>,
    pub index_uuid: Option<String>,
    pub shard: Option<String>,
    pub caused_by: Option<ElasticSearchBulkErrorCausedBy>,
}

// Custom deserializers

/// Serialize { "result": T, "error": E } into a Result<T, E>
pub fn deserialize_bulk_result<'de, D, T: Deserialize<'de>, E: Deserialize<'de>>(
    deserializer: D,
) -> Result<Result<T, E>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(rename_all = "lowercase")]
    pub enum ElasticsearchResult<T, E> {
        Result(T),
        Error(E),
    }

    Ok({
        match Deserialize::deserialize(deserializer)? {
            ElasticsearchResult::Result(x) => Ok(x),
            ElasticsearchResult::Error(err) => Err(err),
        }
    })
}

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

    /// Build a sample response for Bulk API adapted from documentation:
    /// https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk-api-example
    fn sample() -> serde_json::Value {
        json!({
            "took": 486,
            "errors": true,
            "items": [
                {
                    "index": {
                        "_index": "index1",
                        "_type" : "_doc",
                        "_id": "5",
                        "status": 404,
                        "error": {
                            "type": "document_missing_exception",
                            "reason": "[_doc][5]: document missing",
                            "index_uuid": "aAsFqTI0Tc2W0LCWgPNrOA",
                            "shard": "0",
                            "index": "index1"
                        }
                    }
                },
                {
                    "update": {
                        "_index": "index1",
                        "_type" : "_doc",
                        "_id": "7",
                        "_version": 1,
                        "result": "created",
                        "_shards": {
                            "total": 2,
                            "successful": 1,
                            "failed": 0
                        },
                        "_seq_no": 0,
                        "_primary_term": 1,
                        "status": 201
                    }
                }
            ]
        })
    }

    fn sample_400_error() -> serde_json::Value {
        json!({
            "took": 0,
            "errors": true,
            "items": [
                {
                    "index": {
                    "_index": "test_coord",
                    "_type": "_doc",
                    "_id": "1",
                    "status": 400,
                    "error": {
                        "type": "mapper_parsing_exception",
                        "reason": "failed to parse",
                        "caused_by": {
                            "type": "invalid_shape_exception",
                            "reason": "Bad X value -7703653.0 is not in boundary Rect(minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0)"
                        }
                    }
                }
                }
            ]
        })
    }

    #[test]
    fn test_elasticsearch_bulk_response_model() {
        let response: ElasticsearchBulkResponse = serde_json::from_value(sample()).unwrap();

        assert_eq!(
            response,
            ElasticsearchBulkResponse {
                items: vec![
                    ElasticsearchBulkItem::Index(ElasticsearchBulkStatus {
                        status: 404,
                        result: Err(ElasticsearchBulkError {
                            err_type: "document_missing_exception".to_string(),
                            reason: "[_doc][5]: document missing".to_string(),
                            index: "index1".to_string().into(),
                            index_uuid: "aAsFqTI0Tc2W0LCWgPNrOA".to_string().into(),
                            shard: "0".to_string().into(),
                            caused_by: None
                        })
                    }),
                    ElasticsearchBulkItem::Update(ElasticsearchBulkStatus {
                        status: 201,
                        result: Ok(ElasticsearchBulkResult::Created)
                    })
                ]
            }
        )
    }

    #[test]
    fn test_elasticsearch_bulk_400_error() {
        let response: ElasticsearchBulkResponse =
            serde_json::from_value(sample_400_error()).unwrap();
        assert_eq!(
            response,
            ElasticsearchBulkResponse {
                items: vec![
                    ElasticsearchBulkItem::Index(ElasticsearchBulkStatus {
                        status: 400,
                        result: Err(ElasticsearchBulkError {
                            err_type: "mapper_parsing_exception".to_string(),
                            reason: "failed to parse".to_string(),
                            index: None,
                            index_uuid: None,
                            shard: None,
                            caused_by: Some(ElasticSearchBulkErrorCausedBy {
                                caused_by_type: "invalid_shape_exception".to_string(),
                                reason: "Bad X value -7703653.0 is not in boundary Rect(minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0)".to_string()
                            })
                        })
                    }),
                    ElasticsearchBulkItem::Update(ElasticsearchBulkStatus {
                        status: 201,
                        result: Ok(ElasticsearchBulkResult::Created)
                    })
                ]
            }
        )
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use array::Array;
use defines::InterpType;
use defines::ConvMode;
use defines::ConvDomain;
use self::libc::{uint8_t, c_int, c_float, c_double, c_longlong};

type MutAfArray = *mut self::libc::c_longlong;
type AfArray    = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_approx1(out: MutAfArray, inp: AfArray, pos: AfArray,
                  method: c_int, off_grid: c_float);

    fn af_approx2(out: MutAfArray, inp: AfArray, pos0: AfArray, pos1: AfArray,
                  method: c_int, off_grid: c_float);

    fn af_fft(out: MutAfArray, arr: AfArray,
              nfac: c_double, odim0: c_longlong) -> c_int;

    fn af_fft2(out: MutAfArray, arr: AfArray, nfac: c_double,
               odim0: c_longlong, odim1: c_longlong) -> c_int;

    fn af_fft3(out: MutAfArray, arr: AfArray, nfac: c_double,
               odim0: c_longlong, odim1: c_longlong, odim2: c_longlong) -> c_int;

    fn af_ifft(out: MutAfArray, arr: AfArray,
               nfac: c_double, odim0: c_longlong) -> c_int;

    fn af_ifft2(out: MutAfArray, arr: AfArray, nfac: c_double,
                odim0: c_longlong, odim1: c_longlong) -> c_int;

    fn af_ifft3(out: MutAfArray, arr: AfArray, nfac: c_double,
                odim0: c_longlong, odim1: c_longlong, odim2: c_longlong) -> c_int;

    fn af_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve2_sep(o: MutAfArray, c: AfArray, r: AfArray, s: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fir(out: MutAfArray, b: AfArray, x: AfArray) -> c_int;
    fn af_iir(out: MutAfArray, b: AfArray, a: AfArray, x: AfArray) -> c_int;
}

#[allow(unused_mut)]
pub fn approx1(input: &Array, pos: &Array, method: InterpType, off_grid: f32) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_approx1(&mut temp as MutAfArray,
                   input.get() as AfArray, pos.get() as AfArray,
                   method as c_int, off_grid as c_float);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn approx2(input: &Array, pos0: &Array, pos1: &Array,
               method: InterpType, off_grid: f32) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_approx2(&mut temp as MutAfArray,
                   input.get() as AfArray, pos0.get() as AfArray, pos1.get() as AfArray,
                   method as c_int, off_grid as c_float);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft(&mut temp as MutAfArray, input.get() as AfArray,
               norm_factor as c_double, odim0 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft2(&mut temp as MutAfArray, input.get() as AfArray,
                norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft3(input: &Array, norm_factor: f64, odim0: i64, odim1: i64, odim2: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double,
                odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft(&mut temp as MutAfArray, input.get() as AfArray,
                norm_factor as c_double, odim0 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft2(&mut temp as MutAfArray, input.get() as AfArray,
                 norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft3(input: &Array, norm_factor: f64, odim0: i64, odim1: i64, odim2: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double,
                 odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong);
        Array::from(temp)
    }
}

macro_rules! conv_func_def {
    ($fn_name:ident, $ffi_name: ident) => (
        #[allow(unused_mut)]
        pub fn $fn_name(signal: &Array, filter: &Array,
                        mode: ConvMode, domain: ConvDomain) -> Array {
            unsafe {
                let mut temp: i64 = 0;
                $ffi_name(&mut temp as MutAfArray,
                          signal.get() as AfArray, filter.get() as AfArray,
                          mode as uint8_t, domain as uint8_t);
                Array::from(temp)
            }
        }
    )
}

conv_func_def!(convolve1, af_convolve1);
conv_func_def!(convolve2, af_convolve2);
conv_func_def!(convolve3, af_convolve3);

#[allow(unused_mut)]
pub fn convolve2_sep(cfilt: &Array, rfilt: &Array, signal: &Array, mode: ConvMode) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_convolve2_sep(&mut temp as MutAfArray,
                         cfilt.get() as AfArray, rfilt.get() as AfArray,
                         signal.get() as AfArray, mode as uint8_t);
        Array::from(temp)
    }
}

macro_rules! fft_conv_func_def {
    ($fn_name:ident, $ffi_name: ident) => (
        #[allow(unused_mut)]
        pub fn $fn_name(signal: &Array, filter: &Array, mode: ConvMode) -> Array {
            unsafe {
                let mut temp: i64 = 0;
                $ffi_name(&mut temp as MutAfArray, signal.get() as AfArray,
                          filter.get() as AfArray, mode as uint8_t);
                Array::from(temp)
            }
        }
    )
}

fft_conv_func_def!(fft_convolve1, af_fft_convolve1);
fft_conv_func_def!(fft_convolve2, af_fft_convolve2);
fft_conv_func_def!(fft_convolve3, af_fft_convolve3);

#[allow(unused_mut)]
pub fn fir(b: &Array, x: &Array) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fir(&mut temp as MutAfArray, b.get() as AfArray, x.get() as AfArray);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn iir(b: &Array, a: &Array, x: &Array) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_iir(&mut temp as MutAfArray, b.get() as AfArray, a.get() as AfArray, x.get() as AfArray);
        Array::from(temp)
    }
}
<commit_msg>Corrected ffi signature for approx1 & approx2 functions<commit_after>extern crate libc;

use array::Array;
use defines::InterpType;
use defines::ConvMode;
use defines::ConvDomain;
use self::libc::{uint8_t, c_int, c_float, c_double, c_longlong};

type MutAfArray = *mut self::libc::c_longlong;
type AfArray    = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_approx1(out: MutAfArray, inp: AfArray, pos: AfArray,
                  method: c_int, off_grid: c_float) -> c_int;

    fn af_approx2(out: MutAfArray, inp: AfArray, pos0: AfArray, pos1: AfArray,
                  method: c_int, off_grid: c_float) -> c_int;

    fn af_fft(out: MutAfArray, arr: AfArray,
              nfac: c_double, odim0: c_longlong) -> c_int;

    fn af_fft2(out: MutAfArray, arr: AfArray, nfac: c_double,
               odim0: c_longlong, odim1: c_longlong) -> c_int;

    fn af_fft3(out: MutAfArray, arr: AfArray, nfac: c_double,
               odim0: c_longlong, odim1: c_longlong, odim2: c_longlong) -> c_int;

    fn af_ifft(out: MutAfArray, arr: AfArray,
               nfac: c_double, odim0: c_longlong) -> c_int;

    fn af_ifft2(out: MutAfArray, arr: AfArray, nfac: c_double,
                odim0: c_longlong, odim1: c_longlong) -> c_int;

    fn af_ifft3(out: MutAfArray, arr: AfArray, nfac: c_double,
                odim0: c_longlong, odim1: c_longlong, odim2: c_longlong) -> c_int;

    fn af_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t, d: uint8_t) -> c_int;
    fn af_convolve2_sep(o: MutAfArray, c: AfArray, r: AfArray, s: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve1(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve2(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fft_convolve3(out: MutAfArray, s: AfArray, f: AfArray, m: uint8_t) -> c_int;
    fn af_fir(out: MutAfArray, b: AfArray, x: AfArray) -> c_int;
    fn af_iir(out: MutAfArray, b: AfArray, a: AfArray, x: AfArray) -> c_int;
}

#[allow(unused_mut)]
pub fn approx1(input: &Array, pos: &Array, method: InterpType, off_grid: f32) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_approx1(&mut temp as MutAfArray,
                   input.get() as AfArray, pos.get() as AfArray,
                   method as c_int, off_grid as c_float);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn approx2(input: &Array, pos0: &Array, pos1: &Array,
               method: InterpType, off_grid: f32) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_approx2(&mut temp as MutAfArray,
                   input.get() as AfArray, pos0.get() as AfArray, pos1.get() as AfArray,
                   method as c_int, off_grid as c_float);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft(&mut temp as MutAfArray, input.get() as AfArray,
               norm_factor as c_double, odim0 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft2(&mut temp as MutAfArray, input.get() as AfArray,
                norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn fft3(input: &Array, norm_factor: f64, odim0: i64, odim1: i64, odim2: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double,
                odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft(&mut temp as MutAfArray, input.get() as AfArray,
                norm_factor as c_double, odim0 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft2(&mut temp as MutAfArray, input.get() as AfArray,
                 norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn ifft3(input: &Array, norm_factor: f64, odim0: i64, odim1: i64, odim2: i64) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_ifft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double,
                 odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong);
        Array::from(temp)
    }
}

macro_rules! conv_func_def {
    ($fn_name:ident, $ffi_name: ident) => (
        #[allow(unused_mut)]
        pub fn $fn_name(signal: &Array, filter: &Array,
                        mode: ConvMode, domain: ConvDomain) -> Array {
            unsafe {
                let mut temp: i64 = 0;
                $ffi_name(&mut temp as MutAfArray,
                          signal.get() as AfArray, filter.get() as AfArray,
                          mode as uint8_t, domain as uint8_t);
                Array::from(temp)
            }
        }
    )
}

conv_func_def!(convolve1, af_convolve1);
conv_func_def!(convolve2, af_convolve2);
conv_func_def!(convolve3, af_convolve3);

#[allow(unused_mut)]
pub fn convolve2_sep(cfilt: &Array, rfilt: &Array, signal: &Array, mode: ConvMode) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_convolve2_sep(&mut temp as MutAfArray,
                         cfilt.get() as AfArray, rfilt.get() as AfArray,
                         signal.get() as AfArray, mode as uint8_t);
        Array::from(temp)
    }
}

macro_rules! fft_conv_func_def {
    ($fn_name:ident, $ffi_name: ident) => (
        #[allow(unused_mut)]
        pub fn $fn_name(signal: &Array, filter: &Array, mode: ConvMode) -> Array {
            unsafe {
                let mut temp: i64 = 0;
                $ffi_name(&mut temp as MutAfArray, signal.get() as AfArray,
                          filter.get() as AfArray, mode as uint8_t);
                Array::from(temp)
            }
        }
    )
}

fft_conv_func_def!(fft_convolve1, af_fft_convolve1);
fft_conv_func_def!(fft_convolve2, af_fft_convolve2);
fft_conv_func_def!(fft_convolve3, af_fft_convolve3);

#[allow(unused_mut)]
pub fn fir(b: &Array, x: &Array) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_fir(&mut temp as MutAfArray, b.get() as AfArray, x.get() as AfArray);
        Array::from(temp)
    }
}

#[allow(unused_mut)]
pub fn iir(b: &Array, a: &Array, x: &Array) -> Array {
    unsafe {
        let mut temp: i64 = 0;
        af_iir(&mut temp as MutAfArray, b.get() as AfArray, a.get() as AfArray, x.get() as AfArray);
        Array::from(temp)
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2015, Alex Frappier Lachapelle
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::collections::BTreeMap;
use std::error::Error;
use std::fs::{File, Metadata, OpenOptions};
use std::io::{Read, Write};
use std::path::PathBuf;

extern crate term;

use serde_json::Value;

mod utils;

////////////////////////////////////////////////////////////
//                         Macros                         //
////////////////////////////////////////////////////////////

include!("utils_macros.rs");

////////////////////////////////////////////////////////////
//                        Constants                       //
////////////////////////////////////////////////////////////
pub static TRELLO_API_KEY: &'static str = "0e190833c4db5fd7d3b0b26ae642d6fa";

////////////////////////////////////////////////////////////
//                        Structs                         //
////////////////////////////////////////////////////////////

#[derive(Clone)]
pub struct TrelloBSTConfig {
    pub key_val_map: BTreeMap<String, String>,
    pub config_mode: Option<PathBuf>
}

#[derive(Serialize, Deserialize)]
pub struct TrelloBSTAPIConfig {
    pub trello_app_token:    String,
    pub travis_access_token: String,
    pub appveyor_api_token:  String,
}

////////////////////////////////////////////////////////////
//                         Impls                          //
////////////////////////////////////////////////////////////

impl TrelloBSTConfig {

    pub fn load(&mut self, config_mode: Option<PathBuf>) -> Result<(), &'static str> {

        self.config_mode = config_mode;

        //Parse if we're using a config file, silently skip if were not
        if self.config_mode.is_some() {

            //Load file
            let mut file: File;
            match File::open(self.clone().config_mode.unwrap().as_path()) {
                Ok(_file) => {file = _file;}
                Err(_)    =>{
                    self.config_mode = Option::None;
                    return Err("Error: Failed to open the configuration file for parsing, TrelloBST will continue without saving inputted values into the configuration file.");
                }
            }

            //Get config file metadata.
            let metadata: Metadata;
            match file.metadata() {
                Ok(_metadata)  => {metadata = _metadata;}
                Err(_)         => {
                    self.config_mode = Option::None;
                    return Err("Error: Failed to gather metadata of the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                }
            }

            //Parse config file
            let file_length: usize = metadata.len() as usize;
            if file_length == 0 {
                self.key_val_map = BTreeMap::new();
            } else {

                //Read file
                let mut file_data: String = String::with_capacity(file_length +1);
                match file.read_to_string(&mut file_data) {
                    Ok(_)  => (),
                    Err(_) => {
                        self.config_mode = Option::None;
                        return Err("Error: Failed to read the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                    }
                }

                //Parse
                let json_data: Value;
                match serde_json::from_str(&file_data){
                    Ok(_json_data) => json_data = _json_data,
                    Err(_)  => {
                        self.config_mode = Option::None;
                        return Err("Error: Failed to parse the JSON data in the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                    }
                }

                //Extract data
                //Get JSON object
                let json_object: BTreeMap<String, Value>;
                match json_data.as_object().ok_or("Error: JSON data in the configuration file does not describe a JSON object, TrelloBST will continue without saving inputted values into the configuration file.") {
                    Ok(_json_object) => {json_object  = _json_object.clone();},
                    Err(err)         => {
                        self.config_mode = Option::None;
                        return Err(err);
                    }
                }

                //Iterate through object
                for (key, val) in &json_object {
                    if val.is_string() {
                        self.key_val_map.insert(key.clone(), val.as_string().unwrap().to_string());
                    } else {
                        println!("Value of the \"{}\" field in the configuration file is not a string, this value will not be considered.", key);
                    }
                }
            }
        }
        Ok(())
    }

    //Save config
    pub fn save(&mut self) -> Result<(), String> {

        if self.config_mode.is_some() {

            let mut json_map:        BTreeMap<String, Value> = BTreeMap::new();
            let     json_map_string: String;

            for (key, val) in &self.key_val_map {
                json_map.insert(key.clone(), Value::String(val.clone()));
            }

            let value = Value::Object(json_map);

            match serde_json::to_string(&value) {
                Ok(_json_map_string) => {json_map_string = _json_map_string;}
                Err(err) => {
                    return Err(err.description().to_string());
                }
            }

            //Open file, overwrite config with what we have
            let mut file: File;
            match OpenOptions::new().write(true).truncate(true).open(self.config_mode.clone().unwrap().as_path()) {
                Ok(_file) => {
                    file = _file;
                    match file.write_all(json_map_string.as_bytes()) {
                        Ok(()) => (),
                        Err(_) => {
                            self.config_mode = Option::None;
                            return Err("Error: Failed to write data to the configuration file, TrelloBST will continue without saving inputted values into the configuration file.".to_string());
                        }
                    }
                }
                Err(_) => {
                    self.config_mode = Option::None;
                    return Err("Error: Failed to open the configuration file for saving, TrelloBST will continue without saving inputted values into the configuration file.".to_string());
                }
            }
        }
        Ok(())
    }

    //Sets a config key-value pair
    pub fn set(&mut self, key: &str, val: &str) {
        if self.config_mode.is_some() {
            self.key_val_map.insert(key.to_string(), val.to_string());
        }
    }

    //Gets a config value for a key, returns "" if key doesnt exist and creates the key
    pub fn get(&mut self, key: &str) -> String {

        if self.config_mode.is_some() {
            if self.key_val_map.contains_key(&key.to_string()) {
                return self.key_val_map.get(&key.to_string()).unwrap().clone();
            } else {
                self.key_val_map.insert(key.to_string(), "".to_string());
                return "".to_string();
            }
        }
    }
}

impl TrelloBSTAPIConfig {

    pub fn new() -> TrelloBSTAPIConfig {
        TrelloBSTAPIConfig {
            trello_app_token:    String::new(),
            travis_access_token: String::new(),
            appveyor_api_token:  String::new(),
        }
    }

    pub fn from_file(config_file_path: &PathBuf) -> Result<TrelloBSTAPIConfig, &'static str>{

        let mut file: File;
        match File::open(config_file_path.as_path()) {
            Ok(_file) => {
                file = _file;
            }
            Err(_)    =>{
                return Err("Cannot open config file for parsing, configuration file won't be used...");
            }
        }

        let metadata: Metadata;
        match file.metadata() {
            Ok(_metadata)  => {
                metadata = _metadata;
            }
            Err(_)         => {
                return Err("Cannot gather metadata of the configuration file, configuration file won't be used...")
            }
        }

        let api_config         = TrelloBSTAPIConfig::new();
        let file_length: usize = metadata.len() as usize;
        if file_length == 0 {
            return Ok(api_config)
        } else {
            let mut data: String = String::with_capacity(file_length +1);
            match file.read_to_string(&mut data) {
                Ok(_)  => {
                    //TODO: better error checking
                    return Ok(serde_json::from_str(&data[..]).unwrap())
                },
                Err(_) => {
                    return Err("Error while reading the configuration file, configuration file won't be used...")
                }
            }
        }
    }

    pub fn save_config(config_file_path: &PathBuf, config: &TrelloBSTAPIConfig) -> Result<(), &'static str> {
        match File::create(config_file_path.as_path()) {
            Ok(file)  => {
                //TODO: better error reporting
                let     config_json = serde_json::to_string(&config).unwrap();
                let mut config_file = file;
                match config_file.write(&config_json.into_bytes()[..]) {
                    Ok(_)  => Ok(()),
                    Err(_) => Err("Error while saving the configuration file...")
                }
            }
            Err(_)    => {
                Err("Cannot open configuration for saving...")
            }
        }
    }
}

<commit_msg>Fixed compile failure.<commit_after>/*
    Copyright (c) 2015, Alex Frappier Lachapelle
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::collections::BTreeMap;
use std::error::Error;
use std::fs::{File, Metadata, OpenOptions};
use std::io::{Read, Write};
use std::path::PathBuf;

extern crate term;

use serde_json::Value;

mod utils;

////////////////////////////////////////////////////////////
//                         Macros                         //
////////////////////////////////////////////////////////////

include!("utils_macros.rs");

////////////////////////////////////////////////////////////
//                        Constants                       //
////////////////////////////////////////////////////////////
pub static TRELLO_API_KEY: &'static str = "0e190833c4db5fd7d3b0b26ae642d6fa";

////////////////////////////////////////////////////////////
//                        Structs                         //
////////////////////////////////////////////////////////////

#[derive(Clone)]
pub struct TrelloBSTConfig {
    pub key_val_map: BTreeMap<String, String>,
    pub config_mode: Option<PathBuf>
}

#[derive(Serialize, Deserialize)]
pub struct TrelloBSTAPIConfig {
    pub trello_app_token:    String,
    pub travis_access_token: String,
    pub appveyor_api_token:  String,
}

////////////////////////////////////////////////////////////
//                         Impls                          //
////////////////////////////////////////////////////////////

impl TrelloBSTConfig {

    pub fn load(&mut self, config_mode: Option<PathBuf>) -> Result<(), &'static str> {

        self.config_mode = config_mode;

        //Parse if we're using a config file, silently skip if were not
        if self.config_mode.is_some() {

            //Load file
            let mut file: File;
            match File::open(self.clone().config_mode.unwrap().as_path()) {
                Ok(_file) => {file = _file;}
                Err(_)    =>{
                    self.config_mode = Option::None;
                    return Err("Error: Failed to open the configuration file for parsing, TrelloBST will continue without saving inputted values into the configuration file.");
                }
            }

            //Get config file metadata.
            let metadata: Metadata;
            match file.metadata() {
                Ok(_metadata)  => {metadata = _metadata;}
                Err(_)         => {
                    self.config_mode = Option::None;
                    return Err("Error: Failed to gather metadata of the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                }
            }

            //Parse config file
            let file_length: usize = metadata.len() as usize;
            if file_length == 0 {
                self.key_val_map = BTreeMap::new();
            } else {

                //Read file
                let mut file_data: String = String::with_capacity(file_length +1);
                match file.read_to_string(&mut file_data) {
                    Ok(_)  => (),
                    Err(_) => {
                        self.config_mode = Option::None;
                        return Err("Error: Failed to read the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                    }
                }

                //Parse
                let json_data: Value;
                match serde_json::from_str(&file_data){
                    Ok(_json_data) => json_data = _json_data,
                    Err(_)  => {
                        self.config_mode = Option::None;
                        return Err("Error: Failed to parse the JSON data in the configuration file, TrelloBST will continue without saving inputted values into the configuration file.")
                    }
                }

                //Extract data
                //Get JSON object
                let json_object: BTreeMap<String, Value>;
                match json_data.as_object().ok_or("Error: JSON data in the configuration file does not describe a JSON object, TrelloBST will continue without saving inputted values into the configuration file.") {
                    Ok(_json_object) => {json_object  = _json_object.clone();},
                    Err(err)         => {
                        self.config_mode = Option::None;
                        return Err(err);
                    }
                }

                //Iterate through object
                for (key, val) in &json_object {
                    if val.is_string() {
                        self.key_val_map.insert(key.clone(), val.as_string().unwrap().to_string());
                    } else {
                        println!("Value of the \"{}\" field in the configuration file is not a string, this value will not be considered.", key);
                    }
                }
            }
        }
        Ok(())
    }

    //Save config
    pub fn save(&mut self) -> Result<(), String> {

        if self.config_mode.is_some() {

            let mut json_map:        BTreeMap<String, Value> = BTreeMap::new();
            let     json_map_string: String;

            for (key, val) in &self.key_val_map {
                json_map.insert(key.clone(), Value::String(val.clone()));
            }

            let value = Value::Object(json_map);

            match serde_json::to_string(&value) {
                Ok(_json_map_string) => {json_map_string = _json_map_string;}
                Err(err) => {
                    return Err(err.description().to_string());
                }
            }

            //Open file, overwrite config with what we have
            let mut file: File;
            match OpenOptions::new().write(true).truncate(true).open(self.config_mode.clone().unwrap().as_path()) {
                Ok(_file) => {
                    file = _file;
                    match file.write_all(json_map_string.as_bytes()) {
                        Ok(()) => (),
                        Err(_) => {
                            self.config_mode = Option::None;
                            return Err("Error: Failed to write data to the configuration file, TrelloBST will continue without saving inputted values into the configuration file.".to_string());
                        }
                    }
                }
                Err(_) => {
                    self.config_mode = Option::None;
                    return Err("Error: Failed to open the configuration file for saving, TrelloBST will continue without saving inputted values into the configuration file.".to_string());
                }
            }
        }
        Ok(())
    }

    //Sets a config key-value pair
    pub fn set(&mut self, key: &str, val: &str) {
        if self.config_mode.is_some() {
            self.key_val_map.insert(key.to_string(), val.to_string());
        }
    }

    //Gets a config value for a key, returns "" if key doesnt exist and creates the key, returns () if not using config file.
    pub fn get(&mut self, key: &str) -> Result<String, ()> {

        if self.config_mode.is_some() {
            if self.key_val_map.contains_key(&key.to_string()) {
                return Ok(self.key_val_map.get(&key.to_string()).unwrap().clone());
            } else {
                self.key_val_map.insert(key.to_string(), "".to_string());
                return Ok("".to_string());
            }
        } else {
            Err(())
        }
    }
}

impl TrelloBSTAPIConfig {

    pub fn new() -> TrelloBSTAPIConfig {
        TrelloBSTAPIConfig {
            trello_app_token:    String::new(),
            travis_access_token: String::new(),
            appveyor_api_token:  String::new(),
        }
    }

    pub fn from_file(config_file_path: &PathBuf) -> Result<TrelloBSTAPIConfig, &'static str>{

        let mut file: File;
        match File::open(config_file_path.as_path()) {
            Ok(_file) => {
                file = _file;
            }
            Err(_)    =>{
                return Err("Cannot open config file for parsing, configuration file won't be used...");
            }
        }

        let metadata: Metadata;
        match file.metadata() {
            Ok(_metadata)  => {
                metadata = _metadata;
            }
            Err(_)         => {
                return Err("Cannot gather metadata of the configuration file, configuration file won't be used...")
            }
        }

        let api_config         = TrelloBSTAPIConfig::new();
        let file_length: usize = metadata.len() as usize;
        if file_length == 0 {
            return Ok(api_config)
        } else {
            let mut data: String = String::with_capacity(file_length +1);
            match file.read_to_string(&mut data) {
                Ok(_)  => {
                    //TODO: better error checking
                    return Ok(serde_json::from_str(&data[..]).unwrap())
                },
                Err(_) => {
                    return Err("Error while reading the configuration file, configuration file won't be used...")
                }
            }
        }
    }

    pub fn save_config(config_file_path: &PathBuf, config: &TrelloBSTAPIConfig) -> Result<(), &'static str> {
        match File::create(config_file_path.as_path()) {
            Ok(file)  => {
                //TODO: better error reporting
                let     config_json = serde_json::to_string(&config).unwrap();
                let mut config_file = file;
                match config_file.write(&config_json.into_bytes()[..]) {
                    Ok(_)  => Ok(()),
                    Err(_) => Err("Error while saving the configuration file...")
                }
            }
            Err(_)    => {
                Err("Cannot open configuration for saving...")
            }
        }
    }
}

<|endoftext|>


<commit_before>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

// XXX this should probably be split up. The VM has the instructions, a "Thread" has locals, stack, and arguments.
struct VM<'a> {
  instructions: Vec<&'a str>,
  labels: HashMap<&'a str, usize>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      labels: parse_labels(&instructions),
      instructions: instructions,
    }
  }

  pub fn run(&mut self) {
    let ip = self.labels.get("main").unwrap_or(&0).clone();
    self.run_call(ip, &mut Vec::new());
  }

  // TODO locals
  pub fn run_call(&mut self, start_ip: usize, stack: &mut Vec<Expr>) -> Option<Expr> {
    let mut ip = start_ip;
    let len = self.instructions.len();
    let locals: &mut HashMap<&'a str, Expr> = &mut HashMap::new();

    let mut carry = false; // comparison carry

    let mut arguments = Vec::new();

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        &["$label", _] => (),
        &["push", "int", n] => stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        &["push", "str", ref n..] => stack.push(Expr::Str(String::from(n.join(" ")))),
        &["push", "arg"] => arguments.push(stack.pop().expect("Nothing on the stack to push to the arguments")),

        &["dup"] => {
          let expr = stack.pop().expect("Nothing on the stack to pop");
          stack.push(expr.clone());
          stack.push(expr);
        },

        // how = "always" | "carry"
        &["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            self.labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        &["carry", "set", val] => carry = val == "true",
        &["carry", "invert"] => carry = !carry,

        &["call", "primitive", "say"] => if let Some(Expr::Str(arg)) = stack.pop() {
          println!("{}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        &["call", "primitive", "typeof"] => match stack.pop() {
            Some(Expr::Str(_)) => stack.push(Expr::Str(String::from("str"))),
            Some(Expr::Int(_)) => stack.push(Expr::Str(String::from("int"))),
            None => panic!("VM error: no argument supplied to `typeof`"),
        },

        &["call", "primitive", "int2str"] => if let Some(Expr::Int(arg)) = stack.pop() {
            stack.push(Expr::Str(arg.to_string()));
        }
        else {
            panic!("VM error: bad arguments to primitive call `int2str`");
        },

        // TODO resolve name in scope, check type, apply
        &["call", name] => {
          let new_ip = self.labels.get(name).expect("VM error: no such label").clone();
          let ret = self.run_call(new_ip, &mut arguments);
          arguments = Vec::new();
          match ret {
            Some(val) => stack.push(val),
            None => (),
          };
        },

        &["ret"] => {
          return None;
        },

        &["ret", "val"] => {
          if stack.len() != 1 {
            panic!("VM error: trying to return a value but the stack size is not 1 ({})", stack.len());
          }
          return stack.pop();
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        &["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 - arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `math`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        &["cmp", op] => carry = match (stack.pop(), stack.pop()) {
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2))) => match op {
                "<" => arg1 < arg2,
                ">" => arg1 > arg2,
                "<=" => arg1 <= arg2,
                ">=" => arg1 >= arg2,
                "=" => arg1 == arg2,
                _ => panic!("VM error: unrecognized `cmp` operator for int: {}", op),
            },
            (Some(Expr::Str(arg1)), Some(Expr::Str(arg2))) => match op {
                "=" => arg1 == arg2,
                _ => panic!("VM error: unrecognized `cmp` operator for str: {}", op),
            },
            _ => panic!("VM error: not enough arguments to `cmp`"),
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        &["local", "load", name] => match locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        &["local", "store", name] => if let Some(arg) = stack.pop() {
          // XXX check
          let _ = locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        &[instr, ..] => panic!("VM error: no such instruction {}", instr),
        &[..] => panic!("VM error: Unrecognized instruction!"),
      }
    }

    None
  }
}

fn main() {
    let mut content = String::new();
    let result;

	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

        match File::open(&path) {
          Ok(mut file) => result = file.read_to_string(&mut content),
          Err(err) => {
            panic!("Can't read file {} (error: {})", path, err);
          }
        }
    } else {
        result = std::io::stdin().read_to_string(&mut content);
   }

   if let Ok(_) = result {
     // remove trailing newlines, split by line
     let instructions = content.trim_matches('\n').split('\n').collect();
     let mut vm = VM::new(instructions);
     vm.run();
   }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>add concat primitive call<commit_after>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

// XXX this should probably be split up. The VM has the instructions, a "Thread" has locals, stack, and arguments.
struct VM<'a> {
  instructions: Vec<&'a str>,
  labels: HashMap<&'a str, usize>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      labels: parse_labels(&instructions),
      instructions: instructions,
    }
  }

  pub fn run(&mut self) {
    let ip = self.labels.get("main").unwrap_or(&0).clone();
    self.run_call(ip, &mut Vec::new());
  }

  // TODO locals
  pub fn run_call(&mut self, start_ip: usize, stack: &mut Vec<Expr>) -> Option<Expr> {
    let mut ip = start_ip;
    let len = self.instructions.len();
    let locals: &mut HashMap<&'a str, Expr> = &mut HashMap::new();

    let mut carry = false; // comparison carry

    let mut arguments = Vec::new();

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        &["$label", _] => (),
        &["push", "int", n] => stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        &["push", "str", ref n..] => stack.push(Expr::Str(String::from(n.join(" ")))),
        &["push", "arg"] => arguments.push(stack.pop().expect("Nothing on the stack to push to the arguments")),

        &["dup"] => {
          let expr = stack.pop().expect("Nothing on the stack to pop");
          stack.push(expr.clone());
          stack.push(expr);
        },

        // how = "always" | "carry"
        &["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            self.labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        &["carry", "set", val] => carry = val == "true",
        &["carry", "invert"] => carry = !carry,

        &["call", "primitive", "say"] => if let Some(Expr::Str(arg)) = stack.pop() {
          println!("{}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        &["call", "primitive", "concat"] => if let
            (Some(Expr::Str(arg1)), Some(Expr::Str(arg2)))
            =
            (stack.pop(), stack.pop()) {
          stack.push(Expr::Str(arg1 + &arg2));
        } else {
          panic!("VM error: incorrect arguments to `concat`");
        },

        &["call", "primitive", "typeof"] => match stack.pop() {
            Some(Expr::Str(_)) => stack.push(Expr::Str(String::from("str"))),
            Some(Expr::Int(_)) => stack.push(Expr::Str(String::from("int"))),
            None => panic!("VM error: no argument supplied to `typeof`"),
        },

        &["call", "primitive", "int2str"] => if let Some(Expr::Int(arg)) = stack.pop() {
            stack.push(Expr::Str(arg.to_string()));
        }
        else {
            panic!("VM error: bad arguments to primitive call `int2str`");
        },

        // TODO resolve name in scope, check type, apply
        &["call", name] => {
          let new_ip = self.labels.get(name).expect("VM error: no such label").clone();
          let ret = self.run_call(new_ip, &mut arguments);
          arguments = Vec::new();
          match ret {
            Some(val) => stack.push(val),
            None => (),
          };
        },

        &["ret"] => {
          return None;
        },

        &["ret", "val"] => {
          if stack.len() != 1 {
            panic!("VM error: trying to return a value but the stack size is not 1 ({})", stack.len());
          }
          return stack.pop();
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        &["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 - arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `math`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        &["cmp", op] => carry = match (stack.pop(), stack.pop()) {
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2))) => match op {
                "<" => arg1 < arg2,
                ">" => arg1 > arg2,
                "<=" => arg1 <= arg2,
                ">=" => arg1 >= arg2,
                "=" => arg1 == arg2,
                _ => panic!("VM error: unrecognized `cmp` operator for int: {}", op),
            },
            (Some(Expr::Str(arg1)), Some(Expr::Str(arg2))) => match op {
                "=" => arg1 == arg2,
                _ => panic!("VM error: unrecognized `cmp` operator for str: {}", op),
            },
            _ => panic!("VM error: not enough arguments to `cmp`"),
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        &["local", "load", name] => match locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        &["local", "store", name] => if let Some(arg) = stack.pop() {
          // XXX check
          let _ = locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        &[instr, ..] => panic!("VM error: no such instruction {}", instr),
        &[..] => panic!("VM error: Unrecognized instruction!"),
      }
    }

    None
  }
}

fn main() {
    let mut content = String::new();
    let result;

	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

        match File::open(&path) {
          Ok(mut file) => result = file.read_to_string(&mut content),
          Err(err) => {
            panic!("Can't read file {} (error: {})", path, err);
          }
        }
    } else {
        result = std::io::stdin().read_to_string(&mut content);
   }

   if let Ok(_) = result {
     // remove trailing newlines, split by line
     let instructions = content.trim_matches('\n').split('\n').collect();
     let mut vm = VM::new(instructions);
     vm.run();
   }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


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

use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;
use structopt::StructOpt;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool) -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout());
        send_output(outputs.stderr, io::stderr());
        let mut repl = Repl {
            command_context,
            ide_mode,
        };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        let success = match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\x01" } else { "\x02" };
            print!("{}", success_marker);
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
}

fn main() {
    evcxr::runtime_hook();

    let options = Options::from_args();

    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new(options.ide_mode) {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    repl.command_context.set_opt_level(&options.opt).ok();

    let mut editor = Editor::<()>::new();
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(&prompt)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<commit_msg>Make stderr red in repl<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;
use structopt::StructOpt;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(
    channel: mpsc::Receiver<String>,
    mut output: T,
    color: Option<Color>,
) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            let status = if let Some(color) = color {
                writeln!(output, "{}", line.color(color))
            } else {
                writeln!(output, "{}", line)
            };
            if status.is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool) -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout(), None);
        send_output(outputs.stderr, io::stderr(), Some(Color::BrightRed));
        let mut repl = Repl {
            command_context,
            ide_mode,
        };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        let success = match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\x01" } else { "\x02" };
            print!("{}", success_marker);
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
}

fn main() {
    evcxr::runtime_hook();

    let options = Options::from_args();

    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new(options.ide_mode) {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    repl.command_context.set_opt_level(&options.opt).ok();

    let mut editor = Editor::<()>::new();
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(&prompt)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<|endoftext|>