<commit_before>extern crate env_logger;
extern crate alacrity;

use std::env;
use std::net::SocketAddr;
use std::thread;

use alacrity::pool::Pool;
use alacrity::mgmt;

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

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let backend = env::args().nth(2).unwrap_or("127.0.0.1:12345".to_string());
    let backend = backend.parse::<SocketAddr>().unwrap();
    let pool = Pool::with_servers(vec![backend]);

    let admin_ip = env::args().nth(2).unwrap_or("127.0.0.1:8687".to_string());
    let admin_addr = admin_ip.parse::<SocketAddr>().unwrap();
    let p = pool.clone();
    let _ = thread::Builder::new().name("management".to_string()).spawn(move || {
        mgmt::listen(admin_addr, p);
    }).expect("Failed to create proxy thread");

    alacrity::proxy::listen(addr, pool.clone()).expect("Failed to start server");
}
<commit_msg>do not use the 2nd adress for backend and admin<commit_after>extern crate env_logger;
extern crate alacrity;

use std::env;
use std::net::SocketAddr;
use std::thread;

use alacrity::pool::Pool;
use alacrity::mgmt;

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

    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let backend = env::args().nth(2).unwrap_or("127.0.0.1:12345".to_string());
    let backend = backend.parse::<SocketAddr>().unwrap();
    let pool = Pool::with_servers(vec![backend]);

    let admin_ip = env::args().nth(3).unwrap_or("127.0.0.1:8687".to_string());
    let admin_addr = admin_ip.parse::<SocketAddr>().unwrap();
    let p = pool.clone();
    let _ = thread::Builder::new().name("management".to_string()).spawn(move || {
        mgmt::listen(admin_addr, p);
    }).expect("Failed to create proxy thread");

    alacrity::proxy::listen(addr, pool.clone()).expect("Failed to start server");
}
<|endoftext|>


<commit_before>extern crate lion;
extern crate readline;

use readline::{readline, add_history, Error as ReadlineError};

use lion::parse;
use lion::eval::eval_context::EvalContext;

fn main() {
    let mut context = EvalContext::prelude();

    loop {
        let line = match readline("\u{03BB} ") {
            Ok(data) => data,
            Err(ReadlineError::EndOfFile) => break,
            Err(e) => {
                println!("{}", e);
                break;
            },
        };
        add_history(&line).expect("Error adding line to history");

        let program = parse(&line);
        if program.is_err() {
            println!("Parse error: {:?}", program.unwrap_err());
            continue;
        }
        let program = program.unwrap();

        for stmt in program {
            let result = context.apply(stmt);

            if result.is_ok() {
                println!("{:?}", result.unwrap());
            }
            else {
                println!("Error: {:?}", result.unwrap_err());
                break;
            }
        }
    }
}

<commit_msg>Adding a header with the version as well as nicer formatting on exit<commit_after>extern crate lion;
extern crate readline;

use readline::{readline, add_history, Error as ReadlineError};

use lion::parse;
use lion::eval::eval_context::EvalContext;

fn main() {
    let mut context = EvalContext::prelude();

    println!("lion v{}", env!("CARGO_PKG_VERSION"));

    loop {
        let line = match readline("\u{03BB} ") {
            Ok(data) => data,
            Err(ReadlineError::EndOfFile) => {
                // Print an empty line so that the prompt doesn't
                // throw off the user's next line
                println!("");
                break;
            },
            Err(e) => {
                println!("{}", e);
                break;
            },
        };
        add_history(&line).expect("Error adding line to history");

        let program = parse(&line);
        if program.is_err() {
            println!("Parse error: {:?}", program.unwrap_err());
            continue;
        }
        let program = program.unwrap();

        for stmt in program {
            let result = context.apply(stmt);

            if result.is_ok() {
                println!("{:?}", result.unwrap());
            }
            else {
                println!("Error: {:?}", result.unwrap_err());
                break;
            }
        }
    }
}

<|endoftext|>


<commit_before>pub mod bookitem;

pub use self::bookitem::{BookItem, BookItems};

use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;

use {parse, theme, utils};
use renderer::{HtmlHandlebars, Renderer};
use preprocess;
use errors::*;

use config::Config;

pub struct MDBook {
    pub root: PathBuf,
    pub config: Config,

    pub content: Vec<BookItem>,
    renderer: Box<Renderer>,

    pub livereload: Option<String>,
}

impl MDBook {
    /// Create a new `MDBook` struct with root directory `root`
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// let book = MDBook::new("root_dir");
    /// # }
    /// ```
    ///
    /// In this example, `root_dir` will be the root directory of our book
    /// and is specified in function of the current working directory
    /// by using a relative path instead of an
    /// absolute path.
    ///
    /// Default directory paths:
    ///
    /// - source: `root/src`
    /// - output: `root/book`
    /// - theme: `root/theme`
    ///
    /// They can both be changed by using [`set_src()`](#method.set_src) and
    /// [`set_dest()`](#method.set_dest)

    pub fn new<P: Into<PathBuf>>(root: P) -> MDBook {
        let root = root.into();
        if !root.exists() || !root.is_dir() {
            warn!("{:?} No directory with that name", root);
        }

        MDBook {
            root: root,
            config: Config::default(),

            content: vec![],
            renderer: Box::new(HtmlHandlebars::new()),

            livereload: None,
        }
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::new("mybook");
    /// for item in book.iter() {
    ///     match item {
    ///         &BookItem::Chapter(ref section, ref chapter) => {},
    ///         &BookItem::Affix(ref chapter) => {},
    ///         &BookItem::Spacer => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```

    pub fn iter(&self) -> BookItems {
        BookItems {
            items: &self.content[..],
            current_index: 0,
            stack: Vec::new(),
        }
    }

    /// `init()` creates some boilerplate files and directories
    /// to get you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the paths given as source and output directories
    /// and adds a `SUMMARY.md` and a
    /// `chapter_1.md` to the source directory.

    pub fn init(&mut self) -> Result<()> {
        debug!("[fn]: init");

        if !self.root.exists() {
            fs::create_dir_all(&self.root).unwrap();
            info!("{:?} created", self.root.display());
        }

        {
            let dest = self.get_destination();
            if !dest.exists() {
                debug!("[*]: {} does not exist, trying to create directory", dest.display());
                fs::create_dir_all(dest)?;
            }

            let src = self.get_source();
            if !src.exists() {
                debug!("[*]: {} does not exist, trying to create directory", src.display());
                fs::create_dir_all(&src)?;
            }

            let summary = src.join("SUMMARY.md");

            if !summary.exists() {
                // Summary does not exist, create it
                debug!("[*]: {:?} does not exist, trying to create SUMMARY.md",
                       &summary);
                let mut f = File::create(&summary)?;

                debug!("[*]: Writing to SUMMARY.md");

                writeln!(f, "# Summary")?;
                writeln!(f, "")?;
                writeln!(f, "- [Chapter 1](./chapter_1.md)")?;
            }
        }

        // parse SUMMARY.md, and create the missing item related file
        self.parse_summary()?;

        debug!("[*]: constructing paths for missing files");
        for item in self.iter() {
            debug!("[*]: item: {:?}", item);
            let ch = match *item {
                BookItem::Spacer => continue,
                BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) => ch,
            };
            if !ch.path.as_os_str().is_empty() {
                let path = self.get_source().join(&ch.path);

                if !path.exists() {
                    if !self.config.build.create_missing {
                        return Err(
                            format!("'{}' referenced from SUMMARY.md does not exist.", path.to_string_lossy()).into(),
                        );
                    }
                    debug!("[*]: {:?} does not exist, trying to create file", path);
                    ::std::fs::create_dir_all(path.parent().unwrap())?;
                    let mut f = File::create(path)?;

                    // debug!("[*]: Writing to {:?}", path);
                    writeln!(f, "# {}", ch.name)?;
                }
            }
        }

        debug!("[*]: init done");
        Ok(())
    }

    pub fn create_gitignore(&self) {
        let gitignore = self.get_gitignore();

        let destination = self.get_destination();

        // Check that the gitignore does not extist and that the destination path
        // begins with the root path
        // We assume tha if it does begin with the root path it is contained within.
        // This assumption
        // will not hold true for paths containing double dots to go back up e.g.
        // `root/../destination`
        if !gitignore.exists() && destination.starts_with(&self.root) {
            let relative = destination
                .strip_prefix(&self.root)
                .expect("Could not strip the root prefix, path is not relative to root")
                .to_str()
                .expect("Could not convert to &str");

            debug!("[*]: {:?} does not exist, trying to create .gitignore", gitignore);

            let mut f = File::create(&gitignore).expect("Could not create file.");

            debug!("[*]: Writing to .gitignore");

            writeln!(f, "/{}", relative).expect("Could not write to file.");
        }
    }

    /// The `build()` method is the one where everything happens.
    /// First it parses `SUMMARY.md` to construct the book's structure
    /// in the form of a `Vec<BookItem>` and then calls `render()`
    /// method of the current renderer.
    ///
    /// It is the renderer who generates all the output files.
    pub fn build(&mut self) -> Result<()> {
        debug!("[fn]: build");

        self.init()?;

        // Clean output directory
        utils::fs::remove_dir_content(&self.get_destination())?;

        self.renderer.render(self)
    }

    pub fn get_gitignore(&self) -> PathBuf {
        self.root.join(".gitignore")
    }

    pub fn copy_theme(&self) -> Result<()> {
        debug!("[fn]: copy_theme");

        let themedir = self.theme_dir();

        if !themedir.exists() {
            debug!("[*]: {:?} does not exist, trying to create directory",
                   themedir);
            fs::create_dir(&themedir)?;
        }

        // index.hbs
        let mut index = File::create(themedir.join("index.hbs"))?;
        index.write_all(theme::INDEX)?;

        // header.hbs
        let mut header = File::create(themedir.join("header.hbs"))?;
        header.write_all(theme::HEADER)?;

        // book.css
        let mut css = File::create(themedir.join("book.css"))?;
        css.write_all(theme::CSS)?;

        // favicon.png
        let mut favicon = File::create(themedir.join("favicon.png"))?;
        favicon.write_all(theme::FAVICON)?;

        // book.js
        let mut js = File::create(themedir.join("book.js"))?;
        js.write_all(theme::JS)?;

        // highlight.css
        let mut highlight_css = File::create(themedir.join("highlight.css"))?;
        highlight_css.write_all(theme::HIGHLIGHT_CSS)?;

        // highlight.js
        let mut highlight_js = File::create(themedir.join("highlight.js"))?;
        highlight_js.write_all(theme::HIGHLIGHT_JS)?;

        Ok(())
    }

    pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
        let path = self.get_destination().join(filename);

        utils::fs::create_file(&path)?.write_all(content)
                                      .map_err(|e| e.into())
    }

    /// Parses the `book.json` file (if it exists) to extract
    /// the configuration parameters.
    /// The `book.json` file should be in the root directory of the book.
    /// The root directory is the one specified when creating a new `MDBook`

    pub fn read_config(mut self) -> Result<Self> {
        let config_path = self.root.join("book.toml");
        debug!("[*] Loading the config from {}", config_path.display());
        self.config = Config::from_disk(&config_path)?;

        Ok(self)
    }

    /// You can change the default renderer to another one
    /// by using this method. The only requirement
    /// is for your renderer to implement the
    /// [Renderer trait](../../renderer/renderer/trait.Renderer.html)
    ///
    /// ```no_run
    /// extern crate mdbook;
    /// use mdbook::MDBook;
    /// use mdbook::renderer::HtmlHandlebars;
    ///
    /// # #[allow(unused_variables)]
    /// fn main() {
    ///     let book = MDBook::new("mybook")
    ///                         .set_renderer(Box::new(HtmlHandlebars::new()));
    ///
    /// // In this example we replace the default renderer
    /// // by the default renderer...
    /// // Don't forget to put your renderer in a Box
    /// }
    /// ```
    ///
    /// **note:** Don't forget to put your renderer in a `Box`
    /// before passing it to `set_renderer()`

    pub fn set_renderer(mut self, renderer: Box<Renderer>) -> Self {
        self.renderer = renderer;
        self
    }

    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        // read in the chapters
        self.parse_summary().chain_err(|| "Couldn't parse summary")?;
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();
        let temp_dir = TempDir::new("mdbook")?;
        for item in self.iter() {
            if let BookItem::Chapter(_, ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.get_source().join(&ch.path);
                    let base = path.parent()
                                   .ok_or_else(|| String::from("Invalid bookitem path!"))?;
                    let content = utils::fs::file_to_string(&path)?;
                    // Parse and expand links
                    let content = preprocess::links::replace_all(&content, base)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc").arg(&path)
                                                        .arg("--test")
                                                        .args(&library_args)
                                                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(),
                                                    output));
                    }
                }
            }
        }
        Ok(())
    }

    // Construct book
    fn parse_summary(&mut self) -> Result<()> {
        // When append becomes stable, use self.content.append() ...
        let summary = self.get_source().join("SUMMARY.md");
        self.content = parse::construct_bookitems(&summary)?;
        Ok(())
    }

    pub fn get_destination(&self) -> PathBuf {
        self.root.join(&self.config.build.build_dir)
    }

    pub fn get_source(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}
<commit_msg>Added a quick fix so if the config isn't found we use a default<commit_after>pub mod bookitem;

pub use self::bookitem::{BookItem, BookItems};

use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;

use {parse, theme, utils};
use renderer::{HtmlHandlebars, Renderer};
use preprocess;
use errors::*;

use config::Config;

pub struct MDBook {
    pub root: PathBuf,
    pub config: Config,

    pub content: Vec<BookItem>,
    renderer: Box<Renderer>,

    pub livereload: Option<String>,
}

impl MDBook {
    /// Create a new `MDBook` struct with root directory `root`
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// let book = MDBook::new("root_dir");
    /// # }
    /// ```
    ///
    /// In this example, `root_dir` will be the root directory of our book
    /// and is specified in function of the current working directory
    /// by using a relative path instead of an
    /// absolute path.
    ///
    /// Default directory paths:
    ///
    /// - source: `root/src`
    /// - output: `root/book`
    /// - theme: `root/theme`
    ///
    /// They can both be changed by using [`set_src()`](#method.set_src) and
    /// [`set_dest()`](#method.set_dest)

    pub fn new<P: Into<PathBuf>>(root: P) -> MDBook {
        let root = root.into();
        if !root.exists() || !root.is_dir() {
            warn!("{:?} No directory with that name", root);
        }

        MDBook {
            root: root,
            config: Config::default(),

            content: vec![],
            renderer: Box::new(HtmlHandlebars::new()),

            livereload: None,
        }
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::new("mybook");
    /// for item in book.iter() {
    ///     match item {
    ///         &BookItem::Chapter(ref section, ref chapter) => {},
    ///         &BookItem::Affix(ref chapter) => {},
    ///         &BookItem::Spacer => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```

    pub fn iter(&self) -> BookItems {
        BookItems {
            items: &self.content[..],
            current_index: 0,
            stack: Vec::new(),
        }
    }

    /// `init()` creates some boilerplate files and directories
    /// to get you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the paths given as source and output directories
    /// and adds a `SUMMARY.md` and a
    /// `chapter_1.md` to the source directory.

    pub fn init(&mut self) -> Result<()> {
        debug!("[fn]: init");

        if !self.root.exists() {
            fs::create_dir_all(&self.root).unwrap();
            info!("{:?} created", self.root.display());
        }

        {
            let dest = self.get_destination();
            if !dest.exists() {
                debug!("[*]: {} does not exist, trying to create directory", dest.display());
                fs::create_dir_all(dest)?;
            }

            let src = self.get_source();
            if !src.exists() {
                debug!("[*]: {} does not exist, trying to create directory", src.display());
                fs::create_dir_all(&src)?;
            }

            let summary = src.join("SUMMARY.md");

            if !summary.exists() {
                // Summary does not exist, create it
                debug!("[*]: {:?} does not exist, trying to create SUMMARY.md",
                       &summary);
                let mut f = File::create(&summary)?;

                debug!("[*]: Writing to SUMMARY.md");

                writeln!(f, "# Summary")?;
                writeln!(f, "")?;
                writeln!(f, "- [Chapter 1](./chapter_1.md)")?;
            }
        }

        // parse SUMMARY.md, and create the missing item related file
        self.parse_summary()?;

        debug!("[*]: constructing paths for missing files");
        for item in self.iter() {
            debug!("[*]: item: {:?}", item);
            let ch = match *item {
                BookItem::Spacer => continue,
                BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) => ch,
            };
            if !ch.path.as_os_str().is_empty() {
                let path = self.get_source().join(&ch.path);

                if !path.exists() {
                    if !self.config.build.create_missing {
                        return Err(
                            format!("'{}' referenced from SUMMARY.md does not exist.", path.to_string_lossy()).into(),
                        );
                    }
                    debug!("[*]: {:?} does not exist, trying to create file", path);
                    ::std::fs::create_dir_all(path.parent().unwrap())?;
                    let mut f = File::create(path)?;

                    // debug!("[*]: Writing to {:?}", path);
                    writeln!(f, "# {}", ch.name)?;
                }
            }
        }

        debug!("[*]: init done");
        Ok(())
    }

    pub fn create_gitignore(&self) {
        let gitignore = self.get_gitignore();

        let destination = self.get_destination();

        // Check that the gitignore does not extist and that the destination path
        // begins with the root path
        // We assume tha if it does begin with the root path it is contained within.
        // This assumption
        // will not hold true for paths containing double dots to go back up e.g.
        // `root/../destination`
        if !gitignore.exists() && destination.starts_with(&self.root) {
            let relative = destination
                .strip_prefix(&self.root)
                .expect("Could not strip the root prefix, path is not relative to root")
                .to_str()
                .expect("Could not convert to &str");

            debug!("[*]: {:?} does not exist, trying to create .gitignore", gitignore);

            let mut f = File::create(&gitignore).expect("Could not create file.");

            debug!("[*]: Writing to .gitignore");

            writeln!(f, "/{}", relative).expect("Could not write to file.");
        }
    }

    /// The `build()` method is the one where everything happens.
    /// First it parses `SUMMARY.md` to construct the book's structure
    /// in the form of a `Vec<BookItem>` and then calls `render()`
    /// method of the current renderer.
    ///
    /// It is the renderer who generates all the output files.
    pub fn build(&mut self) -> Result<()> {
        debug!("[fn]: build");

        self.init()?;

        // Clean output directory
        utils::fs::remove_dir_content(&self.get_destination())?;

        self.renderer.render(self)
    }

    pub fn get_gitignore(&self) -> PathBuf {
        self.root.join(".gitignore")
    }

    pub fn copy_theme(&self) -> Result<()> {
        debug!("[fn]: copy_theme");

        let themedir = self.theme_dir();

        if !themedir.exists() {
            debug!("[*]: {:?} does not exist, trying to create directory",
                   themedir);
            fs::create_dir(&themedir)?;
        }

        // index.hbs
        let mut index = File::create(themedir.join("index.hbs"))?;
        index.write_all(theme::INDEX)?;

        // header.hbs
        let mut header = File::create(themedir.join("header.hbs"))?;
        header.write_all(theme::HEADER)?;

        // book.css
        let mut css = File::create(themedir.join("book.css"))?;
        css.write_all(theme::CSS)?;

        // favicon.png
        let mut favicon = File::create(themedir.join("favicon.png"))?;
        favicon.write_all(theme::FAVICON)?;

        // book.js
        let mut js = File::create(themedir.join("book.js"))?;
        js.write_all(theme::JS)?;

        // highlight.css
        let mut highlight_css = File::create(themedir.join("highlight.css"))?;
        highlight_css.write_all(theme::HIGHLIGHT_CSS)?;

        // highlight.js
        let mut highlight_js = File::create(themedir.join("highlight.js"))?;
        highlight_js.write_all(theme::HIGHLIGHT_JS)?;

        Ok(())
    }

    pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
        let path = self.get_destination().join(filename);

        utils::fs::create_file(&path)?.write_all(content)
                                      .map_err(|e| e.into())
    }

    /// Parses the `book.json` file (if it exists) to extract
    /// the configuration parameters.
    /// The `book.json` file should be in the root directory of the book.
    /// The root directory is the one specified when creating a new `MDBook`

    pub fn read_config(mut self) -> Result<Self> {
        let config_path = self.root.join("book.toml");

        if config_path.exists() {
            debug!("[*] Loading the config from {}", config_path.display());
            self.config = Config::from_disk(&config_path)?;
        } else {
            self.config = Config::default();
        }

        Ok(self)
    }

    /// You can change the default renderer to another one
    /// by using this method. The only requirement
    /// is for your renderer to implement the
    /// [Renderer trait](../../renderer/renderer/trait.Renderer.html)
    ///
    /// ```no_run
    /// extern crate mdbook;
    /// use mdbook::MDBook;
    /// use mdbook::renderer::HtmlHandlebars;
    ///
    /// # #[allow(unused_variables)]
    /// fn main() {
    ///     let book = MDBook::new("mybook")
    ///                         .set_renderer(Box::new(HtmlHandlebars::new()));
    ///
    /// // In this example we replace the default renderer
    /// // by the default renderer...
    /// // Don't forget to put your renderer in a Box
    /// }
    /// ```
    ///
    /// **note:** Don't forget to put your renderer in a `Box`
    /// before passing it to `set_renderer()`

    pub fn set_renderer(mut self, renderer: Box<Renderer>) -> Self {
        self.renderer = renderer;
        self
    }

    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        // read in the chapters
        self.parse_summary().chain_err(|| "Couldn't parse summary")?;
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();
        let temp_dir = TempDir::new("mdbook")?;
        for item in self.iter() {
            if let BookItem::Chapter(_, ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.get_source().join(&ch.path);
                    let base = path.parent()
                                   .ok_or_else(|| String::from("Invalid bookitem path!"))?;
                    let content = utils::fs::file_to_string(&path)?;
                    // Parse and expand links
                    let content = preprocess::links::replace_all(&content, base)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc").arg(&path)
                                                        .arg("--test")
                                                        .args(&library_args)
                                                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(),
                                                    output));
                    }
                }
            }
        }
        Ok(())
    }

    // Construct book
    fn parse_summary(&mut self) -> Result<()> {
        // When append becomes stable, use self.content.append() ...
        let summary = self.get_source().join("SUMMARY.md");
        self.content = parse::construct_bookitems(&summary)?;
        Ok(())
    }

    pub fn get_destination(&self) -> PathBuf {
        self.root.join(&self.config.build.build_dir)
    }

    pub fn get_source(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}
<|endoftext|>


<commit_before>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

extern crate collections;

use collections::dlist::DList;
use collections::Deque;

use std::cmp;
use std::mem;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.slice_mut(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct Chain {
    head: DList<Box<Node>>,
    length: uint
}

impl Chain {
    pub fn new() -> Chain {
        return Chain{
            head: DList::new(),
            length: 0
        }
    }

    pub fn len(&self) -> uint {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    pub fn append_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let node = Node::new(DataHolder::new(nsize)); // Box<Node>
            self.add_node_tail(node);
        }
        // infailable: added node above
        let node = self.head.back_mut().unwrap();
        node.append_from(data, 0, size);
        self.length += size;
    }

    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let mut node = Node::new(DataHolder::new(nsize)); // Box<Node>
            let r = node.room();
            node.start = r;
            node.end = r;
            self.add_node_head(node);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        node.prepend_from(data, 0, size);
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > self.len() {
            return None
        }
        // could not fail, because self.size() > 0 => has node
        if self.head.front().unwrap().size() >= size {
            let node = self.head.front().unwrap();
            return Some(node.data_range(node.start, node.start + size));
        }

        let mut newn = Node::new(DataHolder::new(size));
        let mut msize = size;
        while msize > 0 {
            {
                let node = self.head.front_mut().unwrap();
                let csize = cmp::min(node.size(), size);
                newn.append_from(node.data(), node.start, csize);

                if node.size() > size {
                    node.start += size;
                    self.length -= size;
                    break
                }
            }
            // infailable
            let n = self.head.pop_front().unwrap();
            msize -= n.size();
            // XXX: free node?
        }
        self.add_node_head(newn);
        // Now first node.size >= size, so we recurse
        return self.pullup(size)
    }

    pub fn concat(&mut self, src: Chain) {
        self.length += src.length;
        self.head.append(src.head);
        // No need to cleanup `src`, because it has moved and cannot be used
    }

    // TODO: maybe we do not need this method?
    // TODO: `concat` better express move semantics
    // XXX: to delete...
    pub fn concat_ptr(&mut self, src: &mut Chain) {
        self.length += src.length;
        let sh = mem::replace(&mut src.head, DList::new());
        self.head.append(sh);
        src.length = 0;
    }

    // XXX: private
    fn add_node_tail(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push(node);
    }

    fn add_node_head(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push_front(node);
    }
}

/// Node of chain buffer.
/// Owned by Chain.
struct Node {
    dh: Box<DataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl Node {
    fn new(dh: Box<DataHolder>) -> Box<Node> {
        let n = box Node {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    fn size(&self) -> uint {
        self.end - self.start
    }

    fn room(&self) -> uint {
        self.dh.size - self.end
    }

    fn data(&self) -> &[u8] {
        self.dh.data.as_slice()
    }

    fn data_range(&self, start:uint, end:uint) -> &[u8] {
        self.data().slice(start, end)
    }

    fn mut_data(&mut self) -> &mut [u8] {
        self.dh.data.as_mut_slice()
    }

    fn append_from(&mut self, data: &[u8], offs: uint, size: uint) {
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let e = self.end;
        blit(data, offs,
             self.mut_data(), e,
             size);
        self.end += size
    }

    fn prepend_from(&mut self, data: &[u8], offs: uint, size: uint) {
        let s = self.start;
        blit(data, offs,
             self.mut_data(), s - size,
             size);
        self.start -= size;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct DataHolder{
    size: uint,
    data: Vec<u8>
}

impl DataHolder {
    fn new(size: uint) -> Box<DataHolder> {
        let dh = box DataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

#[cfg(test)]
mod test {
    use super::Chain;
    use std::rand::{task_rng, Rng};

    #[test]
    fn test_append_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld";
        let ls = s.len();
        chain.append_bytes(s.as_bytes());
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_prepend_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.prepend_bytes(s);
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_pullup_return_none_on_empty_chain() {
        let mut chain = Chain::new();
        assert_eq!(chain.pullup(1), None);
    }

    #[test]
    fn test_pullup_return_what_has_been_appended() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let res = chain.pullup(ls);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), s);
    }

    #[test]
    fn test_pullup_does_not_change_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let olds = chain.len();
        chain.pullup(ls / 2);
        assert_eq!(chain.len(), olds);
    }

    #[test]
    fn test_pullup_works_on_large_sequences() {
        let mut chain = Chain::new();
        let total = 2048u;
        let mut t = total;
        let one_seq = 128u;
        let mut buf = Vec::new();
        while t > 0 {
            let s:String = task_rng().gen_ascii_chars().take(one_seq).collect();
            let b = s.as_bytes();
            buf = buf.append(b);
            chain.append_bytes(b);
            t -= one_seq;
        }
        let ret = chain.pullup(total);
        assert!(ret.is_some());
        assert_eq!(ret.unwrap(), buf.as_slice());
    }

    #[test]
    fn test_concat_increase_dst_length() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain1.append_bytes("HelloWorld".as_bytes());
        let l1 = chain1.len();
        chain2.append_bytes("HelloWorld".as_bytes());
        let l2 = chain2.len();
        chain1.concat(chain2);
        assert_eq!(chain1.len(), l1+l2);
    }

    #[test]
    fn test_concat_appends_content() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        let b = "HelloWorld".as_bytes();
        let bl = b.len();
        chain2.append_bytes(b);
        chain1.concat(chain2);
        let res = chain1.pullup(bl);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), b);
    }

    // XXX: do not need to test it for `concat`, because it is done for us
    // XXX: by type-system.
    #[test]
    fn test_concat_ptr_destroy_src() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain2.append_bytes("HelloWorld".as_bytes());
        chain1.concat_ptr(&mut chain2);
        assert_eq!(chain2.len(), 0);
    }

}
<commit_msg>[add] from_foreign; reset<commit_after>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

extern crate collections;

use collections::dlist::DList;
use collections::Deque;

use std::cmp;
use std::mem;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.slice_mut(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct Chain {
    head: DList<Box<Node>>,
    length: uint
}

impl Chain {
    pub fn new() -> Chain {
        return Chain{
            head: DList::new(),
            length: 0
        }
    }

    pub fn from_foreign(src: Chain) -> Chain {
        let mut ch = Chain::new();
        ch.concat(src);
        ch
    }

    pub fn len(&self) -> uint {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    pub fn append_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let node = Node::new(DataHolder::new(nsize)); // Box<Node>
            self.add_node_tail(node);
        }
        // infailable: added node above
        let node = self.head.back_mut().unwrap();
        node.append_from(data, 0, size);
        self.length += size;
    }

    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            let nsize = if size < CHB_MIN_SIZE { size << 1 } else { size };
            let mut node = Node::new(DataHolder::new(nsize)); // Box<Node>
            let r = node.room();
            node.start = r;
            node.end = r;
            self.add_node_head(node);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        node.prepend_from(data, 0, size);
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > self.len() {
            return None
        }
        // could not fail, because self.size() > 0 => has node
        if self.head.front().unwrap().size() >= size {
            let node = self.head.front().unwrap();
            return Some(node.data_range(node.start, node.start + size));
        }

        let mut newn = Node::new(DataHolder::new(size));
        let mut msize = size;
        while msize > 0 {
            {
                let node = self.head.front_mut().unwrap();
                let csize = cmp::min(node.size(), size);
                newn.append_from(node.data(), node.start, csize);

                if node.size() > size {
                    node.start += size;
                    self.length -= size;
                    break
                }
            }
            // infailable
            let n = self.head.pop_front().unwrap();
            msize -= n.size();
            // XXX: free node?
        }
        self.add_node_head(newn);
        // Now first node.size >= size, so we recurse
        return self.pullup(size)
    }

    pub fn concat(&mut self, src: Chain) {
        self.length += src.length;
        self.head.append(src.head);
        // No need to cleanup `src`, because it has moved and cannot be used
    }

    // XXX: chb_drop; `drop` is the sole method of built-in Drop trait,
    // so use another name
    pub fn reset(&mut self) {
        self.head = DList::new();
        self.length = 0;
    }

    // XXX: deprecated & experimental

    // TODO: maybe we do not need this method?
    // TODO: `concat` better express move semantics
    // XXX: to delete...
    pub fn concat_ptr(&mut self, src: &mut Chain) {
        self.length += src.length;
        let sh = mem::replace(&mut src.head, DList::new());
        self.head.append(sh);
        src.length = 0;
    }

    // XXX: private
    fn add_node_tail(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push(node);
    }

    fn add_node_head(&mut self, node: Box<Node>) {
        self.length += node.size();
        self.head.push_front(node);
    }
}

/// Node of chain buffer.
/// Owned by Chain.
struct Node {
    dh: Box<DataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl Node {
    fn new(dh: Box<DataHolder>) -> Box<Node> {
        let n = box Node {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    fn size(&self) -> uint {
        self.end - self.start
    }

    fn room(&self) -> uint {
        self.dh.size - self.end
    }

    fn data(&self) -> &[u8] {
        self.dh.data.as_slice()
    }

    fn data_range(&self, start:uint, end:uint) -> &[u8] {
        self.data().slice(start, end)
    }

    fn mut_data(&mut self) -> &mut [u8] {
        self.dh.data.as_mut_slice()
    }

    fn append_from(&mut self, data: &[u8], offs: uint, size: uint) {
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let e = self.end;
        blit(data, offs,
             self.mut_data(), e,
             size);
        self.end += size
    }

    fn prepend_from(&mut self, data: &[u8], offs: uint, size: uint) {
        let s = self.start;
        blit(data, offs,
             self.mut_data(), s - size,
             size);
        self.start -= size;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct DataHolder{
    size: uint,
    data: Vec<u8>
}

impl DataHolder {
    fn new(size: uint) -> Box<DataHolder> {
        let dh = box DataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

#[cfg(test)]
mod test {
    use super::Chain;
    use std::rand::{task_rng, Rng};

    #[test]
    fn test_append_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld";
        let ls = s.len();
        chain.append_bytes(s.as_bytes());
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_prepend_bytes_changes_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.prepend_bytes(s);
        assert_eq!(chain.len(), ls);
    }

    #[test]
    fn test_from_foreign_moves_all_data() {
        let mut orig = Chain::new();
        orig.append_bytes("HelloWorld".as_bytes());
        let sz = orig.len();
        let new = Chain::from_foreign(orig);
        assert_eq!(new.len(), sz);
    }

    #[test]
    fn test_pullup_return_none_on_empty_chain() {
        let mut chain = Chain::new();
        assert!(chain.pullup(1).is_none());
    }

    #[test]
    fn test_pullup_return_what_has_been_appended() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let res = chain.pullup(ls);
        assert!(res.is_some());
        assert_eq!(res.unwrap(), s);
    }

    #[test]
    fn test_pullup_does_not_change_length() {
        let mut chain = Chain::new();
        let s = "HelloWorld".as_bytes();
        let ls = s.len();
        chain.append_bytes(s);
        let olds = chain.len();
        chain.pullup(ls / 2);
        assert_eq!(chain.len(), olds);
    }

    #[test]
    fn test_pullup_works_on_large_sequences() {
        let mut chain = Chain::new();
        let total = 2048u;
        let mut t = total;
        let one_seq = 128u;
        let mut buf = Vec::new();
        while t > 0 {
            let s:String = task_rng().gen_ascii_chars().take(one_seq).collect();
            let b = s.as_bytes();
            buf = buf.append(b);
            chain.append_bytes(b);
            t -= one_seq;
        }
        let ret = chain.pullup(total);
        assert!(ret.is_some());
        assert_eq!(ret.unwrap(), buf.as_slice());
    }

    #[test]
    fn test_concat_increase_dst_length() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain1.append_bytes("HelloWorld".as_bytes());
        let l1 = chain1.len();
        chain2.append_bytes("HelloWorld".as_bytes());
        let l2 = chain2.len();
        chain1.concat(chain2);
        assert_eq!(chain1.len(), l1+l2);
    }

    #[test]
    fn test_concat_appends_content() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        let b = "HelloWorld".as_bytes();
        let bl = b.len();
        chain2.append_bytes(b);
        chain1.concat(chain2);
        let res = chain1.pullup(bl);

        assert!(res.is_some());
        assert_eq!(res.unwrap(), b);
    }

    #[test]
    fn test_reset_empties_chain() {
        let mut chain = Chain::new();
        chain.append_bytes("HelloWorld".as_bytes());
        chain.reset();
        assert!(chain.pullup(1).is_none());
        assert_eq!(chain.len(), 0);
    }

    // XXX: do not need to test it for `concat`, because it is done for us
    // XXX: by type-system.
    #[test]
    fn test_concat_ptr_destroy_src() {
        let mut chain1 = Chain::new();
        let mut chain2 = Chain::new();
        chain2.append_bytes("HelloWorld".as_bytes());
        chain1.concat_ptr(&mut chain2);
        assert_eq!(chain2.len(), 0);
    }

}
<|endoftext|>


<commit_before>//! Types and functions dealing with positions within the source code
//!

use std::ops::{Add, Sub};
use std::cmp::{min, max};

// Helps implementing basic operators, like `Add` and `Sub`
macro_rules! impl_math {
    ($ty_name:ident, $trait_name:ident, $fun_name:ident) => {
        impl $trait_name for $ty_name {
            type Output = $ty_name;

            fn $fun_name(self, rhs: $ty_name) -> $ty_name {
                $ty_name($trait_name::$fun_name(self.0, rhs.0))
            }
        }
    }
}

// ----------------------------------------------------------------------------
/// Type do index one byte in a source code. It should be rather small, since
/// it's used a lot.
pub type SrcOffset = u32;

/// Position within source specified by byte offset. This is not equal to
/// `CharPos` thanks to UTF-8 and multibyte chars. This type always represents
/// positions relative to the whole codemap.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct BytePos(pub SrcOffset);

impl_math!(BytePos, Add, add);
impl_math!(BytePos, Sub, sub);

// ----------------------------------------------------------------------------
/// A region within the source specified by first and last byte offset. `lo`
/// byte is included in the span, `hi` byte is excluded.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Span {
    pub lo: BytePos,
    pub hi: BytePos,
}

impl Span {
    /// Creates a span that points to a single char
    pub fn single(pos: BytePos) -> Span {
        Span { lo: pos, hi: pos + BytePos(1) }
    }

    /// Creates a span from a lo and hi (shorter than struct constructor
    /// syntax)
    pub fn new(lo: BytePos, hi: BytePos) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a span from a tuple
    pub fn from_pair((lo, hi): (BytePos, BytePos)) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a dummy span. Should be used with caution.
    pub fn dummy() -> Span {
        Span { lo: BytePos(1), hi: BytePos(0) }
    }

    /// Checks if the this span is a dummy span
    pub fn is_dummy(&self) -> bool {
        self.lo.0 == 1 && self.hi.0 == 0
    }

    /// Returns the length (number of bytes) of the span or 0 if it's a dummy
    /// span
    pub fn len(&self) -> SrcOffset {
        if self.is_dummy() {
            0
        } else {
            (self.hi - self.lo).0
        }
    }

    /// Returns the smallest span which encloses both given spans
    ///
    /// If one of given spans is a dummy span, it is ignored and the other span
    /// is returned. If both spans are dummy spans, a dummy span is returned.
    pub fn hull(&self, other: &Self) -> Span {
        if self.is_dummy() {
            *other
        } else if other.is_dummy() {
            *self
        } else {
            Span {
                lo: min(self.lo, other.lo),
                hi: max(self.hi, other.hi),
            }
        }
    }

    /// Checks if this span contains another span. A dummy span never contains
    /// any other span (always returns `false`).
    pub fn contains(&self, other: Self) -> bool {
        !self.is_dummy() && self.lo <= other.lo && self.hi >= other.hi
    }
}

// ----------------------------------------------------------------------------
/// Represents a line index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct LineIdx(pub SrcOffset);

impl ::std::fmt::Display for LineIdx {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        (self.0 + 1).fmt(f)
    }
}

/// Represents a column index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct ColIdx(pub SrcOffset);

impl_math!(LineIdx, Add, add);
impl_math!(LineIdx, Sub, sub);
impl_math!(ColIdx, Add, add);
impl_math!(ColIdx, Sub, sub);

/// Location within one file specified by line and column.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Loc {
    pub line: LineIdx,
    pub col: ColIdx,
}
<commit_msg>Add `Span` field documentation<commit_after>//! Types and functions dealing with positions within the source code
//!

use std::ops::{Add, Sub};
use std::cmp::{min, max};

// Helps implementing basic operators, like `Add` and `Sub`
macro_rules! impl_math {
    ($ty_name:ident, $trait_name:ident, $fun_name:ident) => {
        impl $trait_name for $ty_name {
            type Output = $ty_name;

            fn $fun_name(self, rhs: $ty_name) -> $ty_name {
                $ty_name($trait_name::$fun_name(self.0, rhs.0))
            }
        }
    }
}

// ----------------------------------------------------------------------------
/// Type do index one byte in a source code. It should be rather small, since
/// it's used a lot.
pub type SrcOffset = u32;

/// Position within source specified by byte offset. This is not equal to
/// `CharPos` thanks to UTF-8 and multibyte chars. This type always represents
/// positions relative to the whole codemap.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct BytePos(pub SrcOffset);

impl_math!(BytePos, Add, add);
impl_math!(BytePos, Sub, sub);

// ----------------------------------------------------------------------------
/// A region within the source specified by first and last byte offset. `lo`
/// byte is included in the span, `hi` byte is excluded.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Span {
    /// Low byte, inclusive
    pub lo: BytePos,
    /// High byte, exclusive
    pub hi: BytePos,
}

impl Span {
    /// Creates a span that points to a single char
    pub fn single(pos: BytePos) -> Span {
        Span { lo: pos, hi: pos + BytePos(1) }
    }

    /// Creates a span from a lo and hi (shorter than struct constructor
    /// syntax)
    pub fn new(lo: BytePos, hi: BytePos) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a span from a tuple
    pub fn from_pair((lo, hi): (BytePos, BytePos)) -> Span {
        Span { lo: lo, hi: hi }
    }

    /// Creates a dummy span. Should be used with caution.
    pub fn dummy() -> Span {
        Span { lo: BytePos(1), hi: BytePos(0) }
    }

    /// Checks if the this span is a dummy span
    pub fn is_dummy(&self) -> bool {
        self.lo.0 == 1 && self.hi.0 == 0
    }

    /// Returns the length (number of bytes) of the span or 0 if it's a dummy
    /// span
    pub fn len(&self) -> SrcOffset {
        if self.is_dummy() {
            0
        } else {
            (self.hi - self.lo).0
        }
    }

    /// Returns the smallest span which encloses both given spans
    ///
    /// If one of given spans is a dummy span, it is ignored and the other span
    /// is returned. If both spans are dummy spans, a dummy span is returned.
    pub fn hull(&self, other: &Self) -> Span {
        if self.is_dummy() {
            *other
        } else if other.is_dummy() {
            *self
        } else {
            Span {
                lo: min(self.lo, other.lo),
                hi: max(self.hi, other.hi),
            }
        }
    }

    /// Checks if this span contains another span. A dummy span never contains
    /// any other span (always returns `false`).
    pub fn contains(&self, other: Self) -> bool {
        !self.is_dummy() && self.lo <= other.lo && self.hi >= other.hi
    }
}

// ----------------------------------------------------------------------------
/// Represents a line index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct LineIdx(pub SrcOffset);

impl ::std::fmt::Display for LineIdx {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        (self.0 + 1).fmt(f)
    }
}

/// Represents a column index.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct ColIdx(pub SrcOffset);

impl_math!(LineIdx, Add, add);
impl_math!(LineIdx, Sub, sub);
impl_math!(ColIdx, Add, add);
impl_math!(ColIdx, Sub, sub);

/// Location within one file specified by line and column.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Loc {
    pub line: LineIdx,
    pub col: ColIdx,
}
<|endoftext|>


<commit_before>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::collections::BTreeMap;
use std::fmt;
use std::sync::{Arc, Mutex};

use config;
use webhooks;

include!("logger_macros.rs");

////////////////////////////////////////////////////////////
//                         Command                        //
////////////////////////////////////////////////////////////

//                            Config,                             Raw webhook,            Arguments
pub type CommandCallback = fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>;

pub struct Command {
    pub requires_please: bool,
    pub whitelist_only:  bool,
    pub callback:        CommandCallback
}

impl Command {
    pub fn new(requires_please: bool, whitelist_only: bool, callback: CommandCallback) -> Command {
        Command{
            requires_please: requires_please,
            whitelist_only:  whitelist_only,
            callback:        callback
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Command {{requires_please: {}, whitelist_only: {}, callback: fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>}}", self.requires_please, self.whitelist_only)
    }
}

////////////////////////////////////////////////////////////
//                     CommandHandler                     //
////////////////////////////////////////////////////////////

#[derive(Debug)]
pub struct CommandHandler {
    config:   Arc<Mutex<config::ConfigHandler>>,
    commands: BTreeMap<String, Command>
}

impl CommandHandler {

    pub fn new(tsconfig: &Arc<Mutex<config::ConfigHandler>>) -> CommandHandler {

        thread_trace!("commands.rs: CommandHandler::new(tsconfig)");

        //Register commands
        let mut commands: BTreeMap<String, Command> = BTreeMap::new();
        commands.insert(String::from("ping"), Command::new(false, false, ping));

        CommandHandler {
            config:   tsconfig.clone(),
            commands: commands
        }
    }

    pub fn parse_command(&self, webhook: webhooks::WebhookEvent) {

        thread_trace!("commands.rs: CommandHandler::parse_command(&self, webhook)");

        let mut tokens: Vec<&str>   = webhook.command.split_whitespace().collect();
        let mut is_please_provided  = false;
        let mut is_user_whitelisted = false;
        let mut next_token_index    = 0;
        let mut bot_name            = String::new();

        thread_debug!("Command tokens: {:?}", tokens);

        //Check if please was said
        if tokens[0].to_lowercase() == "please" {
            is_please_provided = true;
            next_token_index   = 1;
        }
        thread_debug!("Please was said: {}", is_please_provided);

        //Check if user is whitelisted for restricted commands
        //  Restricted scope, we are using the config here but
        //  the callback can also use it so we force the mutex
        //  to unlock before letting the callback lock it
        //  given that locking twice will induce a panic.
        {
            let mut config      = self.config.lock().unwrap();
            is_user_whitelisted = config.whitelist_validate_user(webhook.clone().user);
            bot_name            = config.get_string_required("config", "github_bot_name");
        }

        //Ignore commands/responses from the bot
        thread_trace!("Check if command is from bot.");
        if bot_name == webhook.user {
            thread_trace!("Command is from bot, return.");
            return;
        }

        //Find command among registered commands
        thread_trace!("Check if command exists.");
        thread_debug!("Looking for command: {}", tokens[next_token_index]);
        let command = match self.commands.get(tokens[next_token_index]) {
            Some(command) => {
                thread_trace!("Command exists.");
                command
            },
            None          => {
                thread_trace!("Command does not exists, send response.");
                respond(&self.config, webhook.clone(), String::from("Sorry the command was not found."));
                return;
            }
        };

        //Check if please and whitelist is required
        let mut run_cmd         = false;
        let mut response_prefix = String::new();

        thread_trace!("Check for whitelist and please.");
        thread_debug!("is_please_provided:  {}", is_please_provided);
        thread_debug!("is_user_whitelisted: {}", is_user_whitelisted);

        if !(command.whitelist_only && !is_user_whitelisted) {
            if (command.requires_please && is_please_provided) || (!command.requires_please && !is_please_provided) {
                run_cmd = true;
            } else if !command.requires_please && is_please_provided {
                run_cmd         = true;
                response_prefix = String::from("You didn't need to say please but thanks anyways :smiley: \\r\\n\\r\\nOhh and: \\r\\n");
            } else if command.requires_please && !is_please_provided {
                //TODO: keep please state
                respond(&self.config, webhook.clone(), String::from("Whats the magic word?"));
            }
        } else {
            respond(&self.config, webhook.clone(), String::from("Sorry! That command if for whitelisted people only!"));
        }

        thread_debug!("run_cmd: {}", run_cmd);

        if run_cmd {
            match (command.callback)(&self.config, webhook.clone(), tokens.split_off(next_token_index)) {
                Ok(msg)  => {
                    respond(&self.config, webhook.clone(), format!("{}{}", response_prefix, msg));
                }
                Err(msg) => {
                    respond(&self.config, webhook.clone(), format!("An error occurred while executing the command: {}", msg));
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////
//                        Callbacks                       //
////////////////////////////////////////////////////////////

#[allow(unused_variables)]
pub fn ping(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, args: Vec<&str>) -> Result<String, String> {
    return Ok(String::from("Pong"))
}

////////////////////////////////////////////////////////////
//                          Utils                         //
////////////////////////////////////////////////////////////

pub fn respond(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, msg: String) {

    thread_trace!("commands.rs: respond(tsconfig, raw_event, msg)");

    //TODO: Don't forget to change this when refactoring config
    //Get repo were following
    let github_follow_repo: String;
    let github_owner_token: String;
    {
        let mut config = tsconfig.lock().unwrap();
        github_follow_repo = config.get_string_required("config", "github_follow_repo");
        github_owner_token = config.get_string_required("config", "github_bot_token");
    }

    let endpoint = format!("repos/{}/issues/{}/comments?access_token={}", github_follow_repo, raw_event.number, github_owner_token);
    let message  = format!("{{\"body\": \"@{} {}\"}}", raw_event.user, msg);
    match webhooks::github_post_request(endpoint, message) {
        Ok(())   => (),
        Err(err) => {thread_error!("{}", err);}
    }
}
<commit_msg>Added help command and renamed a variable to reflect past changes.<commit_after>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::collections::BTreeMap;
use std::fmt;
use std::sync::{Arc, Mutex};

use config;
use webhooks;

include!("logger_macros.rs");

////////////////////////////////////////////////////////////
//                         Command                        //
////////////////////////////////////////////////////////////

//                            Config,                             Raw webhook,            Arguments
pub type CommandCallback = fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>;

pub struct Command {
    pub requires_please: bool,
    pub whitelist_only:  bool,
    pub callback:        CommandCallback
}

impl Command {
    pub fn new(requires_please: bool, whitelist_only: bool, callback: CommandCallback) -> Command {
        Command{
            requires_please: requires_please,
            whitelist_only:  whitelist_only,
            callback:        callback
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Command {{requires_please: {}, whitelist_only: {}, callback: fn(&Arc<Mutex<config::ConfigHandler>>, webhooks::WebhookEvent, Vec<&str>) -> Result<String, String>}}", self.requires_please, self.whitelist_only)
    }
}

////////////////////////////////////////////////////////////
//                     CommandHandler                     //
////////////////////////////////////////////////////////////

#[derive(Debug)]
pub struct CommandHandler {
    config:   Arc<Mutex<config::ConfigHandler>>,
    commands: BTreeMap<String, Command>
}

impl CommandHandler {

    pub fn new(tsconfig: &Arc<Mutex<config::ConfigHandler>>) -> CommandHandler {

        thread_trace!("commands.rs: CommandHandler::new(tsconfig)");

        //Register commands
        let mut commands: BTreeMap<String, Command> = BTreeMap::new();
        commands.insert(String::from("ping"), Command::new(false, false, ping));
        commands.insert(String::from("help"), Command::new(false, false, help));

        CommandHandler {
            config:   tsconfig.clone(),
            commands: commands
        }
    }

    pub fn parse_command(&self, webhook: webhooks::WebhookEvent) {

        thread_trace!("commands.rs: CommandHandler::parse_command(&self, webhook)");

        let mut tokens: Vec<&str>   = webhook.command.split_whitespace().collect();
        let mut is_please_provided  = false;
        let mut is_user_whitelisted = false;
        let mut next_token_index    = 0;
        let mut bot_name            = String::new();

        thread_debug!("Command tokens: {:?}", tokens);

        //Check if please was said
        if tokens[0].to_lowercase() == "please" {
            is_please_provided = true;
            next_token_index   = 1;
        }
        thread_debug!("Please was said: {}", is_please_provided);

        //Check if user is whitelisted for restricted commands
        //  Restricted scope, we are using the config here but
        //  the callback can also use it so we force the mutex
        //  to unlock before letting the callback lock it
        //  given that locking twice will induce a panic.
        {
            let mut config      = self.config.lock().unwrap();
            is_user_whitelisted = config.whitelist_validate_user(webhook.clone().user);
            bot_name            = config.get_string_required("config", "github_bot_name");
        }

        //Ignore commands/responses from the bot
        thread_trace!("Check if command is from bot.");
        if bot_name == webhook.user {
            thread_trace!("Command is from bot, return.");
            return;
        }

        //Find command among registered commands
        thread_trace!("Check if command exists.");
        thread_debug!("Looking for command: {}", tokens[next_token_index]);
        let command = match self.commands.get(tokens[next_token_index]) {
            Some(command) => {
                thread_trace!("Command exists.");
                command
            },
            None          => {
                thread_trace!("Command does not exists, send response.");
                respond(&self.config, webhook.clone(), String::from("Sorry the command was not found. Please visit [https://hunterbot.readthedocs.io](https://hunterbot.readthedocs.io) for available commands."));
                return;
            }
        };

        //Check if please and whitelist is required
        let mut run_cmd         = false;
        let mut response_prefix = String::new();

        thread_trace!("Check for whitelist and please.");
        thread_debug!("is_please_provided:  {}", is_please_provided);
        thread_debug!("is_user_whitelisted: {}", is_user_whitelisted);

        if !(command.whitelist_only && !is_user_whitelisted) {
            if (command.requires_please && is_please_provided) || (!command.requires_please && !is_please_provided) {
                run_cmd = true;
            } else if !command.requires_please && is_please_provided {
                run_cmd         = true;
                response_prefix = String::from("You didn't need to say please but thanks anyways :smiley: \\r\\n\\r\\nOhh and: \\r\\n");
            } else if command.requires_please && !is_please_provided {
                //TODO: keep please state
                respond(&self.config, webhook.clone(), String::from("Whats the magic word?"));
            }
        } else {
            respond(&self.config, webhook.clone(), String::from("Sorry! That command if for whitelisted people only!"));
        }

        thread_debug!("run_cmd: {}", run_cmd);

        if run_cmd {
            match (command.callback)(&self.config, webhook.clone(), tokens.split_off(next_token_index)) {
                Ok(msg)  => {
                    respond(&self.config, webhook.clone(), format!("{}{}", response_prefix, msg));
                }
                Err(msg) => {
                    respond(&self.config, webhook.clone(), format!("An error occurred while executing the command: {}", msg));
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////
//                        Callbacks                       //
////////////////////////////////////////////////////////////

#[allow(unused_variables)]
pub fn ping(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, args: Vec<&str>) -> Result<String, String> {
    return Ok(String::from("Pong"))
}

#[allow(unused_variables)]
pub fn help(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, args: Vec<&str>) -> Result<String, String> {
    return Ok(String::from("Documentation related to the bot including available commands are at [https://hunterbot.readthedocs.io](https://hunterbot.readthedocs.io)"))
}

////////////////////////////////////////////////////////////
//                          Utils                         //
////////////////////////////////////////////////////////////

pub fn respond(tsconfig: &Arc<Mutex<config::ConfigHandler>>, raw_event: webhooks::WebhookEvent, msg: String) {

    thread_trace!("commands.rs: respond(tsconfig, raw_event, msg)");

    //TODO: Don't forget to change this when refactoring config
    //Get repo were following
    let github_follow_repo: String;
    let github_bot_token: String;
    {
        let mut config = tsconfig.lock().unwrap();
        github_follow_repo = config.get_string_required("config", "github_follow_repo");
        github_bot_token = config.get_string_required("config", "github_bot_token");
    }

    let endpoint = format!("repos/{}/issues/{}/comments?access_token={}", github_follow_repo, raw_event.number, github_bot_token);
    let message  = format!("{{\"body\": \"@{} {}\"}}", raw_event.user, msg);
    match webhooks::github_post_request(endpoint, message) {
        Ok(())   => (),
        Err(err) => {thread_error!("{}", err);}
    }
}
<|endoftext|>


<commit_before>pub const SPLITTED_POSITION: f32 = 0.5;<commit_msg>The ultimate answer added<commit_after>pub const SPLITTED_POSITION: f32 = 0.5;
pub const THE_ULTIMATE_ANSWER_TO_EVERYTHING: u16 = 42;<|endoftext|>