<commit_before>use std::borrow::Cow::{Owned, Borrowed};

use pulldown_cmark as cmark;
use self::cmark::{Parser, Event, Tag, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use slug::slugify;
use syntect::easy::HighlightLines;
use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, IncludeBackground};

use errors::Result;
use utils::site::resolve_internal_link;
use highlighting::{get_highlighter, THEME_SET};
use link_checker::check_url;

use table_of_contents::{TempHeader, Header, make_table_of_contents};
use context::RenderContext;

const CONTINUE_READING: &str = "

\n";

#[derive(Debug)]
pub struct Rendered {
    pub body: String,
    pub summary_len: Option<usize>,
    pub toc: Vec
}

// We might have cases where the slug is already present in our list of anchor
// for example an article could have several titles named Example
// We add a counter after the slug if the slug is already present, which
// means we will have example, example-1, example-2 etc
fn find_anchor(anchors: &[String], name: String, level: u8) -> String {
    if level == 0 && !anchors.contains(&name) {
        return name.to_string();
    }

    let new_anchor = format!("{}-{}", name, level + 1);
    if !anchors.contains(&new_anchor) {
        return new_anchor;
    }

    find_anchor(anchors, name, level + 1)
}

fn is_colocated_asset_link(link: &str) -> bool {
    !link.contains("/")  // http://, ftp://, ../ etc
        && !link.starts_with("mailto:")
}

pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Rendered> {
    // the rendered html
    let mut html = String::with_capacity(content.len());
    // Set while parsing
    let mut error = None;

    let mut highlighter: Option<HighlightLines> = None;
    // If we get text in header, we need to insert the id and a anchor
    let mut in_header = false;
    // pulldown_cmark can send several text events for a title if there are markdown
    // specific characters like `!` in them. We only want to insert the anchor the first time
    let mut header_created = false;
    let mut anchors: Vec<String> = vec![];

    let mut headers = vec![];
    // Defaults to a 0 level so not a real header
    // It should be an Option ideally but not worth the hassle to update
    let mut temp_header = TempHeader::default();

    let mut opts = Options::empty();
    let mut has_summary = false;
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    {
        let parser = Parser::new_ext(content, opts).map(|event| {
            match event {
                Event::Text(text) => {
                    // Header first
                    if in_header {
                        if header_created {
                            temp_header.push(&text);
                            return Event::Html(Borrowed(""));
                        }
                        let id = find_anchor(&anchors, slugify(&text), 0);
                        anchors.push(id.clone());
                        // update the header and add it to the list
                        temp_header.permalink = format!("{}#{}", context.current_page_permalink, id);
                        temp_header.id = id;
                        // += as we might have some  or other things already there
                        temp_header.title += &text;
                        header_created = true;
                        return Event::Html(Borrowed(""));
                    }

                    // if we are in the middle of a code block
                    if let Some(ref mut highlighter) = highlighter {
                        let highlighted = &highlighter.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes);
                        return Event::Html(Owned(html));
                    }

                    // Business as usual
                    Event::Text(text)
                }
                Event::Start(Tag::CodeBlock(ref info)) => {
                    if !context.config.highlight_code {
                        return Event::Html(Borrowed("
"));
                    }

                    let theme = &THEME_SET.themes[&context.config.highlight_theme];
                    match get_highlighter(&theme, info, context.base_path, &context.config.extra_syntaxes) {
                        Ok(h) => highlighter = Some(h),
                        Err(err) => {
                            error = Some(format!("Could not load syntax: {}", err).into());
                            return Event::Html(Borrowed(""));
                        }
                    }
                    let snippet = start_coloured_html_snippet(theme);
                    Event::Html(Owned(snippet))
                }
                Event::End(Tag::CodeBlock(_)) => {
                    if !context.config.highlight_code {
                        return Event::Html(Borrowed("
\n"));
                    }
                    // reset highlight and close the code block
                    highlighter = None;
                    Event::Html(Borrowed("
"))
                }
                Event::Start(Tag::Image(src, title)) => {
                    if is_colocated_asset_link(&src) {
                        return Event::Start(
                            Tag::Image(
                                Owned(format!("{}{}", context.current_page_permalink, src)),
                                title,
                            )
                        );
                    }

                    Event::Start(Tag::Image(src, title))
                }
                Event::Start(Tag::Link(link, title)) => {
                    // A few situations here:
                    // - it could be a relative link (starting with `./`)
                    // - it could be a link to a co-located asset
                    // - it could be a normal link
                    // - any of those can be in a header or not: if it's in a header
                    //   we need to append to a string
                    let fixed_link = if link.starts_with("./") {
                        match resolve_internal_link(&link, context.permalinks) {
                            Ok(url) => url,
                            Err(_) => {
                                error = Some(format!("Relative link {} not found.", link).into());
                                return Event::Html(Borrowed(""));
                            }
                        }
                    } else if is_colocated_asset_link(&link) {
                        format!("{}{}", context.current_page_permalink, link)
                    } else {
                        if context.config.check_external_links && !link.starts_with('#') {
                            let res = check_url(&link);
                            if res.is_valid() {
                                link.to_string()
                            } else {
                                error = Some(
                                    format!("Link {} is not valid: {}", link, res.message()).into()
                                );
                                String::new()
                            }
                        } else {
                            link.to_string()
                        }
                    };

                    if in_header {
                        let html = if title.is_empty() {
                            format!("", fixed_link)
                        } else {
                            format!("", fixed_link, title)
                        };
                        temp_header.push(&html);
                        return Event::Html(Borrowed(""));
                    }

                    Event::Start(Tag::Link(Owned(fixed_link), title))
                }
                Event::End(Tag::Link(_, _)) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::Start(Tag::Code) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::End(Tag::Code) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::Start(Tag::Header(num)) => {
                    in_header = true;
                    temp_header = TempHeader::new(num);
                    Event::Html(Borrowed(""))
                }
                Event::End(Tag::Header(_)) => {
                    // End of a header, reset all the things and return the stringified
                    // version of the header
                    in_header = false;
                    header_created = false;
                    let val = temp_header.to_string(context.tera, context.insert_anchor);
                    headers.push(temp_header.clone());
                    temp_header = TempHeader::default();
                    Event::Html(Owned(val))
                }
                Event::Html(ref markup) if markup.contains("") => {
                    has_summary = true;
                    Event::Html(Borrowed(CONTINUE_READING))
                }
                _ => event,
            }
        });

        cmark::html::push_html(&mut html, parser);
    }

    if let Some(e) = error {
        return Err(e)
    } else {
        html = html.replace("

", "").replace("

", "
");
        Ok(Rendered {
            summary_len: if has_summary { html.find(CONTINUE_READING) } else { None },
            body: html,
            toc: make_table_of_contents(&headers)
        })
    }
}
<commit_msg>Change highlighting to not include duplicated background colors<commit_after>use std::borrow::Cow::{Owned, Borrowed};

use pulldown_cmark as cmark;
use self::cmark::{Parser, Event, Tag, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use slug::slugify;
use syntect::easy::HighlightLines;
use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, IncludeBackground};

use errors::Result;
use utils::site::resolve_internal_link;
use highlighting::{get_highlighter, THEME_SET};
use link_checker::check_url;

use table_of_contents::{TempHeader, Header, make_table_of_contents};
use context::RenderContext;

const CONTINUE_READING: &str = "

\n";

#[derive(Debug)]
pub struct Rendered {
    pub body: String,
    pub summary_len: Option<usize>,
    pub toc: Vec
}

// We might have cases where the slug is already present in our list of anchor
// for example an article could have several titles named Example
// We add a counter after the slug if the slug is already present, which
// means we will have example, example-1, example-2 etc
fn find_anchor(anchors: &[String], name: String, level: u8) -> String {
    if level == 0 && !anchors.contains(&name) {
        return name.to_string();
    }

    let new_anchor = format!("{}-{}", name, level + 1);
    if !anchors.contains(&new_anchor) {
        return new_anchor;
    }

    find_anchor(anchors, name, level + 1)
}

fn is_colocated_asset_link(link: &str) -> bool {
    !link.contains("/")  // http://, ftp://, ../ etc
        && !link.starts_with("mailto:")
}

pub fn markdown_to_html(content: &str, context: &RenderContext) -> Result<Rendered> {
    // the rendered html
    let mut html = String::with_capacity(content.len());
    // Set while parsing
    let mut error = None;

    let mut background = IncludeBackground::Yes;
    let mut highlighter: Option<HighlightLines> = None;
    // If we get text in header, we need to insert the id and a anchor
    let mut in_header = false;
    // pulldown_cmark can send several text events for a title if there are markdown
    // specific characters like `!` in them. We only want to insert the anchor the first time
    let mut header_created = false;
    let mut anchors: Vec<String> = vec![];

    let mut headers = vec![];
    // Defaults to a 0 level so not a real header
    // It should be an Option ideally but not worth the hassle to update
    let mut temp_header = TempHeader::default();

    let mut opts = Options::empty();
    let mut has_summary = false;
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    {
        let parser = Parser::new_ext(content, opts).map(|event| {
            match event {
                Event::Text(text) => {
                    // Header first
                    if in_header {
                        if header_created {
                            temp_header.push(&text);
                            return Event::Html(Borrowed(""));
                        }
                        let id = find_anchor(&anchors, slugify(&text), 0);
                        anchors.push(id.clone());
                        // update the header and add it to the list
                        temp_header.permalink = format!("{}#{}", context.current_page_permalink, id);
                        temp_header.id = id;
                        // += as we might have some  or other things already there
                        temp_header.title += &text;
                        header_created = true;
                        return Event::Html(Borrowed(""));
                    }

                    // if we are in the middle of a code block
                    if let Some(ref mut highlighter) = highlighter {
                        let highlighted = &highlighter.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, background);
                        return Event::Html(Owned(html));
                    }

                    // Business as usual
                    Event::Text(text)
                }
                Event::Start(Tag::CodeBlock(ref info)) => {
                    if !context.config.highlight_code {
                        return Event::Html(Borrowed("
"));
                    }

                    let theme = &THEME_SET.themes[&context.config.highlight_theme];
                    match get_highlighter(&theme, info, context.base_path, &context.config.extra_syntaxes) {
                        Ok(h) => {
                            highlighter = Some(h);
                            // This selects the background color the same way that start_coloured_html_snippet does
                            let color = theme.settings.background.unwrap_or(::syntect::highlighting::Color::WHITE);
                            background = IncludeBackground::IfDifferent(color);
                        }
                        Err(err) => {
                            error = Some(format!("Could not load syntax: {}", err).into());
                            return Event::Html(Borrowed(""));
                        }
                    }
                    let snippet = start_coloured_html_snippet(theme);
                    Event::Html(Owned(snippet))
                }
                Event::End(Tag::CodeBlock(_)) => {
                    if !context.config.highlight_code {
                        return Event::Html(Borrowed("
\n"));
                    }
                    // reset highlight and close the code block
                    highlighter = None;
                    Event::Html(Borrowed("
"))
                }
                Event::Start(Tag::Image(src, title)) => {
                    if is_colocated_asset_link(&src) {
                        return Event::Start(
                            Tag::Image(
                                Owned(format!("{}{}", context.current_page_permalink, src)),
                                title,
                            )
                        );
                    }

                    Event::Start(Tag::Image(src, title))
                }
                Event::Start(Tag::Link(link, title)) => {
                    // A few situations here:
                    // - it could be a relative link (starting with `./`)
                    // - it could be a link to a co-located asset
                    // - it could be a normal link
                    // - any of those can be in a header or not: if it's in a header
                    //   we need to append to a string
                    let fixed_link = if link.starts_with("./") {
                        match resolve_internal_link(&link, context.permalinks) {
                            Ok(url) => url,
                            Err(_) => {
                                error = Some(format!("Relative link {} not found.", link).into());
                                return Event::Html(Borrowed(""));
                            }
                        }
                    } else if is_colocated_asset_link(&link) {
                        format!("{}{}", context.current_page_permalink, link)
                    } else {
                        if context.config.check_external_links && !link.starts_with('#') {
                            let res = check_url(&link);
                            if res.is_valid() {
                                link.to_string()
                            } else {
                                error = Some(
                                    format!("Link {} is not valid: {}", link, res.message()).into()
                                );
                                String::new()
                            }
                        } else {
                            link.to_string()
                        }
                    };

                    if in_header {
                        let html = if title.is_empty() {
                            format!("", fixed_link)
                        } else {
                            format!("", fixed_link, title)
                        };
                        temp_header.push(&html);
                        return Event::Html(Borrowed(""));
                    }

                    Event::Start(Tag::Link(Owned(fixed_link), title))
                }
                Event::End(Tag::Link(_, _)) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::Start(Tag::Code) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::End(Tag::Code) => {
                    if in_header {
                        temp_header.push("");
                        return Event::Html(Borrowed(""));
                    }
                    event
                }
                Event::Start(Tag::Header(num)) => {
                    in_header = true;
                    temp_header = TempHeader::new(num);
                    Event::Html(Borrowed(""))
                }
                Event::End(Tag::Header(_)) => {
                    // End of a header, reset all the things and return the stringified
                    // version of the header
                    in_header = false;
                    header_created = false;
                    let val = temp_header.to_string(context.tera, context.insert_anchor);
                    headers.push(temp_header.clone());
                    temp_header = TempHeader::default();
                    Event::Html(Owned(val))
                }
                Event::Html(ref markup) if markup.contains("") => {
                    has_summary = true;
                    Event::Html(Borrowed(CONTINUE_READING))
                }
                _ => event,
            }
        });

        cmark::html::push_html(&mut html, parser);
    }

    if let Some(e) = error {
        return Err(e)
    } else {
        html = html.replace("

", "").replace("

", "
");
        Ok(Rendered {
            summary_len: if has_summary { html.find(CONTINUE_READING) } else { None },
            body: html,
            toc: make_table_of_contents(&headers)
        })
    }
}
<|endoftext|>


<commit_before>use crate::syntax;
use anyhow::anyhow;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream, WriteColor};
use codespan_reporting::term::{self, Config};
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io::{self, Write};
use std::ops::Range;
use std::path::Path;
use std::process;

pub(super) type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Debug)]
pub(super) enum Error {
    NoBridgeMod,
    OutOfLineMod,
    Io(io::Error),
    Syn(syn::Error),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::NoBridgeMod => write!(f, "no #[cxx::bridge] module found"),
            Error::OutOfLineMod => write!(f, "#[cxx::bridge] module must have inline contents"),
            Error::Io(err) => err.fmt(f),
            Error::Syn(err) => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Io(err) => Some(err),
            Error::Syn(err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<syn::Error> for Error {
    fn from(err: syn::Error) -> Self {
        Error::Syn(err)
    }
}

pub(super) fn format_err(path: &Path, source: &str, error: Error) -> ! {
    match error {
        Error::Syn(syn_error) => {
            let writer = StandardStream::stderr(ColorChoice::Auto);
            let ref mut stderr = writer.lock();
            for error in syn_error {
                let _ = writeln!(stderr);
                display_syn_error(stderr, path, source, error);
            }
        }
        _ => eprintln!("cxxbridge: {:?}", anyhow!(error)),
    }
    process::exit(1);
}

fn display_syn_error(stderr: &mut dyn WriteColor, path: &Path, source: &str, error: syn::Error) {
    let span = error.span();
    let start = span.start();
    let end = span.end();

    let mut start_offset = 0;
    for _ in 1..start.line {
        start_offset += source[start_offset..].find('\n').unwrap() + 1;
    }
    start_offset += start.column;

    let mut end_offset = start_offset;
    if start.line == end.line {
        end_offset -= start.column;
    } else {
        for _ in 0..end.line - start.line {
            end_offset += source[end_offset..].find('\n').unwrap() + 1;
        }
    }
    end_offset += end.column;

    let mut files = SimpleFiles::new();
    let file = files.add(path.to_string_lossy(), source);

    let diagnostic = diagnose(file, start_offset..end_offset, error);

    let config = Config::default();
    let _ = term::emit(stderr, &config, &files, &diagnostic);
}

fn diagnose(file: usize, range: Range<usize>, error: syn::Error) -> Diagnostic<usize> {
    let message = error.to_string();
    let info = syntax::error::ERRORS
        .iter()
        .find(|e| message.contains(e.msg));
    let mut diagnostic = Diagnostic::error().with_message(&message);
    let mut label = Label::primary(file, range);
    if let Some(info) = info {
        label.message = info.label.map_or(message, str::to_owned);
        diagnostic.labels.push(label);
        diagnostic.notes.extend(info.note.map(str::to_owned));
    } else {
        label.message = message;
        diagnostic.labels.push(label);
    }
    diagnostic.code = Some("cxxbridge".to_owned());
    diagnostic
}
<commit_msg>Sort errors reported by line number<commit_after>use crate::syntax;
use anyhow::anyhow;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream, WriteColor};
use codespan_reporting::term::{self, Config};
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io::{self, Write};
use std::ops::Range;
use std::path::Path;
use std::process;

pub(super) type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Debug)]
pub(super) enum Error {
    NoBridgeMod,
    OutOfLineMod,
    Io(io::Error),
    Syn(syn::Error),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::NoBridgeMod => write!(f, "no #[cxx::bridge] module found"),
            Error::OutOfLineMod => write!(f, "#[cxx::bridge] module must have inline contents"),
            Error::Io(err) => err.fmt(f),
            Error::Syn(err) => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::Io(err) => Some(err),
            Error::Syn(err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<syn::Error> for Error {
    fn from(err: syn::Error) -> Self {
        Error::Syn(err)
    }
}

pub(super) fn format_err(path: &Path, source: &str, error: Error) -> ! {
    match error {
        Error::Syn(syn_error) => {
            let syn_error = sort_syn_errors(syn_error);
            let writer = StandardStream::stderr(ColorChoice::Auto);
            let ref mut stderr = writer.lock();
            for error in syn_error {
                let _ = writeln!(stderr);
                display_syn_error(stderr, path, source, error);
            }
        }
        _ => eprintln!("cxxbridge: {:?}", anyhow!(error)),
    }
    process::exit(1);
}

fn sort_syn_errors(error: syn::Error) -> Vec<syn::Error> {
    let mut errors: Vec<_> = error.into_iter().collect();
    errors.sort_by_key(|e| {
        let start = e.span().start();
        (start.line, start.column)
    });
    errors
}

fn display_syn_error(stderr: &mut dyn WriteColor, path: &Path, source: &str, error: syn::Error) {
    let span = error.span();
    let start = span.start();
    let end = span.end();

    let mut start_offset = 0;
    for _ in 1..start.line {
        start_offset += source[start_offset..].find('\n').unwrap() + 1;
    }
    start_offset += start.column;

    let mut end_offset = start_offset;
    if start.line == end.line {
        end_offset -= start.column;
    } else {
        for _ in 0..end.line - start.line {
            end_offset += source[end_offset..].find('\n').unwrap() + 1;
        }
    }
    end_offset += end.column;

    let mut files = SimpleFiles::new();
    let file = files.add(path.to_string_lossy(), source);

    let diagnostic = diagnose(file, start_offset..end_offset, error);

    let config = Config::default();
    let _ = term::emit(stderr, &config, &files, &diagnostic);
}

fn diagnose(file: usize, range: Range<usize>, error: syn::Error) -> Diagnostic<usize> {
    let message = error.to_string();
    let info = syntax::error::ERRORS
        .iter()
        .find(|e| message.contains(e.msg));
    let mut diagnostic = Diagnostic::error().with_message(&message);
    let mut label = Label::primary(file, range);
    if let Some(info) = info {
        label.message = info.label.map_or(message, str::to_owned);
        diagnostic.labels.push(label);
        diagnostic.notes.extend(info.note.map(str::to_owned));
    } else {
        label.message = message;
        diagnostic.labels.push(label);
    }
    diagnostic.code = Some("cxxbridge".to_owned());
    diagnostic
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(ref error) if error.kind() == ErrorKind::NotFound => {
            match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => {
                    panic!("File creation failed: {:?}", e)
                }
            }
        },
        Err(error) => {
            panic!("Problem with opening file: {:?}", error)
        }
    };

    // Example of unwrap usage to shorten code (Ok(res) => res and Err(e) => panic!("...")
    let f_unwrap = File::open("hello.txt").unwrap();
    // Similar to unwrap but it's possible to provide panic message
    let f_expect = File::open("hello.txt").expect("Failed to open file hello.txt");
}

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("hello.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}<commit_msg>Usage of "?" for propagating errors<commit_after>use std::io;
use std::io::Read;
use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(ref error) if error.kind() == ErrorKind::NotFound => {
            match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => {
                    panic!("File creation failed: {:?}", e)
                }
            }
        },
        Err(error) => {
            panic!("Problem with opening file: {:?}", error)
        }
    };

    // Example of unwrap usage to shorten code (Ok(res) => res and Err(e) => panic!("...")
    let f_unwrap = File::open("hello.txt").unwrap();
    // Similar to unwrap but it's possible to provide panic message
    let f_expect = File::open("hello.txt").expect("Failed to open file hello.txt");
}

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("hello.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

fn read_username_from_file_shorthand() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}
<|endoftext|>


<commit_before>/**
 *   Mles-utils to be used with Mles client or server.
 *   Copyright (C) 2017  Mles developers
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
extern crate tokio_core;
extern crate futures;
extern crate mles_utils;

use std::{thread, process, env};
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::net::TcpStream;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::TcpListener;
use std::collections::HashMap;
use std::io::{Read, Error};
use std::io::Write;
use std::time::Duration;
use std::option::Option;
use std::str;
use mles_utils::*;

const HDRL: u64 = 4;
const KEYL: u64 = 8;
const DELAY: u64 = 50;

fn main_old() {
    let mut peer = "".to_string();
    let mut argcnt = 0;
    for arg in env::args() {
        argcnt += 1;
        if 2 == argcnt {
            peer = arg;
            peer += ":8077";
            match peer.parse::<SocketAddr>() {
                Ok(_) => {},
                    Err(err) => {
                        println!("Error: {}\nUsage: mles [peer-address]", err);
                        process::exit(1);
                    },
            }
        }
        if argcnt > 2 {
            println!("Usage: mles [peer-address]");
            process::exit(1);
        }
    }
    let peer = match peer.parse::<SocketAddr>() {
        Ok(addr) => addr,
        Err(_) => {
            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
        },
    };

    let address = "0.0.0.0:8077";
    let listener = match TcpListener::bind(&address) {
        Ok(listener) => listener,
        Err(err) => {
            println!("Error: {}", err);
            process::exit(1);
        },
    };

    let keyval =match env::var("MLES_KEY") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut spawned = HashMap::new();
    let option: Option<Duration> = Some(Duration::from_millis(DELAY));
    let addr = listener.local_addr().unwrap();
    println!("Listening for connections on {}", addr);
    let (tx, rx) = channel();
    let (removedtx, removedrx) = channel();

    for socket in listener.incoming() {
        /* Check first has anybody removed channels */
        let mut remrx = true;
        while remrx {
            match removedrx.try_recv() {
                Ok(val) => {
                    let removed_channel: String = val;
                    println!("Removing unused channel {}", removed_channel.as_str());
                    spawned.remove(&removed_channel);
                    remrx = true;
                },
                Err(_) => { remrx = false; }
            }
        }
        /* 1. Read incoming msg channel
         * 2. If it does not exist, spawn new thread
         * 3. Send socket to thread
         */
        let socket = socket.unwrap();
        let stream = socket.try_clone().unwrap();
        let tuple = read_n(&stream, HDRL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        if 0 == buf.len() {
            continue;
        }
        if read_hdr_type(buf.as_slice()) != 'M' as u32 {
            println!("Incorrect payload type");
            continue;
        }
        // read key
        let tuple = read_n(&stream, KEYL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        // verify key
        let hkey;
        let key = read_key(tuple.1);
        if 0 == keyval.len() {
            let paddr = match stream.peer_addr() {
                Ok(paddr) => paddr,
                Err(_) => {
                    let addr = "0.0.0.0:0";
                    let addr = addr.parse::<SocketAddr>().unwrap();
                    addr
                }
            };
            hkey = do_hash(&paddr);
        }
        else {
            hkey = do_hash(&keyval);
        }
        if hkey != key {
            println!("Incorrect remote key");
            continue;
        }
        let tuple = read_n(&stream, read_hdr_len(buf.as_slice()) as u64);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        let decoded_msg = message_decode(buf.as_slice());
        if 0 == decoded_msg.channel.len() {
            continue;
        }
        let _val = socket.set_nodelay(true);
        let _val = socket.set_read_timeout(option);
        if !spawned.contains_key(decoded_msg.channel.as_str()) {
            let tx = tx.clone();
            let removedtx = removedtx.clone();
            let msg = decoded_msg.clone();
            thread::spawn(move|| process_channel(peer, key, tx, removedtx, msg));

            let thr_feed = rx.recv().unwrap();
            spawned.insert(decoded_msg.channel.clone(), thr_feed);
        }
        let thr_socket = spawned.get_mut(&decoded_msg.channel).unwrap();
        thr_socket.send(socket).unwrap();
    }
}

fn process_channel(peer: SocketAddr, key: u64, tx: Sender<Sender<TcpStream>>, removedtx: Sender<String>, msg: Msg ) {
    let mut cnt = 0;
    let (thr_tx, thr_rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
    println!("Spawned: New channel {} created!", msg.channel);
    let mut users = HashMap::new();
    let mut messages: Vec<Vec<u8>> = Vec::new();
    tx.send(thr_tx.clone()).unwrap();

    // just try once during channel creation
    if 0 != peer.port() {
        match TcpStream::connect(peer) {
            Ok(mut sock) => {
                let option: Option<Duration> = Some(Duration::from_millis(DELAY));
                let _val = sock.set_nodelay(true);
                let _val = sock.set_read_timeout(option);
                let encoded_msg = message_encode(&msg);
                let keyv = write_key(key);
                let mut msgv = write_hdr(encoded_msg.len());
                msgv.extend(keyv);
                msgv.extend(encoded_msg);
                sock.write(msgv.as_slice()).unwrap();

                cnt += 1;
                println!("Adding peer {}", cnt);
                users.insert(cnt, sock);
            },
            Err(_) => {
                println!("Could not connect to peer {}", peer);
            },
        }
    }

    loop {
        let mut removals = Vec::new();
        let mut newuser = true;
        while newuser {
            match thr_rx.try_recv() {
                Ok(val) => {
                    let mut thr: TcpStream = val;
                    cnt += 1;
                    println!("Adding user {}", cnt);
                    users.insert(cnt, thr.try_clone().unwrap());

                    /* If a new user, all push messages to her */
                    for buf in &messages {
                        thr.write(buf.as_slice()).unwrap();
                    }
                    newuser = true;
                },
                Err(_) => { newuser = false; }
            }
        }
        for (user, thr_socket) in &users {
            let stream = thr_socket.try_clone().unwrap();
            let tuple = read_n(&stream, HDRL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let mut buf = tuple.1;
            if 0 == buf.len() {
                continue;
            }
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                continue;
            }
            let hdr_len = read_hdr_len(buf.as_slice()) as u64;
            if 0 == hdr_len {
                continue;
            }
            // read key
            let tuple = read_n(&stream, KEYL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    continue;
                },
                    Ok(_) => {},
                    _ => {
                        continue;
                    },
            }
            let key = tuple.1;
            //ignore key
            buf.extend(key);
            let tuple = read_n(&stream, hdr_len);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let payload = tuple.1;
            if payload.len() != (hdr_len as usize) {
                continue;
            }
            buf.extend(payload);
            for (another_user, mut thr_sock) in &users {
                if user != another_user {
                    thr_sock.write(buf.as_slice()).unwrap();
                }
            }
            /* Add to local db */
            messages.push(buf);
        }
        for removal in &removals {
            println!("Removing user {}", removal);
            users.remove(removal);
        }
        if cnt > 0 && users.is_empty() {
            removedtx.send(msg.channel).unwrap();
            break;
        }
    }
}

fn read_n<R>(reader: R, bytes_to_read: u64) -> (Result<usize, Error>, Vec<u8>)
where R: Read,
{
    let mut buf = vec![];
    let mut chunk = reader.take(bytes_to_read);
    let status = chunk.read_to_end(&mut buf);
    (status, buf)
}

/* Tokio version */
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::iter;
use std::env;
use std::io::{Error, ErrorKind, BufReader};

use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;
use tokio_core::io::{self, Io, Read};

use futures::stream::{self, Stream};
use futures::Future;
use mles_utils::*;

//static mut BUF: Vec<u8> = vec![0,4];

fn main() {
    let addr = env::args().nth(1).unwrap_or("0.0.0.0:8077".to_string());
    let addr = addr.parse().unwrap();
    let mut cnt = 0;

    // Create the event loop and TCP listener we'll accept connections on.
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();
    println!("Listening on: {}", addr);

    // This is a single-threaded server, so we can just use Rc and RefCell to
    // store the map of all connections we know about.
    let connections = Rc::new(RefCell::new(HashMap::new()));

    let srv = socket.incoming().for_each(move |(stream, addr)| {
        println!("New Connection: {}", addr);
        let (reader, writer) = stream.split();

        // Create a channel for our stream, which other sockets will use to
        // send us messages. Then register our address with the stream to send
        // data to us.
        let (tx, rx) = futures::sync::mpsc::unbounded();
        cnt += 1;
        connections.borrow_mut().insert(cnt, tx);

        // Define here what we do for the actual I/O. That is, read a bunch of
        // frames from the socket and dispatch them while we also write any frames
        // from other sockets.
        let connections_inner = connections.clone();
        //let reader = BufReader::new(reader);

        // Model the read portion of this socket by mapping an infinite
        // iterator to each frame off the socket. This "loop" is then
        // terminated with an error once we hit EOF on the socket.
        let iter = stream::iter(iter::repeat(()).map(Ok::<(), Error>));
        let socket_reader = iter.fold(reader, move |reader, _| {
            // Read a off header the socket, failing if we're at EOF
            //let frame = io::read_until(reader, b'\n', Vec::new());
            let mut buf = vec![0,4];
            let frame = io::read_exact(reader, &mut buf);
            let frame = frame.and_then(|(reader, payload)| {
                if payload.len() == 0 {
                    Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
                } else {
                    if read_hdr_type(payload.as_slice()) != 'M' as u32 {
                        return Err(Error::new(ErrorKind::BrokenPipe, "incorrect header"));
                    }
                    let hdr_len = read_hdr_len(payload.as_slice());
                    if 0 == hdr_len {
                        return Err(Error::new(ErrorKind::BrokenPipe, "incorrect header len"));
                    }
                    /* XXX Next read the payload of the frame */
                    /*let mut payload = vec![0, 100]; //XXX just that it compiles
                      let buf = io::read_exact(reader, &mut payload);
                      let buf = buf.and_then(|(reader, buf)| {
                      if buf.len() == 0 {
                      return Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
                      }
                      Ok((reader, buf))
                      }); */
                    Ok((reader, payload))
                }
            });

            // Send frame to all other connected clients
            let connections = connections_inner.clone();
            frame.map(move |(reader, message)| {
                println!("{}: {:?}", cnt, message);
                let mut conns = connections.borrow_mut();
                let iter = conns.iter_mut()
                .filter(|&(&k, _)| k != cnt)
                .map(|(_, v)| v);
                for tx in iter {
                    tx.send(message.clone()).unwrap();
                }
            reader
            })
        });

        // Whenever we receive a string on the Receiver, we write it to
        // `WriteHalf<TcpStream>`.
        let socket_writer = rx.fold(writer, |writer, msg| {
            let amt = io::write_all(writer, msg);
            let amt = amt.map(|(writer, _)| writer);
            amt.map_err(|_| ())
        });

        // Now that we've got futures representing each half of the socket, we
        // use the `select` combinator to wait for either half to be done to
        // tear down the other. Then we spawn off the result.
        let connections = connections.clone();
        let socket_reader = socket_reader.map_err(|_| ());
        let connection = socket_reader.map(|_| ()).select(socket_writer.map(|_| ()));
        handle.spawn(connection.then(move |_| {
            connections.borrow_mut().remove(&cnt);
            println!("Connection {} closed.", addr);
            Ok(())
        }));

        Ok(())
    });

    // execute server
    core.run(srv).unwrap();
}
<commit_msg>Fix buffering borrow checker issue. Still does not compile..<commit_after>/**
 *   Mles-utils to be used with Mles client or server.
 *   Copyright (C) 2017  Mles developers
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
extern crate tokio_core;
extern crate futures;
extern crate mles_utils;

use std::{thread, process, env};
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::net::TcpStream;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::TcpListener;
use std::collections::HashMap;
use std::io::{Read, Error};
use std::io::Write;
use std::time::Duration;
use std::option::Option;
use std::str;
use mles_utils::*;

const HDRL: u64 = 4;
const KEYL: u64 = 8;
const DELAY: u64 = 50;

fn main_old() {
    let mut peer = "".to_string();
    let mut argcnt = 0;
    for arg in env::args() {
        argcnt += 1;
        if 2 == argcnt {
            peer = arg;
            peer += ":8077";
            match peer.parse::<SocketAddr>() {
                Ok(_) => {},
                    Err(err) => {
                        println!("Error: {}\nUsage: mles [peer-address]", err);
                        process::exit(1);
                    },
            }
        }
        if argcnt > 2 {
            println!("Usage: mles [peer-address]");
            process::exit(1);
        }
    }
    let peer = match peer.parse::<SocketAddr>() {
        Ok(addr) => addr,
        Err(_) => {
            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
        },
    };

    let address = "0.0.0.0:8077";
    let listener = match TcpListener::bind(&address) {
        Ok(listener) => listener,
        Err(err) => {
            println!("Error: {}", err);
            process::exit(1);
        },
    };

    let keyval =match env::var("MLES_KEY") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut spawned = HashMap::new();
    let option: Option<Duration> = Some(Duration::from_millis(DELAY));
    let addr = listener.local_addr().unwrap();
    println!("Listening for connections on {}", addr);
    let (tx, rx) = channel();
    let (removedtx, removedrx) = channel();

    for socket in listener.incoming() {
        /* Check first has anybody removed channels */
        let mut remrx = true;
        while remrx {
            match removedrx.try_recv() {
                Ok(val) => {
                    let removed_channel: String = val;
                    println!("Removing unused channel {}", removed_channel.as_str());
                    spawned.remove(&removed_channel);
                    remrx = true;
                },
                Err(_) => { remrx = false; }
            }
        }
        /* 1. Read incoming msg channel
         * 2. If it does not exist, spawn new thread
         * 3. Send socket to thread
         */
        let socket = socket.unwrap();
        let stream = socket.try_clone().unwrap();
        let tuple = read_n(&stream, HDRL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        if 0 == buf.len() {
            continue;
        }
        if read_hdr_type(buf.as_slice()) != 'M' as u32 {
            println!("Incorrect payload type");
            continue;
        }
        // read key
        let tuple = read_n(&stream, KEYL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        // verify key
        let hkey;
        let key = read_key(tuple.1);
        if 0 == keyval.len() {
            let paddr = match stream.peer_addr() {
                Ok(paddr) => paddr,
                Err(_) => {
                    let addr = "0.0.0.0:0";
                    let addr = addr.parse::<SocketAddr>().unwrap();
                    addr
                }
            };
            hkey = do_hash(&paddr);
        }
        else {
            hkey = do_hash(&keyval);
        }
        if hkey != key {
            println!("Incorrect remote key");
            continue;
        }
        let tuple = read_n(&stream, read_hdr_len(buf.as_slice()) as u64);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        let decoded_msg = message_decode(buf.as_slice());
        if 0 == decoded_msg.channel.len() {
            continue;
        }
        let _val = socket.set_nodelay(true);
        let _val = socket.set_read_timeout(option);
        if !spawned.contains_key(decoded_msg.channel.as_str()) {
            let tx = tx.clone();
            let removedtx = removedtx.clone();
            let msg = decoded_msg.clone();
            thread::spawn(move|| process_channel(peer, key, tx, removedtx, msg));

            let thr_feed = rx.recv().unwrap();
            spawned.insert(decoded_msg.channel.clone(), thr_feed);
        }
        let thr_socket = spawned.get_mut(&decoded_msg.channel).unwrap();
        thr_socket.send(socket).unwrap();
    }
}

fn process_channel(peer: SocketAddr, key: u64, tx: Sender<Sender<TcpStream>>, removedtx: Sender<String>, msg: Msg ) {
    let mut cnt = 0;
    let (thr_tx, thr_rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
    println!("Spawned: New channel {} created!", msg.channel);
    let mut users = HashMap::new();
    let mut messages: Vec<Vec<u8>> = Vec::new();
    tx.send(thr_tx.clone()).unwrap();

    // just try once during channel creation
    if 0 != peer.port() {
        match TcpStream::connect(peer) {
            Ok(mut sock) => {
                let option: Option<Duration> = Some(Duration::from_millis(DELAY));
                let _val = sock.set_nodelay(true);
                let _val = sock.set_read_timeout(option);
                let encoded_msg = message_encode(&msg);
                let keyv = write_key(key);
                let mut msgv = write_hdr(encoded_msg.len());
                msgv.extend(keyv);
                msgv.extend(encoded_msg);
                sock.write(msgv.as_slice()).unwrap();

                cnt += 1;
                println!("Adding peer {}", cnt);
                users.insert(cnt, sock);
            },
            Err(_) => {
                println!("Could not connect to peer {}", peer);
            },
        }
    }

    loop {
        let mut removals = Vec::new();
        let mut newuser = true;
        while newuser {
            match thr_rx.try_recv() {
                Ok(val) => {
                    let mut thr: TcpStream = val;
                    cnt += 1;
                    println!("Adding user {}", cnt);
                    users.insert(cnt, thr.try_clone().unwrap());

                    /* If a new user, all push messages to her */
                    for buf in &messages {
                        thr.write(buf.as_slice()).unwrap();
                    }
                    newuser = true;
                },
                Err(_) => { newuser = false; }
            }
        }
        for (user, thr_socket) in &users {
            let stream = thr_socket.try_clone().unwrap();
            let tuple = read_n(&stream, HDRL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let mut buf = tuple.1;
            if 0 == buf.len() {
                continue;
            }
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                continue;
            }
            let hdr_len = read_hdr_len(buf.as_slice()) as u64;
            if 0 == hdr_len {
                continue;
            }
            // read key
            let tuple = read_n(&stream, KEYL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    continue;
                },
                    Ok(_) => {},
                    _ => {
                        continue;
                    },
            }
            let key = tuple.1;
            //ignore key
            buf.extend(key);
            let tuple = read_n(&stream, hdr_len);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let payload = tuple.1;
            if payload.len() != (hdr_len as usize) {
                continue;
            }
            buf.extend(payload);
            for (another_user, mut thr_sock) in &users {
                if user != another_user {
                    thr_sock.write(buf.as_slice()).unwrap();
                }
            }
            /* Add to local db */
            messages.push(buf);
        }
        for removal in &removals {
            println!("Removing user {}", removal);
            users.remove(removal);
        }
        if cnt > 0 && users.is_empty() {
            removedtx.send(msg.channel).unwrap();
            break;
        }
    }
}

fn read_n<R>(reader: R, bytes_to_read: u64) -> (Result<usize, Error>, Vec<u8>)
where R: Read,
{
    let mut buf = vec![];
    let mut chunk = reader.take(bytes_to_read);
    let status = chunk.read_to_end(&mut buf);
    (status, buf)
}

/* Tokio version */
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::iter;
use std::env;
use std::io::{Error, ErrorKind, BufReader};

use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;
use tokio_core::io::{self, Io, Read};

use futures::stream::{self, Stream};
use futures::Future;
use mles_utils::*;

//static mut BUF: Vec<u8> = vec![0,4];

fn main() {
    let addr = env::args().nth(1).unwrap_or("0.0.0.0:8077".to_string());
    let addr = addr.parse().unwrap();
    let mut cnt = 0;

    // Create the event loop and TCP listener we'll accept connections on.
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();
    println!("Listening on: {}", addr);

    // This is a single-threaded server, so we can just use Rc and RefCell to
    // store the map of all connections we know about.
    let connections = Rc::new(RefCell::new(HashMap::new()));

    let srv = socket.incoming().for_each(move |(stream, addr)| {
        println!("New Connection: {}", addr);
        let (reader, writer) = stream.split();

        // Create a channel for our stream, which other sockets will use to
        // send us messages. Then register our address with the stream to send
        // data to us.
        let (tx, rx) = futures::sync::mpsc::unbounded();
        cnt += 1;
        connections.borrow_mut().insert(cnt, tx);

        // Define here what we do for the actual I/O. That is, read a bunch of
        // frames from the socket and dispatch them while we also write any frames
        // from other sockets.
        let connections_inner = connections.clone();

        // Model the read portion of this socket by mapping an infinite
        // iterator to each frame off the socket. This "loop" is then
        // terminated with an error once we hit EOF on the socket.
        let iter = stream::iter(iter::repeat(()).map(Ok::<(), Error>));
        let socket_reader = iter.fold(reader, move |reader, _| {
            // Read a off header the socket, failing if we're at EOF
            let frame = io::read_exact(reader, vec![0;4]);
            let frame = frame.and_then(|(reader, payload)| {
                if payload.len() == 0 {
                    Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
                } else {
                    if read_hdr_type(payload.as_slice()) != 'M' as u32 {
                        return Err(Error::new(ErrorKind::BrokenPipe, "incorrect header"));
                    }
                    let hdr_len = read_hdr_len(payload.as_slice());
                    if 0 == hdr_len {
                        return Err(Error::new(ErrorKind::BrokenPipe, "incorrect header len"));
                    }
                    let pframe = io::read_exact(reader, vec![0;hdr_len]);
                    let pframe = pframe.and_then(|(reader, buf)| {
                        if buf.len() == 0 {
                            return Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
                        }
                        Ok((reader, buf))
                    });
                    Ok((reader, payload))
                }
            });

            // Send frame to all other connected clients
            let connections = connections_inner.clone();
            frame.map(move |(reader, message)| {
                println!("{}: {:?}", cnt, message);
                let mut conns = connections.borrow_mut();
                let iter = conns.iter_mut()
                .filter(|&(&k, _)| k != cnt)
                .map(|(_, v)| v);
                for tx in iter {
                    tx.send(message.clone()).unwrap();
                }
            reader
            })
        });

        // Whenever we receive a string on the Receiver, we write it to
        // `WriteHalf<TcpStream>`.
        let socket_writer = rx.fold(writer, |writer, msg| {
            let amt = io::write_all(writer, msg);
            let amt = amt.map(|(writer, _)| writer);
            amt.map_err(|_| ())
        });

        // Now that we've got futures representing each half of the socket, we
        // use the `select` combinator to wait for either half to be done to
        // tear down the other. Then we spawn off the result.
        let connections = connections.clone();
        let socket_reader = socket_reader.map_err(|_| ());
        let connection = socket_reader.map(|_| ()).select(socket_writer.map(|_| ()));
        handle.spawn(connection.then(move |_| {
            connections.borrow_mut().remove(&cnt);
            println!("Connection {} closed.", addr);
            Ok(())
        }));

        Ok(())
    });

    // execute server
    core.run(srv).unwrap();
}
<|endoftext|>


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

use crate::serde_helpers::{de, ser};

use chrono::{DateTime, Duration, Utc};
use failure::{format_err, Fail};
use serde::{Deserialize, Serialize};
use serde_ini;
use slog_scope::debug;
use std::{
    io,
    path::{Path, PathBuf},
};

#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
pub(crate) struct RuntimeSettings {
    polling: RuntimePolling,
    update: RuntimeUpdate,
    #[serde(skip)]
    path: PathBuf,
    #[serde(skip)]
    persistent: bool,
}

impl RuntimeSettings {
    pub(crate) fn new() -> Self {
        Self::default()
    }

    pub(crate) fn load(mut self, path: &str) -> Result<Self, failure::Error> {
        use std::{fs::File, io::Read};

        let path = Path::new(path);

        if path.exists() {
            debug!(
                "Loading runtime settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;
            self = Self::parse(&content)?;
        } else {
            debug!(
                "Runtime settings file {} does not exists. Using default runtime settings...",
                path.to_string_lossy()
            );
        }

        self.path = path.to_path_buf();
        Ok(self)
    }

    fn parse(content: &str) -> Result<Self, failure::Error> {
        Ok(serde_ini::from_str::<Self>(content)?)
    }

    fn save(&self) -> Result<(), failure::Error> {
        use std::{
            fs::{self, File},
            io::Write,
        };

        if !self.persistent {
            debug!("Skipping runtime settings save, using non-persistent.");
            return Ok(());
        }

        self.path
            .parent()
            .ok_or_else(|| format_err!("Invalid runtime settings destination"))
            .and_then(|p| {
                if !p.exists() {
                    debug!("Creating runtime settings to store state.");
                    fs::create_dir_all(p)?;
                }

                Ok(())
            })?;

        debug!("Saving runtime settings from '{}'...", &self.path.display());
        File::create(&self.path)?.write_all(self.serialize()?.as_bytes())?;

        Ok(())
    }

    fn serialize(&self) -> Result<String, failure::Error> {
        Ok(serde_ini::to_string(&self)?)
    }

    pub(crate) fn enable_persistency(&mut self) {
        self.persistent = true;
    }

    pub(crate) fn is_polling_forced(&self) -> bool {
        self.polling.now
    }

    pub(crate) fn force_poll(&mut self) -> Result<(), failure::Error> {
        self.polling.now = true;
        self.save()
    }

    pub(crate) fn retries(&self) -> usize {
        self.polling.retries
    }

    pub(crate) fn inc_retries(&mut self) {
        self.polling.retries += 1;
    }

    pub(crate) fn clear_retries(&mut self) {
        self.polling.retries = 0;
    }

    pub(crate) fn polling_extra_interval(&self) -> Option<Duration> {
        self.polling.extra_interval
    }

    pub(crate) fn set_polling_extra_interval(
        &mut self,
        extra_interval: Duration,
    ) -> Result<(), failure::Error> {
        self.polling.extra_interval = Some(extra_interval);
        self.save()
    }

    pub(crate) fn last_polling(&self) -> Option<DateTime<Utc>> {
        self.polling.last
    }

    pub(crate) fn set_last_polling(
        &mut self,
        last_polling: DateTime<Utc>,
    ) -> Result<(), failure::Error> {
        self.polling.last = Some(last_polling);
        self.save()
    }

    pub(crate) fn applied_package_uid(&self) -> Option<String> {
        self.update.applied_package_uid.clone()
    }

    pub(crate) fn set_applied_package_uid(
        &mut self,
        applied_package_uid: &str,
    ) -> Result<(), failure::Error> {
        self.update.applied_package_uid = Some(applied_package_uid.to_string());
        self.save()
    }
}

#[derive(Debug, Fail)]
pub(crate) enum Error {
    #[cause]
    #[fail(display = "IO error")]
    Io(io::Error),
    #[cause]
    #[fail(display = "Fail reading the INI file")]
    IniDeserialize(serde_ini::de::Error),
    #[cause]
    #[fail(display = "Fail generating the INI file")]
    IniSerialize(serde_ini::ser::Error),
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "LastPoll")]
    last: Option<DateTime<Utc>>,
    #[serde(deserialize_with = "de::duration_from_int")]
    #[serde(serialize_with = "ser::duration_option_to_int")]
    extra_interval: Option<Duration>,
    retries: usize,
    #[serde(rename = "ProbeASAP")]
    #[serde(deserialize_with = "de::bool_from_str")]
    #[serde(serialize_with = "ser::bool_to_string")]
    now: bool,
}

impl Default for RuntimePolling {
    fn default() -> Self {
        Self {
            last: None,
            extra_interval: None,
            retries: 0,
            now: false,
        }
    }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
struct RuntimeUpdate {
    #[serde(rename = "UpgradeToInstallation")]
    upgrading_to: i8,
    #[serde(skip_serializing_if = "Option::is_none")]
    applied_package_uid: Option<String>,
}

impl Default for RuntimeUpdate {
    fn default() -> Self {
        Self {
            upgrading_to: -1,
            applied_package_uid: None,
        }
    }
}

#[test]
fn de() {
    use pretty_assertions::assert_eq;
    let ini = r"
[Polling]
LastPoll=2017-01-01T00:00:00Z
ExtraInterval=4
Retries=5
ProbeASAP=false

[Update]
UpgradeToInstallation=1
";
    let expected = RuntimeSettings {
        polling: RuntimePolling {
            last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
            extra_interval: Some(Duration::seconds(4)),
            retries: 5,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: 1,
            applied_package_uid: None,
        },
        ..Default::default()
    };

    assert_eq!(
        serde_ini::from_str::<RuntimeSettings>(ini)
            .map_err(|e| println!("{}", e))
            .as_ref()
            .ok(),
        Some(&expected)
    );
    assert_eq!(RuntimeSettings::parse(ini).as_ref().ok(), Some(&expected));
}

#[test]
fn default() {
    use pretty_assertions::assert_eq;
    let settings = RuntimeSettings::new();
    let expected = RuntimeSettings {
        polling: RuntimePolling {
            last: None,
            extra_interval: None,
            retries: 0,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: -1,
            applied_package_uid: None,
        },
        path: PathBuf::new(),
        persistent: false,
    };

    assert_eq!(Some(settings), Some(expected));
}

#[test]
fn ser() {
    use pretty_assertions::assert_eq;
    let settings = RuntimeSettings {
        polling: RuntimePolling {
            last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
            extra_interval: Some(Duration::seconds(4)),
            retries: 5,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: 1,
            applied_package_uid: Some("package-uid".to_string()),
        },
        ..Default::default()
    };

    assert_eq!(
        serde_ini::from_str(&settings.serialize().unwrap()).ok(),
        Some(settings)
    );
}

#[test]
fn load_and_save() {
    use pretty_assertions::assert_eq;
    use std::fs;
    use tempfile::NamedTempFile;

    let tempfile = NamedTempFile::new().unwrap();
    let settings_file = tempfile.path();
    fs::remove_file(&settings_file).unwrap();

    let mut settings = RuntimeSettings::new()
        .load(settings_file.to_str().unwrap())
        .unwrap();

    assert_eq!(settings.polling.now, false);
    settings.polling.now = true;

    assert_eq!(settings.polling.now, true);
    settings
        .save()
        .expect("Failed to save the runtime settings");

    let new_settings = RuntimeSettings::new()
        .load(settings_file.to_str().unwrap())
        .unwrap();

    assert_eq!(settings.update, new_settings.update);
}
<commit_msg>updatehub: Derive default for runtime_settings::RuntimePolling<commit_after>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::serde_helpers::{de, ser};

use chrono::{DateTime, Duration, Utc};
use failure::{format_err, Fail};
use serde::{Deserialize, Serialize};
use serde_ini;
use slog_scope::debug;
use std::{
    io,
    path::{Path, PathBuf},
};

#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
pub(crate) struct RuntimeSettings {
    polling: RuntimePolling,
    update: RuntimeUpdate,
    #[serde(skip)]
    path: PathBuf,
    #[serde(skip)]
    persistent: bool,
}

impl RuntimeSettings {
    pub(crate) fn new() -> Self {
        Self::default()
    }

    pub(crate) fn load(mut self, path: &str) -> Result<Self, failure::Error> {
        use std::{fs::File, io::Read};

        let path = Path::new(path);

        if path.exists() {
            debug!(
                "Loading runtime settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;
            self = Self::parse(&content)?;
        } else {
            debug!(
                "Runtime settings file {} does not exists. Using default runtime settings...",
                path.to_string_lossy()
            );
        }

        self.path = path.to_path_buf();
        Ok(self)
    }

    fn parse(content: &str) -> Result<Self, failure::Error> {
        Ok(serde_ini::from_str::<Self>(content)?)
    }

    fn save(&self) -> Result<(), failure::Error> {
        use std::{
            fs::{self, File},
            io::Write,
        };

        if !self.persistent {
            debug!("Skipping runtime settings save, using non-persistent.");
            return Ok(());
        }

        self.path
            .parent()
            .ok_or_else(|| format_err!("Invalid runtime settings destination"))
            .and_then(|p| {
                if !p.exists() {
                    debug!("Creating runtime settings to store state.");
                    fs::create_dir_all(p)?;
                }

                Ok(())
            })?;

        debug!("Saving runtime settings from '{}'...", &self.path.display());
        File::create(&self.path)?.write_all(self.serialize()?.as_bytes())?;

        Ok(())
    }

    fn serialize(&self) -> Result<String, failure::Error> {
        Ok(serde_ini::to_string(&self)?)
    }

    pub(crate) fn enable_persistency(&mut self) {
        self.persistent = true;
    }

    pub(crate) fn is_polling_forced(&self) -> bool {
        self.polling.now
    }

    pub(crate) fn force_poll(&mut self) -> Result<(), failure::Error> {
        self.polling.now = true;
        self.save()
    }

    pub(crate) fn retries(&self) -> usize {
        self.polling.retries
    }

    pub(crate) fn inc_retries(&mut self) {
        self.polling.retries += 1;
    }

    pub(crate) fn clear_retries(&mut self) {
        self.polling.retries = 0;
    }

    pub(crate) fn polling_extra_interval(&self) -> Option<Duration> {
        self.polling.extra_interval
    }

    pub(crate) fn set_polling_extra_interval(
        &mut self,
        extra_interval: Duration,
    ) -> Result<(), failure::Error> {
        self.polling.extra_interval = Some(extra_interval);
        self.save()
    }

    pub(crate) fn last_polling(&self) -> Option<DateTime<Utc>> {
        self.polling.last
    }

    pub(crate) fn set_last_polling(
        &mut self,
        last_polling: DateTime<Utc>,
    ) -> Result<(), failure::Error> {
        self.polling.last = Some(last_polling);
        self.save()
    }

    pub(crate) fn applied_package_uid(&self) -> Option<String> {
        self.update.applied_package_uid.clone()
    }

    pub(crate) fn set_applied_package_uid(
        &mut self,
        applied_package_uid: &str,
    ) -> Result<(), failure::Error> {
        self.update.applied_package_uid = Some(applied_package_uid.to_string());
        self.save()
    }
}

#[derive(Debug, Fail)]
pub(crate) enum Error {
    #[cause]
    #[fail(display = "IO error")]
    Io(io::Error),
    #[cause]
    #[fail(display = "Fail reading the INI file")]
    IniDeserialize(serde_ini::de::Error),
    #[cause]
    #[fail(display = "Fail generating the INI file")]
    IniSerialize(serde_ini::ser::Error),
}

#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "LastPoll")]
    last: Option<DateTime<Utc>>,
    #[serde(deserialize_with = "de::duration_from_int")]
    #[serde(serialize_with = "ser::duration_option_to_int")]
    extra_interval: Option<Duration>,
    retries: usize,
    #[serde(rename = "ProbeASAP")]
    #[serde(deserialize_with = "de::bool_from_str")]
    #[serde(serialize_with = "ser::bool_to_string")]
    now: bool,
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
struct RuntimeUpdate {
    #[serde(rename = "UpgradeToInstallation")]
    upgrading_to: i8,
    #[serde(skip_serializing_if = "Option::is_none")]
    applied_package_uid: Option<String>,
}

impl Default for RuntimeUpdate {
    fn default() -> Self {
        Self {
            upgrading_to: -1,
            applied_package_uid: None,
        }
    }
}

#[test]
fn de() {
    use pretty_assertions::assert_eq;
    let ini = r"
[Polling]
LastPoll=2017-01-01T00:00:00Z
ExtraInterval=4
Retries=5
ProbeASAP=false

[Update]
UpgradeToInstallation=1
";
    let expected = RuntimeSettings {
        polling: RuntimePolling {
            last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
            extra_interval: Some(Duration::seconds(4)),
            retries: 5,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: 1,
            applied_package_uid: None,
        },
        ..Default::default()
    };

    assert_eq!(
        serde_ini::from_str::<RuntimeSettings>(ini)
            .map_err(|e| println!("{}", e))
            .as_ref()
            .ok(),
        Some(&expected)
    );
    assert_eq!(RuntimeSettings::parse(ini).as_ref().ok(), Some(&expected));
}

#[test]
fn default() {
    use pretty_assertions::assert_eq;
    let settings = RuntimeSettings::new();
    let expected = RuntimeSettings {
        polling: RuntimePolling {
            last: None,
            extra_interval: None,
            retries: 0,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: -1,
            applied_package_uid: None,
        },
        path: PathBuf::new(),
        persistent: false,
    };

    assert_eq!(Some(settings), Some(expected));
}

#[test]
fn ser() {
    use pretty_assertions::assert_eq;
    let settings = RuntimeSettings {
        polling: RuntimePolling {
            last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
            extra_interval: Some(Duration::seconds(4)),
            retries: 5,
            now: false,
        },
        update: RuntimeUpdate {
            upgrading_to: 1,
            applied_package_uid: Some("package-uid".to_string()),
        },
        ..Default::default()
    };

    assert_eq!(
        serde_ini::from_str(&settings.serialize().unwrap()).ok(),
        Some(settings)
    );
}

#[test]
fn load_and_save() {
    use pretty_assertions::assert_eq;
    use std::fs;
    use tempfile::NamedTempFile;

    let tempfile = NamedTempFile::new().unwrap();
    let settings_file = tempfile.path();
    fs::remove_file(&settings_file).unwrap();

    let mut settings = RuntimeSettings::new()
        .load(settings_file.to_str().unwrap())
        .unwrap();

    assert_eq!(settings.polling.now, false);
    settings.polling.now = true;

    assert_eq!(settings.polling.now, true);
    settings
        .save()
        .expect("Failed to save the runtime settings");

    let new_settings = RuntimeSettings::new()
        .load(settings_file.to_str().unwrap())
        .unwrap();

    assert_eq!(settings.update, new_settings.update);
}
<|endoftext|>


<commit_before>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use std::path::Path;
use std::fs::File;
use std::io::Read;

use proc_macro::TokenStream;

#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = {
        let src = syn_item.attrs.iter().filter_map(|attr| {
            match attr.value {
                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                    Some(val.clone())
                },
                _ => None
            }
        }).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");

        let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
        let path = Path::new(&root).join(&src[..]);

        if path.is_file() {
            let mut buf = String::new();
            File::open(path).and_then(|mut file| file.read_to_string(&mut buf)).expect("Unable to read source from given file");
            buf
        } else {
            src
        }
    };

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<commit_msg>Use path attribute instead of src for filename<commit_after>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use std::path::Path;
use std::fs::File;
use std::io::Read;

use proc_macro::TokenStream;

enum SourceKind {
    Src(String),
    Path(String),
}

#[proc_macro_derive(VulkanoShader, attributes(src, path, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = {
        let mut iter = syn_item.attrs.iter().filter_map(|attr| {
            match attr.value {
                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                    Some(SourceKind::Src(val.clone()))
                },

                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "path" => {
                    Some(SourceKind::Path(val.clone()))
                },

                _ => None
            }
        });

        let source = iter.next().expect("No source attribute given ; put #[src = \"...\"] or #[path = \"...\"]");

        if iter.next().is_some() {
            panic!("Multilpe src or path attributes given ; please provide only one");
        }

        match source {
            SourceKind::Src(src) => src,

            SourceKind::Path(path) => {
                let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
                let path = Path::new(&root).join(&path);

                if path.is_file() {
                    let mut buf = String::new();
                    File::open(path).and_then(|mut file| file.read_to_string(&mut buf)).expect("Unable to read source from given file");
                    buf
                } else {
                    panic!("Given source file does not exist");
                }
            }
        }
    };

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<|endoftext|>


<commit_before>use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::collections::VecDeque;

use progress::Timestamp;
use communication::Data;
use communication::{Communicator, Pullable, Pushable, Observer};
use communication::observer::ExchangeObserver;

use columnar::Columnar;

// A ParallelizationContract transforms the output of a Communicator, a (Vec<Pushable>, Pullable), to an (Observer, Pullable)
// TODO : There is an asymmetry with the Observer/Pullable interface at the moment in that the Pullable
// TODO : yields (and loses) vectors, which need to be continually allocated on the Observer side. It would
// TODO : be better if there were a way to recycle them, perhaps by having the Pullable only show them,
// TODO : or be a Pullable<(&T, &mut Vec<D>)>, or Pullable<(T, Iterator<D>)>, or who knows what...
pub trait ParallelizationContract<T: Timestamp, D: Data> {
    type Observer: Observer<Time=T, Data=D>+'static;
    type Pullable: Pullable<(T, Vec<D>)>+'static;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>);
}

// direct connection
pub struct Pipeline;
impl<T: Timestamp, D: Data> ParallelizationContract<T, D> for Pipeline {
    type Observer = PactObserver<T, D, Rc<RefCell<VecDeque<(T, Vec<D>)>>>>;
    type Pullable = Rc<RefCell<VecDeque<(T, Vec<D>)>>>;
    fn connect<C: Communicator>(self,_communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let shared1 = Rc::new(RefCell::new(VecDeque::new()));
        let shared2 = Rc::new(RefCell::new(Vec::new()));
        return (PactObserver::new(shared1.clone(), shared2.clone()), PactPullable::new(shared1, shared2));
    }
}

// exchanges between multiple observers
pub struct Exchange<D, F: Fn(&D)->u64> { hash_func: F, phantom: PhantomData<D>, }
impl<D, F: Fn(&D)->u64> Exchange<D, F> {
    pub fn new(func: F) -> Exchange<D, F> {
        Exchange {
            hash_func:  func,
            phantom:    PhantomData,
        }
    }
}

// Exchange uses a Box<Pushable> because it cannot know what type of pushable will return from the communicator.
// The PactObserver will do some buffering for Exchange, cutting down on the virtual calls, but we still
// would like to get the vectors it sends back, so that they can be re-used if possible.
impl<T: Timestamp, D: Data+Columnar, F: Fn(&D)->u64+'static> ParallelizationContract<T, D> for Exchange<D, F> {
    type Observer = ExchangeObserver<PactObserver<T, D, Box<Pushable<(T, Vec<D>)>>>, F>;
    type Pullable = Box<Pullable<(T, Vec<D>)>>;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let (senders, receiver) = communicator.new_channel();

        let shared = Rc::new(RefCell::new(Vec::new()));

        let exchange_sender = ExchangeObserver {
            observers:  senders.into_iter().map(|x| PactObserver::new(x, shared.clone())).collect(),
            hash_func:  self.hash_func,
        };

        return (exchange_sender, PactPullable::new(receiver, shared));
    }
}

pub struct PactPullable<T:Send, D:Send+Clone, P: Pullable<(T, Vec<D>)>> {
    pullable: P,
    buffer:   Vec<D>,
    shared:   Rc<RefCell<Vec<Vec<D>>>>,
    phantom:  PhantomData<T>,
}

impl<T:Send, D: Send+Clone, P: Pullable<(T, Vec<D>)>> PactPullable<T, D, P> {
    pub fn pull(&mut self) -> Option<(T, &mut Vec<D>)> {
        if let Some((time, mut data)) = self.pullable.pull() {
            if data.len() > 0 {
                mem::swap(&mut data, &mut self.buffer);
                data.clear();
                // self.shared.borrow_mut().push(data);
                Some((time, &mut self.buffer))
            } else { None }
        } else { None }
    }
    fn new(pullable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactPullable<T, D, P> {
        PactPullable {
            pullable: pullable,
            buffer:   Vec::new(),
            shared:   shared,
            phantom:  PhantomData,
        }
    }
}

pub struct PactObserver<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> {
    pub data:       Vec<D>,
    pub pushable:   P,
    pub phantom:    PhantomData<T>,
    shared:         Rc<RefCell<Vec<Vec<D>>>>,
    // threshold:      usize, // TODO : add this in, cloning time, I guess.
    my_time:        Option<T>,
}

impl<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> PactObserver<T, D, P> {
    pub fn new(pushable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactObserver<T, D, P> {
        PactObserver {
            data:       Vec::new(),
            pushable:   pushable,
            phantom:    PhantomData,
            shared:     shared,
            my_time:    None,
        }
    }
}

impl<T:Send+Clone, D:Send+Clone, P: Pushable<(T, Vec<D>)>> Observer for PactObserver<T,D,P> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) { self.my_time = Some(time.clone()); }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.data.push(data);
        if self.data.len() > 1024 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            self.pushable.push((self.my_time.as_ref().unwrap().clone(), mem::replace(&mut self.data, empty)));
        }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.data.len() > 0 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            // if empty.capacity() == 0 { println!("empty buffer!"); }
            self.pushable.push((time.clone(), mem::replace(&mut self.data, empty)));
        }
    }
}

// broadcasts to all observers
// TODO : This needs support from the progress tracking protocol;
// TODO : we don't know/report how many messages are actually created.
// pub struct Broadcast;
// impl<T: Timestamp, D: Data+Columnar> ParallelizationContract<T, D> for Broadcast {
//     type Observer = BroadcastObserver<PushableObserver<T,D,Box<Pushable<(T,Vec<D>)>>>>;
//     type Pullable = Box<Pullable<(T, Vec<D>)>>;
//     fn connect<C: Communicator>(self, communicator: &mut C) -> (<Broadcast as ParallelizationContract<T, D>>::Observer,
//                                                                 <Broadcast as ParallelizationContract<T, D>>::Pullable) {
//         let (senders, receiver) = communicator.new_channel();
//
//         let exchange_sender = BroadcastObserver {
//             observers:  senders.into_iter().map(|x| PushableObserver { data: Vec::new(), pushable: x, phantom: PhantomData }).collect()
//         };
//
//         panic!("Broadcast won't work until progress counting becomes aware of how many records are sent");
//
//         return (exchange_sender, receiver);
//     }
// }
<commit_msg>revert pact transimssion; seems buggy<commit_after>use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::collections::VecDeque;

use progress::Timestamp;
use communication::Data;
use communication::{Communicator, Pullable, Pushable, Observer};
use communication::observer::ExchangeObserver;

use columnar::Columnar;

// A ParallelizationContract transforms the output of a Communicator, a (Vec<Pushable>, Pullable), to an (Observer, Pullable)
// TODO : There is an asymmetry with the Observer/Pullable interface at the moment in that the Pullable
// TODO : yields (and loses) vectors, which need to be continually allocated on the Observer side. It would
// TODO : be better if there were a way to recycle them, perhaps by having the Pullable only show them,
// TODO : or be a Pullable<(&T, &mut Vec<D>)>, or Pullable<(T, Iterator<D>)>, or who knows what...
pub trait ParallelizationContract<T: Timestamp, D: Data> {
    type Observer: Observer<Time=T, Data=D>+'static;
    type Pullable: Pullable<(T, Vec<D>)>+'static;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>);
}

// direct connection
pub struct Pipeline;
impl<T: Timestamp, D: Data> ParallelizationContract<T, D> for Pipeline {
    type Observer = PactObserver<T, D, Rc<RefCell<VecDeque<(T, Vec<D>)>>>>;
    type Pullable = Rc<RefCell<VecDeque<(T, Vec<D>)>>>;
    fn connect<C: Communicator>(self,_communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let shared1 = Rc::new(RefCell::new(VecDeque::new()));
        let shared2 = Rc::new(RefCell::new(Vec::new()));
        return (PactObserver::new(shared1.clone(), shared2.clone()), PactPullable::new(shared1, shared2));
    }
}

// exchanges between multiple observers
pub struct Exchange<D, F: Fn(&D)->u64> { hash_func: F, phantom: PhantomData<D>, }
impl<D, F: Fn(&D)->u64> Exchange<D, F> {
    pub fn new(func: F) -> Exchange<D, F> {
        Exchange {
            hash_func:  func,
            phantom:    PhantomData,
        }
    }
}

// Exchange uses a Box<Pushable> because it cannot know what type of pushable will return from the communicator.
// The PactObserver will do some buffering for Exchange, cutting down on the virtual calls, but we still
// would like to get the vectors it sends back, so that they can be re-used if possible.
impl<T: Timestamp, D: Data+Columnar, F: Fn(&D)->u64+'static> ParallelizationContract<T, D> for Exchange<D, F> {
    type Observer = ExchangeObserver<PactObserver<T, D, Box<Pushable<(T, Vec<D>)>>>, F>;
    type Pullable = Box<Pullable<(T, Vec<D>)>>;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let (senders, receiver) = communicator.new_channel();

        let shared = Rc::new(RefCell::new(Vec::new()));

        let exchange_sender = ExchangeObserver {
            observers:  senders.into_iter().map(|x| PactObserver::new(x, shared.clone())).collect(),
            hash_func:  self.hash_func,
        };

        return (exchange_sender, PactPullable::new(receiver, shared));
    }
}

pub struct PactPullable<T:Send, D:Send+Clone, P: Pullable<(T, Vec<D>)>> {
    pullable: P,
    buffer:   Vec<D>,
    shared:   Rc<RefCell<Vec<Vec<D>>>>,
    phantom:  PhantomData<T>,
}

impl<T:Send, D: Send+Clone, P: Pullable<(T, Vec<D>)>> PactPullable<T, D, P> {
    pub fn pull(&mut self) -> Option<(T, &mut Vec<D>)> {
        if let Some((time, mut data)) = self.pullable.pull() {
            if data.len() > 0 {
                mem::swap(&mut data, &mut self.buffer);
                data.clear();
                // self.shared.borrow_mut().push(data);
                Some((time, &mut self.buffer))
            } else { None }
        } else { None }
    }
    fn new(pullable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactPullable<T, D, P> {
        PactPullable {
            pullable: pullable,
            buffer:   Vec::new(),
            shared:   shared,
            phantom:  PhantomData,
        }
    }
}

pub struct PactObserver<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> {
    pub data:       Vec<D>,
    pub pushable:   P,
    pub phantom:    PhantomData<T>,
    shared:         Rc<RefCell<Vec<Vec<D>>>>,
    // threshold:      usize, // TODO : add this in, cloning time, I guess.
    my_time:        Option<T>,
}

impl<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> PactObserver<T, D, P> {
    pub fn new(pushable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactObserver<T, D, P> {
        PactObserver {
            data:       Vec::new(),
            pushable:   pushable,
            phantom:    PhantomData,
            shared:     shared,
            my_time:    None,
        }
    }
}

impl<T:Send+Clone, D:Send+Clone, P: Pushable<(T, Vec<D>)>> Observer for PactObserver<T,D,P> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) { self.my_time = Some(time.clone()); }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.data.push(data);
        // TODO : causes correctness issue in notification; likely subtlely wrong... =/
        // if self.data.len() > 1024 {
        //     let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
        //     self.pushable.push((self.my_time.as_ref().unwrap().clone(), mem::replace(&mut self.data, empty)));
        // }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.data.len() > 0 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            assert!(empty.len() == 0);
            self.pushable.push((time.clone(), mem::replace(&mut self.data, empty)));
        }
    }
}

// broadcasts to all observers
// TODO : This needs support from the progress tracking protocol;
// TODO : we don't know/report how many messages are actually created.
// pub struct Broadcast;
// impl<T: Timestamp, D: Data+Columnar> ParallelizationContract<T, D> for Broadcast {
//     type Observer = BroadcastObserver<PushableObserver<T,D,Box<Pushable<(T,Vec<D>)>>>>;
//     type Pullable = Box<Pullable<(T, Vec<D>)>>;
//     fn connect<C: Communicator>(self, communicator: &mut C) -> (<Broadcast as ParallelizationContract<T, D>>::Observer,
//                                                                 <Broadcast as ParallelizationContract<T, D>>::Pullable) {
//         let (senders, receiver) = communicator.new_channel();
//
//         let exchange_sender = BroadcastObserver {
//             observers:  senders.into_iter().map(|x| PushableObserver { data: Vec::new(), pushable: x, phantom: PhantomData }).collect()
//         };
//
//         panic!("Broadcast won't work until progress counting becomes aware of how many records are sent");
//
//         return (exchange_sender, receiver);
//     }
// }
<|endoftext|>