<commit_before>use crate::config::Config;
use crate::error::{Error, ErrorKind, ExpectedNumberOfArgs, Result};
use crate::git::Git;
use std::fmt;
use std::fs;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DiffOp {
    TwoDots,   // '..'
    ThreeDots, // '...'
}

impl fmt::Display for DiffOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DiffOp::TwoDots => write!(f, ".."),
            DiffOp::ThreeDots => write!(f, "..."),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Line {
    At(usize),
    Range(usize, usize), // start and end
}

#[derive(Debug, PartialEq)]
pub enum Page {
    Open {
        website: bool,
        pull_request: bool,
    },
    Diff {
        lhs: String,
        rhs: String,
        op: DiffOp, // '...' or '..'
    },
    Commit {
        hash: String,
    },
    FilePath {
        relative_path: String,
        hash: String,
        line: Option<Line>,
        blame: bool,
        is_dir: bool,
    },
    Issue {
        number: usize,
    },
    Tag {
        tagname: String,
        commit: String,
    },
}

struct BrowsePageParser<'a> {
    cfg: &'a Config,
    git: Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn shorten_hash(&self, mut hash: String) -> String {
        if self.cfg.env.short_commit_hash {
            hash.truncate(7);
        }
        hash
    }

    fn wrong_number_of_args(&self, expected: ExpectedNumberOfArgs, kind: &str) -> Result<Page> {
        Error::err(ErrorKind::WrongNumberOfArgs {
            expected,
            actual: self.cfg.args.len(),
            kind: kind.to_string(),
        })
    }

    fn try_parse_commit(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "commit")
        } else {
            let hash = self.git.hash(&self.cfg.args[0])?;
            Ok(Page::Commit {
                hash: self.shorten_hash(hash),
            })
        }
    }

    fn try_parse_tag(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "tag name")
        } else {
            let hash = self.git.tag_hash(&self.cfg.args[0])?;
            Ok(Page::Tag {
                tagname: self.cfg.args[0].clone(),
                commit: self.shorten_hash(hash),
            })
        }
    }

    fn try_parse_diff(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "diff");
        }

        let arg = &self.cfg.args[0];
        let dots = if arg.contains("...") {
            "..."
        } else if arg.contains("..") {
            ".."
        } else {
            return Error::err(ErrorKind::DiffDotsNotFound);
        };

        let mut split = arg.splitn(2, dots);
        let lhs = split.next().unwrap();
        let rhs = split.next().unwrap();

        if lhs.is_empty() || rhs.is_empty() {
            return Error::err(ErrorKind::DiffHandIsEmpty {
                input: arg.to_string(),
            });
        }

        let lhs = self.git.hash(&lhs)?;
        let rhs = self.git.hash(&rhs)?;
        Ok(Page::Diff {
            lhs: self.shorten_hash(lhs),
            rhs: self.shorten_hash(rhs),
            op: if dots == ".." {
                DiffOp::TwoDots
            } else {
                DiffOp::ThreeDots
            },
        })
    }

    fn parse_path_and_line(&self) -> (&str, Option<Line>) {
        let arg = &self.cfg.args[0];

        let line_start = match arg.find('#') {
            Some(i) => i,
            None => return (arg.as_str(), None),
        };

        let mut idx = line_start;
        if arg.chars().nth(idx + 1) == Some('L') {
            // Skip 'L' of file#L123
            idx += 1;
        }

        let path = &arg[..line_start];
        let line_spec = &arg[idx + 1..];
        if let Some(mut dash_idx) = line_spec.find('-') {
            let start = (&line_spec[..dash_idx]).parse().ok();

            if line_spec.chars().nth(dash_idx + 1) == Some('L') {
                // Skip second 'L' of file#L123-L345
                dash_idx += 1;
            }
            let end = (&line_spec[dash_idx + 1..]).parse().ok();

            (
                path,
                start.map(|s| match end {
                    Some(e) => Line::Range(s, e),
                    None => Line::At(s),
                }),
            )
        } else {
            let line = line_spec.parse().ok();
            (path, line.map(Line::At))
        }
    }

    fn try_parse_file_or_dir(&self) -> Result<Page> {
        let len = self.cfg.args.len();
        if len != 1 && len != 2 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Range(1, 2), "file path");
        }

        let (path, line) = self.parse_path_and_line();
        let path = fs::canonicalize(path)?;
        let is_dir = path.is_dir();

        if is_dir {
            if self.cfg.blame {
                return Error::err(ErrorKind::CannotBlameDirectory {
                    dir: path.to_string_lossy().into(),
                });
            }
            if line.is_some() {
                return Error::err(ErrorKind::LineSpecifiedForDir(path));
            }
        }

        let repo_root = self.git.root_dir()?;
        let relative_path = path
            .strip_prefix(&repo_root)
            .map_err(|_| {
                Error::new(ErrorKind::FileDirNotInRepo {
                    repo_root: repo_root.to_owned(),
                    path: path.clone(),
                })
            })?
            .to_str()
            .expect("Failed to convert path into UTF-8 string")
            .to_string();

        let mut hash = if len == 2 {
            self.git.hash(self.cfg.args[1].as_str())?
        } else {
            self.git.hash("HEAD")?
        };

        // Fall back into branch name when the commit is not existing in remote branch (#12)
        //
        // Ignore this check when the local branch does not point to any remote branch
        let remote_contains_hash = match self.git.remote_branch(&self.cfg.remote, &self.cfg.branch)
        {
            Ok(remote_branch) => self.git.remote_contains(&hash, &remote_branch)?,
            Err(_) => true, // Ignore check
        };
        if !remote_contains_hash {
            hash = match &self.cfg.branch {
                Some(b) => b.clone(),
                None => self.git.current_branch()?,
            };
        } else {
            // Use full-length hash for Git::remote_contains()
            hash = self.shorten_hash(hash);
        };

        Ok(Page::FilePath {
            relative_path,
            hash,
            line,
            blame: self.cfg.blame,
            is_dir,
        })
    }

    fn try_parse_issue_number(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "issue number");
        }

        let arg = &self.cfg.args[0];
        if !arg.starts_with('#') {
            return Error::err(ErrorKind::InvalidIssueNumberFormat);
        }
        let arg = &arg[1..];
        let number: usize = arg
            .parse()
            .map_err(|_| Error::new(ErrorKind::InvalidIssueNumberFormat))?;
        Ok(Page::Issue { number })
    }
}

pub fn parse_page(cfg: &Config) -> Result<Page> {
    let mut attempts = Vec::with_capacity(5);

    // Note: Ignore any arguments when opening a website
    if cfg.args.is_empty() || cfg.website || cfg.pull_request {
        if cfg.blame {
            return Error::err(ErrorKind::BlameWithoutFilePath);
        }

        return Ok(Page::Open {
            website: cfg.website,
            pull_request: cfg.pull_request,
        });
    }

    let parser = BrowsePageParser {
        cfg,
        git: cfg.git(),
    };

    match parser.try_parse_issue_number() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Issue number", *e)),
    }

    // Note: Early return for --blame
    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        Err(err) => match err.kind() {
            ErrorKind::CannotBlameDirectory { .. } => return Err(err),
            _ if cfg.blame => return Error::err(ErrorKind::BlameWithoutFilePath),
            _ => attempts.push(("File path", *err)),
        },
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Diff", *e)),
    }

    match parser.try_parse_tag() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Tag", *e)),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Commit", *e)),
    }

    Error::err(ErrorKind::PageParseError {
        args: cfg.args.clone(),
        attempts,
    })
}
<commit_msg>fix clippy warnings<commit_after>use crate::config::Config;
use crate::error::{Error, ErrorKind, ExpectedNumberOfArgs, Result};
use crate::git::Git;
use std::fmt;
use std::fs;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DiffOp {
    TwoDots,   // '..'
    ThreeDots, // '...'
}

impl fmt::Display for DiffOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DiffOp::TwoDots => write!(f, ".."),
            DiffOp::ThreeDots => write!(f, "..."),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Line {
    At(usize),
    Range(usize, usize), // start and end
}

#[derive(Debug, PartialEq)]
pub enum Page {
    Open {
        website: bool,
        pull_request: bool,
    },
    Diff {
        lhs: String,
        rhs: String,
        op: DiffOp, // '...' or '..'
    },
    Commit {
        hash: String,
    },
    FilePath {
        relative_path: String,
        hash: String,
        line: Option<Line>,
        blame: bool,
        is_dir: bool,
    },
    Issue {
        number: usize,
    },
    Tag {
        tagname: String,
        commit: String,
    },
}

struct BrowsePageParser<'a> {
    cfg: &'a Config,
    git: Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn shorten_hash(&self, mut hash: String) -> String {
        if self.cfg.env.short_commit_hash {
            hash.truncate(7);
        }
        hash
    }

    fn wrong_number_of_args(&self, expected: ExpectedNumberOfArgs, kind: &str) -> Result<Page> {
        Error::err(ErrorKind::WrongNumberOfArgs {
            expected,
            actual: self.cfg.args.len(),
            kind: kind.to_string(),
        })
    }

    fn try_parse_commit(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "commit")
        } else {
            let hash = self.git.hash(&self.cfg.args[0])?;
            Ok(Page::Commit {
                hash: self.shorten_hash(hash),
            })
        }
    }

    fn try_parse_tag(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "tag name")
        } else {
            let hash = self.git.tag_hash(&self.cfg.args[0])?;
            Ok(Page::Tag {
                tagname: self.cfg.args[0].clone(),
                commit: self.shorten_hash(hash),
            })
        }
    }

    fn try_parse_diff(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "diff");
        }

        let arg = &self.cfg.args[0];
        let dots = if arg.contains("...") {
            "..."
        } else if arg.contains("..") {
            ".."
        } else {
            return Error::err(ErrorKind::DiffDotsNotFound);
        };

        let (lhs, rhs) = arg.split_once(dots).unwrap();

        if lhs.is_empty() || rhs.is_empty() {
            return Error::err(ErrorKind::DiffHandIsEmpty {
                input: arg.to_string(),
            });
        }

        let lhs = self.git.hash(&lhs)?;
        let rhs = self.git.hash(&rhs)?;
        Ok(Page::Diff {
            lhs: self.shorten_hash(lhs),
            rhs: self.shorten_hash(rhs),
            op: if dots == ".." {
                DiffOp::TwoDots
            } else {
                DiffOp::ThreeDots
            },
        })
    }

    fn parse_path_and_line(&self) -> (&str, Option<Line>) {
        let arg = &self.cfg.args[0];

        let line_start = match arg.find('#') {
            Some(i) => i,
            None => return (arg.as_str(), None),
        };

        let mut idx = line_start;
        if arg.chars().nth(idx + 1) == Some('L') {
            // Skip 'L' of file#L123
            idx += 1;
        }

        let path = &arg[..line_start];
        let line_spec = &arg[idx + 1..];
        if let Some(mut dash_idx) = line_spec.find('-') {
            let start = (&line_spec[..dash_idx]).parse().ok();

            if line_spec.chars().nth(dash_idx + 1) == Some('L') {
                // Skip second 'L' of file#L123-L345
                dash_idx += 1;
            }
            let end = (&line_spec[dash_idx + 1..]).parse().ok();

            (
                path,
                start.map(|s| match end {
                    Some(e) => Line::Range(s, e),
                    None => Line::At(s),
                }),
            )
        } else {
            let line = line_spec.parse().ok();
            (path, line.map(Line::At))
        }
    }

    fn try_parse_file_or_dir(&self) -> Result<Page> {
        let len = self.cfg.args.len();
        if len != 1 && len != 2 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Range(1, 2), "file path");
        }

        let (path, line) = self.parse_path_and_line();
        let path = fs::canonicalize(path)?;
        let is_dir = path.is_dir();

        if is_dir {
            if self.cfg.blame {
                return Error::err(ErrorKind::CannotBlameDirectory {
                    dir: path.to_string_lossy().into(),
                });
            }
            if line.is_some() {
                return Error::err(ErrorKind::LineSpecifiedForDir(path));
            }
        }

        let repo_root = self.git.root_dir()?;
        let relative_path = path
            .strip_prefix(&repo_root)
            .map_err(|_| {
                Error::new(ErrorKind::FileDirNotInRepo {
                    repo_root: repo_root.to_owned(),
                    path: path.clone(),
                })
            })?
            .to_str()
            .expect("Failed to convert path into UTF-8 string")
            .to_string();

        let mut hash = if len == 2 {
            self.git.hash(self.cfg.args[1].as_str())?
        } else {
            self.git.hash("HEAD")?
        };

        // Fall back into branch name when the commit is not existing in remote branch (#12)
        //
        // Ignore this check when the local branch does not point to any remote branch
        let remote_contains_hash = match self.git.remote_branch(&self.cfg.remote, &self.cfg.branch)
        {
            Ok(remote_branch) => self.git.remote_contains(&hash, &remote_branch)?,
            Err(_) => true, // Ignore check
        };
        if !remote_contains_hash {
            hash = match &self.cfg.branch {
                Some(b) => b.clone(),
                None => self.git.current_branch()?,
            };
        } else {
            // Use full-length hash for Git::remote_contains()
            hash = self.shorten_hash(hash);
        };

        Ok(Page::FilePath {
            relative_path,
            hash,
            line,
            blame: self.cfg.blame,
            is_dir,
        })
    }

    fn try_parse_issue_number(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "issue number");
        }

        let arg = &self.cfg.args[0];
        if !arg.starts_with('#') {
            return Error::err(ErrorKind::InvalidIssueNumberFormat);
        }
        let arg = &arg[1..];
        let number: usize = arg
            .parse()
            .map_err(|_| Error::new(ErrorKind::InvalidIssueNumberFormat))?;
        Ok(Page::Issue { number })
    }
}

pub fn parse_page(cfg: &Config) -> Result<Page> {
    let mut attempts = Vec::with_capacity(5);

    // Note: Ignore any arguments when opening a website
    if cfg.args.is_empty() || cfg.website || cfg.pull_request {
        if cfg.blame {
            return Error::err(ErrorKind::BlameWithoutFilePath);
        }

        return Ok(Page::Open {
            website: cfg.website,
            pull_request: cfg.pull_request,
        });
    }

    let parser = BrowsePageParser {
        cfg,
        git: cfg.git(),
    };

    match parser.try_parse_issue_number() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Issue number", *e)),
    }

    // Note: Early return for --blame
    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        Err(err) => match err.kind() {
            ErrorKind::CannotBlameDirectory { .. } => return Err(err),
            _ if cfg.blame => return Error::err(ErrorKind::BlameWithoutFilePath),
            _ => attempts.push(("File path", *err)),
        },
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Diff", *e)),
    }

    match parser.try_parse_tag() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Tag", *e)),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Commit", *e)),
    }

    Error::err(ErrorKind::PageParseError {
        args: cfg.args.clone(),
        attempts,
    })
}
<|endoftext|>


<commit_before>use render::{RenderContext, RenderError, Directive};
use registry::Registry;

pub use self::inline::INLINE_DIRECTIVE;

/// Directive Definition
///
/// Implement this trait to define your own decorators or directives
pub trait DirectiveDef: Send + Sync {
    fn call(&self, d: &Directive, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError>;
}

/// implement DirectiveDef for bare function so we can use function as directive
impl<F: Send + Sync + for<'b, 'c, 'd, 'e> Fn(&'b Directive, &'c Registry, &'d mut RenderContext) -> Result<(), RenderError>> DirectiveDef for F {
    fn call(&self, d: &Directive, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError>{
        (*self)(d, r, rc)
    }
}

mod inline;
<commit_msg>(test) added tests for decorators<commit_after>use render::{RenderContext, RenderError, Directive};
use registry::Registry;

pub use self::inline::INLINE_DIRECTIVE;

/// Directive Definition
///
/// Implement this trait to define your own decorators or directives
pub trait DirectiveDef: Send + Sync {
    fn call(&self, d: &Directive, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError>;
}

/// implement DirectiveDef for bare function so we can use function as directive
impl<F: Send + Sync + for<'b, 'c, 'd, 'e> Fn(&'b Directive, &'c Registry, &'d mut RenderContext) -> Result<(), RenderError>> DirectiveDef for F {
    fn call(&self, d: &Directive, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError>{
        (*self)(d, r, rc)
    }
}

mod inline;

#[cfg(test)]
mod test {
    use registry::Registry;
    use context::{as_string, Context};
    use render::{RenderContext, RenderError, Directive, Helper};

    // default feature, using rustc_serialize `Json` as data type
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use serialize::json::ToJson;
    // serde_type feature, using serde_json as data type
    #[cfg(feature = "serde_type")]
    use serde_json::value::ToJson;

    #[test]
    fn test_register_decorator() {
        let mut handlebars = Registry::new();
        handlebars.register_template_string("t0", "{{*foo}}".to_string()).unwrap();

        let data = btreemap! {
            "hello".to_string() => "world".to_string()
        };

        assert!(handlebars.render("t0", &data).is_err());

        handlebars.register_decorator("foo",
                                      Box::new(|_: &Directive,
                                                _: &Registry,
                                                _: &mut RenderContext|
                                                -> Result<(), RenderError> {
                                          Ok(())
                                      }));
        assert_eq!(handlebars.render("t0", &data).ok().unwrap(), "".to_string());
    }

    #[test]
    fn test_update_data_with_decorator() {
        let mut handlebars = Registry::new();
        handlebars.register_template_string("t0", "{{hello}}{{*foo}}{{hello}}".to_string())
                  .unwrap();

        let data = btreemap! {
            "hello".to_string() => "world".to_string()
        };

        handlebars.register_decorator("foo",
                                      Box::new(|_: &Directive,
                                                _: &Registry,
                                                rc: &mut RenderContext|
                                                -> Result<(), RenderError> {
                                          // modify json object
                                          let mut ctx_ref = rc.context_mut();
                                          if let Some(ref mut m) = ctx_ref.data_mut()
                                                                          .as_object_mut()
                                                                          .as_mut() {
                                              m.insert("hello".to_string(),
                                                       "war".to_owned().to_json());
                                          }
                                          Ok(())
                                      }));

        assert_eq!(handlebars.render("t0", &data).ok().unwrap(),
                   "worldwar".to_string());

        let data2 = 0;
        handlebars.register_decorator("bar",
                                      Box::new(|d: &Directive,
                                                _: &Registry,
                                                rc: &mut RenderContext|
                                                -> Result<(), RenderError> {
                                          // modify value
                                          let v = d.param(0)
                                                   .map(|v| Context::wraps(v.value()))
                                                   .unwrap_or(Context::null());
                                          *rc.context_mut() = v;
                                          Ok(())
                                      }));
        handlebars.register_template_string("t1", "{{this}}{{*bar 1}}{{this}}".to_string())
                  .unwrap();
        assert_eq!(handlebars.render("t1", &data2).ok().unwrap(),
                   "01".to_string());

        handlebars.register_template_string("t2",
                                            "{{this}}{{*bar \"string_literal\"}}{{this}}"
                                                .to_string())
                  .unwrap();
        assert_eq!(handlebars.render("t2", &data2).ok().unwrap(),
                   "0string_literal".to_string());

        handlebars.register_template_string("t3", "{{this}}{{*bar}}{{this}}".to_string())
                  .unwrap();
        assert_eq!(handlebars.render("t3", &data2).ok().unwrap(),
                   "0".to_string());
    }

    #[test]
    fn test_local_helper_with_decorator() {
        let mut handlebars = Registry::new();
        handlebars.register_template_string("t0",
                                            "{{distance 4.5}},{{*foo \"miles\"}}{{distance 10.1}},{{*bar}}{{distance 3.4}}"
                                                .to_string())
                  .unwrap();

        handlebars.register_helper("distance",
                                   Box::new(|h: &Helper,
                                             _: &Registry,
                                             rc: &mut RenderContext|
                                             -> Result<(), RenderError> {
                                       let s = format!("{}m",
                                                       h.param(0)
                                                        .map(|v| v.value())
                                                        .unwrap_or(&0.to_json()));
                                       try!(rc.writer().write(s.into_bytes().as_ref()));
                                       Ok(())
                                   }));
        handlebars.register_decorator("foo",
                                      Box::new(|d: &Directive,
                                                _: &Registry,
                                                rc: &mut RenderContext|
                                                -> Result<(), RenderError> {
                                          let new_unit = d.param(0)
                                                          .and_then(|v| as_string(v.value()))
                                                          .unwrap_or("")
                                                          .to_owned();
                                          let new_helper = move |h: &Helper,
                                                                 _: &Registry,
                                                                 rc: &mut RenderContext|
                                                                 -> Result<(), RenderError> {
                                              let s = format!("{}{}",
                                                              h.param(0)
                                                               .map(|v| v.value())
                                                               .unwrap_or(&0.to_json()),
                                                              new_unit);
                                              try!(rc.writer().write(s.into_bytes().as_ref()));
                                              Ok(())
                                          };

                                          rc.register_local_helper("distance",
                                                                   Box::new(new_helper));
                                          Ok(())
                                      }));
        handlebars.register_decorator("bar",
                                      Box::new(|_: &Directive,
                                                _: &Registry,
                                                rc: &mut RenderContext|
                                                -> Result<(), RenderError> {
                                          rc.unregister_local_helper("distance");
                                          Ok(())
                                      }));
        assert_eq!(handlebars.render("t0", &0).ok().unwrap(),
                   "4.5m,10.1miles,3.4m".to_owned());
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use self::rand::Rng;
use std::collections::HashSet;

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Point(pub i32, pub i32);

impl Point {
    pub fn new_with_xy(x: i32, y: i32) -> Point {
        Point(x, y)
    }
}

#[derive(Debug)]
pub enum GameOver {
    Win(&'static str),
    Lose(&'static str),
}

#[derive(Debug, PartialEq)]
pub enum BodyDirection {
    Left,
    Right,
}

#[derive(Debug)]
pub struct SpaceInvaders {
    pub head: Point,
    pub body: HashSet<Point>,
    pub bullets: HashSet<Point>,
    pub eggs: HashSet<Point>,
    pub body_direction: BodyDirection,
    pub max_x: u16,
    pub max_y: u16,
    pub max_bullets: u16,
    pub count_bullets: u16,
    pub paused: bool,
}

impl SpaceInvaders {
    pub fn new_with_bounds(max_x: u16, max_y: u16) -> SpaceInvaders {
        SpaceInvaders {
            head: Point::new_with_xy((max_x / 2) as i32, (max_y - 1) as i32),
            body: Self::init_body(20, 60),
            bullets: HashSet::new(),
            eggs: HashSet::new(),
            body_direction: BodyDirection::Right,
            max_x: max_x,
            max_y: max_y,
            max_bullets: 200,
            count_bullets: 0,
            paused: true,
        }
    }

    pub fn set_max_bullets(&mut self, max: u16) {
        self.max_bullets = max;
    }

    pub fn gen_egg(&mut self) {
        let index = rand::thread_rng().gen_range(0, self.body.len());
        let mut count = 0;
        for i in self.body.iter() {
            if count == index {
                self.eggs.insert(Point(i.0, 1));
                break;
            }
            count += 1;
        }
    }

    pub fn move_on(&mut self) -> Result<&'static str, GameOver> {
        self.del_body();
        self.del_eggs();

        self.new_body();
        self.new_bullets();
        self.del_eggs();
        self.new_eggs();

        if self.body.len() == 0 {
            Err(GameOver::Win("You win!!!\n"))
        } else if self.count_bullets >= self.max_bullets {
            Err(GameOver::Lose("You lose!!!\nNo bullets left...\n"))
        } else if self.eggs.contains(&self.head) {
            Err(GameOver::Lose("You lose!!!\nYou were shoot...\n"))
        }
        else {
            Ok("continue...")
        }
    }

    fn init_body(begin: u16, end: u16) -> HashSet<Point> {
        let mut body = HashSet::new();
        for i in begin..end {
            body.insert(Point(i as i32, 0));
        }
        body
    }

    fn new_body(&mut self) {
        let ra = rand::thread_rng().gen_range(1, 4);
        for _ in 0..ra {
            match self.body_direction {
                BodyDirection::Right => self.body_right(),
                BodyDirection::Left => self.body_left(),
            }
        }
    }

    fn body_right(&mut self) {
        let mut tmp_body = HashSet::new();
        for i in self.body.iter() {
            tmp_body.insert(Point(i.0 + 1, 0));
            if i.0 == ((self.max_x - 1) as i32) {
                self.body_direction = BodyDirection::Left;
            }
        }
        self.body = tmp_body;
    }

    fn body_left(&mut self) {
        let mut tmp_body = HashSet::new();
        for i in self.body.iter() {
            tmp_body.insert(Point(i.0 - 1, 0));
            if i.0 == 0 {
                self.body_direction = BodyDirection::Right;
            }
        }
        self.body = tmp_body;
    }

    fn new_bullets(&mut self) {
        let mut tmp_bullets = HashSet::new();
        {
            for i in self.bullets.iter() {
                if i.1 >= 0 {
                    let point = Point(i.0, i.1 - 1);
                    tmp_bullets.insert(point);
                }
            }
        }
        self.bullets = tmp_bullets;
    }

    fn new_eggs(&mut self) {
        let mut tmp_eggs = HashSet::new();
        {
            for i in self.eggs.iter() {
                if i.1 < (self.max_y as i32) {
                    let point = Point(i.0, i.1 + 1);
                    tmp_eggs.insert(point);
                }
            }
        }
        self.eggs = tmp_eggs;
    }

    pub fn shoot(&mut self) {
        self.bullets.insert(Point(self.head.0, self.head.1 -1));
        self.count_bullets += 1;
    }

    fn del_body(&mut self) {
        self.body = self.body.difference(&self.bullets).cloned().collect::<HashSet<_>>();
    }

    fn del_eggs(&mut self) {
        let tmp_eggs = self.eggs.clone();
        let tmp_bullets = self.bullets.clone();

        self.eggs = tmp_eggs.difference(&tmp_bullets).cloned().collect::<HashSet<_>>();
        self.bullets = tmp_bullets.difference(&tmp_eggs).cloned().collect::<HashSet<_>>();
    }
}
<commit_msg>modify src/space_invaders i32 yo i35<commit_after>extern crate rand;

use self::rand::Rng;
use std::collections::HashSet;

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Point(pub i32, pub i35);

impl Point {
    pub fn new_with_xy(x: i32, y: i32) -> Point {
        Point(x, y)
    }
}

#[derive(Debug)]
pub enum GameOver {
    Win(&'static str),
    Lose(&'static str),
}

#[derive(Debug, PartialEq)]
pub enum BodyDirection {
    Left,
    Right,
}

#[derive(Debug)]
pub struct SpaceInvaders {
    pub head: Point,
    pub body: HashSet<Point>,
    pub bullets: HashSet<Point>,
    pub eggs: HashSet<Point>,
    pub body_direction: BodyDirection,
    pub max_x: u16,
    pub max_y: u16,
    pub max_bullets: u16,
    pub count_bullets: u16,
    pub paused: bool,
}

impl SpaceInvaders {
    pub fn new_with_bounds(max_x: u16, max_y: u16) -> SpaceInvaders {
        SpaceInvaders {
            head: Point::new_with_xy((max_x / 2) as i32, (max_y - 1) as i32),
            body: Self::init_body(20, 60),
            bullets: HashSet::new(),
            eggs: HashSet::new(),
            body_direction: BodyDirection::Right,
            max_x: max_x,
            max_y: max_y,
            max_bullets: 200,
            count_bullets: 0,
            paused: true,
        }
    }

    pub fn set_max_bullets(&mut self, max: u16) {
        self.max_bullets = max;
    }

    pub fn gen_egg(&mut self) {
        let index = rand::thread_rng().gen_range(0, self.body.len());
        let mut count = 0;
        for i in self.body.iter() {
            if count == index {
                self.eggs.insert(Point(i.0, 1));
                break;
            }
            count += 1;
        }
    }

    pub fn move_on(&mut self) -> Result<&'static str, GameOver> {
        self.del_body();
        self.del_eggs();

        self.new_body();
        self.new_bullets();
        self.del_eggs();
        self.new_eggs();

        if self.body.len() == 0 {
            Err(GameOver::Win("You win!!!\n"))
        } else if self.count_bullets >= self.max_bullets {
            Err(GameOver::Lose("You lose!!!\nNo bullets left...\n"))
        } else if self.eggs.contains(&self.head) {
            Err(GameOver::Lose("You lose!!!\nYou were shoot...\n"))
        }
        else {
            Ok("continue...")
        }
    }

    fn init_body(begin: u16, end: u16) -> HashSet<Point> {
        let mut body = HashSet::new();
        for i in begin..end {
            body.insert(Point(i as i32, 0));
        }
        body
    }

    fn new_body(&mut self) {
        let ra = rand::thread_rng().gen_range(1, 4);
        for _ in 0..ra {
            match self.body_direction {
                BodyDirection::Right => self.body_right(),
                BodyDirection::Left => self.body_left(),
            }
        }
    }

    fn body_right(&mut self) {
        let mut tmp_body = HashSet::new();
        for i in self.body.iter() {
            tmp_body.insert(Point(i.0 + 1, 0));
            if i.0 == ((self.max_x - 1) as i32) {
                self.body_direction = BodyDirection::Left;
            }
        }
        self.body = tmp_body;
    }

    fn body_left(&mut self) {
        let mut tmp_body = HashSet::new();
        for i in self.body.iter() {
            tmp_body.insert(Point(i.0 - 1, 0));
            if i.0 == 0 {
                self.body_direction = BodyDirection::Right;
            }
        }
        self.body = tmp_body;
    }

    fn new_bullets(&mut self) {
        let mut tmp_bullets = HashSet::new();
        {
            for i in self.bullets.iter() {
                if i.1 >= 0 {
                    let point = Point(i.0, i.1 - 1);
                    tmp_bullets.insert(point);
                }
            }
        }
        self.bullets = tmp_bullets;
    }

    fn new_eggs(&mut self) {
        let mut tmp_eggs = HashSet::new();
        {
            for i in self.eggs.iter() {
                if i.1 < (self.max_y as i32) {
                    let point = Point(i.0, i.1 + 1);
                    tmp_eggs.insert(point);
                }
            }
        }
        self.eggs = tmp_eggs;
    }

    pub fn shoot(&mut self) {
        self.bullets.insert(Point(self.head.0, self.head.1 -1));
        self.count_bullets += 1;
    }

    fn del_body(&mut self) {
        self.body = self.body.difference(&self.bullets).cloned().collect::<HashSet<_>>();
    }

    fn del_eggs(&mut self) {
        let tmp_eggs = self.eggs.clone();
        let tmp_bullets = self.bullets.clone();

        self.eggs = tmp_eggs.difference(&tmp_bullets).cloned().collect::<HashSet<_>>();
        self.bullets = tmp_bullets.difference(&tmp_eggs).cloned().collect::<HashSet<_>>();
    }
}
<|endoftext|>


<commit_before>
use std::ops::{Index, IndexMut};
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: String,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new(key: &str) -> Pair {
        Pair {
            key: key.to_owned(),
            value: vec![]
        }
    }

    pub fn new_string(key: String) -> Pair {
        Pair {
            key: key,
            value: vec![]
        }
    }

    pub fn add(&mut self, val: &str) {
        self.add_pair(Pair::new(val));
    }

    pub fn add_string(&mut self, val: String) {
        self.add_pair(Pair::new_string(val));
    }

    pub fn add_pair(&mut self, pair: Pair) {
        if !self.value.contains(&pair) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    pub fn get_pair(&self, value: String) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get_pair_mut(&mut self, value: String) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get(&self) -> &String {
        if self.value.len() == 0 {
            panic!("No value associated with key");
        }
        &self.value[0].key
    }
}

impl<'a> Index<&'a str> for Pair {
    type Output = Pair;
    fn index(&self, value: &'a str) -> &Pair {
        self.get_pair(value.to_owned()).expect("Did not find value in pair")
    }
}

impl<'a> IndexMut<&'a str> for Pair {
    fn index_mut(&mut self, value: &'a str) -> &mut Pair {
        self.get_pair_mut(value.to_owned()).expect("Did not find value in pair")
    }
}

impl Deref for Pair {
    type Target = String;
    fn deref(&self) -> &String {
        &self.get()
    }
}

<commit_msg>whoops<commit_after>
use std::ops::{Index, IndexMut, Deref};
use error::Error;

// top level key that contains everything is __top_level__
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    pub key: String,
    pub value: Vec<Pair>
}

impl Pair {
    pub fn new(key: &str) -> Pair {
        Pair {
            key: key.to_owned(),
            value: vec![]
        }
    }

    pub fn new_string(key: String) -> Pair {
        Pair {
            key: key,
            value: vec![]
        }
    }

    pub fn add(&mut self, val: &str) {
        self.add_pair(Pair::new(val));
    }

    pub fn add_string(&mut self, val: String) {
        self.add_pair(Pair::new_string(val));
    }

    pub fn add_pair(&mut self, pair: Pair) {
        if !self.value.contains(&pair) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    pub fn get_pair(&self, value: String) -> Result<&Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get_pair_mut(&mut self, value: String) -> Result<&mut Pair, Error> {
        let mut p = None;
        for (k, v) in self.value.iter().enumerate() {
            if v.key == value {
                p = Some(k);
            }
        }
        if p.is_some() {
            Ok(&mut self.value[p.unwrap()])
        } else {
            Err(Error::KeyNotFound)
        }
    }

    pub fn get(&self) -> &String {
        if self.value.len() == 0 {
            panic!("No value associated with key");
        }
        &self.value[0].key
    }
}

impl<'a> Index<&'a str> for Pair {
    type Output = Pair;
    fn index(&self, value: &'a str) -> &Pair {
        self.get_pair(value.to_owned()).expect("Did not find value in pair")
    }
}

impl<'a> IndexMut<&'a str> for Pair {
    fn index_mut(&mut self, value: &'a str) -> &mut Pair {
        self.get_pair_mut(value.to_owned()).expect("Did not find value in pair")
    }
}

impl Deref for Pair {
    type Target = String;
    fn deref(&self) -> &String {
        &self.get()
    }
}

<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::collections::btree_set::Iter;
use std::iter::Iterator;
use super::entry::{Entry, Timestamp};

#[derive(Debug)]
pub struct Storage {
    entries: BTreeSet<Entry>,
}

impl Storage {
    pub fn new() -> Self {
        Storage { entries: BTreeSet::new() }
    }

    pub fn add_entry(&mut self, entry: Entry) {
        self.entries.insert(entry);
    }

    pub fn has_entry(&self, entry: &Entry) -> bool {
        self.entries.contains(entry)
    }

    pub fn remove_entry(&mut self, entry: &Entry) {
        self.entries.remove(entry);
    }

    pub fn expired_entries(&self) -> Vec<Entry> {
        let iter = ExpiredItems {
            iter: self.entries.iter(),
            timestamp: Timestamp::now(),
        };

        let mut entries = Vec::<Entry>::new();

        for entry in iter {
            entries.push(entry);
        }

        return entries;
    }
}

pub struct ExpiredItems<'a> {
    iter: Iter<'a, Entry>,
    timestamp: Timestamp,
}

impl<'a> Iterator for ExpiredItems<'a> {
    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        let entry = maybe!(self.iter.next());

        if self.timestamp <= entry.timestamp() {
            return None;
        }

        Some(*entry)
    }
}
<commit_msg>Make ExpiredItems iterator private<commit_after>use std::collections::BTreeSet;
use std::collections::btree_set::Iter;
use std::iter::Iterator;
use super::entry::{Entry, Timestamp};

#[derive(Debug)]
pub struct Storage {
    entries: BTreeSet<Entry>,
}

impl Storage {
    pub fn new() -> Self {
        Storage { entries: BTreeSet::new() }
    }

    pub fn add_entry(&mut self, entry: Entry) {
        self.entries.insert(entry);
    }

    pub fn has_entry(&self, entry: &Entry) -> bool {
        self.entries.contains(entry)
    }

    pub fn remove_entry(&mut self, entry: &Entry) {
        self.entries.remove(entry);
    }

    pub fn expired_entries(&self) -> Vec<Entry> {
        let iter = ExpiredItems {
            iter: self.entries.iter(),
            timestamp: Timestamp::now(),
        };

        let mut entries = Vec::<Entry>::new();

        for entry in iter {
            entries.push(entry);
        }

        return entries;
    }
}

struct ExpiredItems<'a> {
    iter: Iter<'a, Entry>,
    timestamp: Timestamp,
}

impl<'a> Iterator for ExpiredItems<'a> {
    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        let entry = maybe!(self.iter.next());

        if self.timestamp <= entry.timestamp() {
            return None;
        }

        Some(*entry)
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use ::token::parse_expressions;
use ::token::{Expression, Token, Multiplicity};

#[derive(PartialEq,Debug)]
pub struct Regex {
    pub pattern: String
}

impl Regex {
    pub fn from(pattern: &str) -> Regex {
        Regex {
            pattern: pattern.to_owned()
        }
    }

    pub fn is_match(&self, text: &str) -> bool {
        let expressions = parse_expressions(&self.pattern).unwrap();

        let mut regex_i = 0;
        let mut text_i = 0;

        while regex_i < expressions.len() {
            let mut options = Self::ways_to_grab_text(&text[text_i..], &expressions[regex_i]);

            if options.len() == 0 {
                text_i += 1;

                if text_i >= text.len() {
                    return false;
                }

                continue;
            }

            let chosen_option = options.pop().unwrap();

            text_i += chosen_option;
            regex_i += 1;
        }

        true
    }

    fn ways_to_grab_text(text: &str, expr: &Expression) -> Vec<usize> {
        let mut valid_offsets = Vec::<usize>::new();
        let mut valid_chars = Vec::new();
        let mut valid_multiplicity = Multiplicity {
            minimum: Some(1), maximum: Some(1)
        };

        match expr {
            &Expression::Token(ref token, ref multiplicity) => {
                valid_multiplicity = multiplicity.clone();
                match token {
                    &Token::Literal(ref value) => {
                        valid_chars.push(value.clone());
                    },
                    &Token::Class(ref values) => {
                        valid_chars.append(&mut values.clone());
                    }
                    _ => ()
                }
            },
            _ => ()
        }

        if valid_multiplicity.minimum == None || valid_multiplicity.minimum == Some(0) {
            valid_offsets.push(0); //it is an option to do nothing with this expr
        }

        let mut offset = 0;

        for c in text.chars() {
            if !valid_chars.contains(&c) {
                break;
            }

            offset += 1;

            match valid_multiplicity.minimum {
                Some(min) => {
                    if min < offset { continue; }
                },
                None => ()
            }

            match valid_multiplicity.maximum {
                Some(max) => {
                    if max > offset { continue; }
                },
                None => ()
            }

            valid_offsets.push(offset);
        }

        valid_offsets
    }

    pub fn first(&self, text: &str) -> Option<(usize, usize)> {
        if text.contains(&self.pattern) {
            Some((1, 2))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod regex_spec {
    use super::Regex;

    #[test]
    fn matches_simple_examples() {
        assert!(Regex::from("ab?c").is_match("zac"));
        assert!(Regex::from("ab?c").is_match("abbbc"));
        assert!(Regex::from("a?").is_match(""));
        assert!(Regex::from("a+").is_match("a"));
        assert!(Regex::from("ab+").is_match("abbbb"));
    }

    #[test]
    fn does_not_match() {
        assert!(!Regex::from("ab?c").is_match("z"));
        assert!(!Regex::from("a+").is_match(""));
        assert!(!Regex::from("ab+").is_match("bbbb"));
    }

    #[test]
    fn matches_character_class() {
        assert!(Regex::from("[abc]").is_match("a"));
        assert!(Regex::from("[abc]").is_match("b"));
        assert!(Regex::from("[abc]").is_match("c"));
        assert!(!Regex::from("[abc]").is_match("["));
        assert!(!Regex::from("[abc]").is_match("]"));
        assert!(!Regex::from("[abc]").is_match("z"));
    }

    #[test]
    fn backtracks_to_find_match() {
        assert!(Regex::from("[bc]?c").is_match("cb"));
        assert!(Regex::from("[bc]?c").is_match("cc"));
        assert!(Regex::from("[bc]?c").is_match("c"));
        assert!(!Regex::from("[bc]?c").is_match("b"));
    }

    #[test]
    fn matches_zero_or_more() {
        let regex = Regex::from("ab*");
        assert!(regex.is_match("abbbb"));
        assert!(regex.is_match("ab"));
        assert!(regex.is_match("a"));
        assert!(!regex.is_match("bb"));
    }
}
<commit_msg>get first match as a position tuple<commit_after>use std::str::FromStr;
use ::token::parse_expressions;
use ::token::{Expression, Token, Multiplicity};

#[derive(PartialEq,Debug)]
pub struct Regex {
    pub pattern: String
}

impl Regex {
    pub fn from(pattern: &str) -> Regex {
        Regex {
            pattern: pattern.to_owned()
        }
    }

    pub fn first(&self, text: &str) -> Option<(usize, usize)> {
        let expressions = parse_expressions(&self.pattern).unwrap();

        let mut regex_i = 0;
        let mut text_i = 0;
        let mut match_start = 0;

        while regex_i < expressions.len() {
            let mut options = Self::ways_to_grab_text(&text[text_i..], &expressions[regex_i]);

            if options.len() == 0 {
                text_i += 1;
                match_start = text_i;

                if text_i >= text.len() {
                    return None;
                }

                continue;
            }

            let chosen_option = options.pop().unwrap();

            text_i += chosen_option;
            regex_i += 1;
        }

        Some((match_start, text_i))
    }

    fn ways_to_grab_text(text: &str, expr: &Expression) -> Vec<usize> {
        let mut valid_offsets = Vec::<usize>::new();
        let mut valid_chars = Vec::new();
        let mut valid_multiplicity = Multiplicity {
            minimum: Some(1), maximum: Some(1)
        };

        match expr {
            &Expression::Token(ref token, ref multiplicity) => {
                valid_multiplicity = multiplicity.clone();
                match token {
                    &Token::Literal(ref value) => {
                        valid_chars.push(value.clone());
                    },
                    &Token::Class(ref values) => {
                        valid_chars.append(&mut values.clone());
                    }
                    _ => ()
                }
            },
            _ => ()
        }

        if valid_multiplicity.minimum == None || valid_multiplicity.minimum == Some(0) {
            valid_offsets.push(0); //it is an option to do nothing with this expr
        }

        let mut offset = 0;

        for c in text.chars() {
            if !valid_chars.contains(&c) {
                break;
            }

            offset += 1;

            match valid_multiplicity.minimum {
                Some(min) => {
                    if min < offset { continue; }
                },
                None => ()
            }

            match valid_multiplicity.maximum {
                Some(max) => {
                    if max > offset { continue; }
                },
                None => ()
            }

            valid_offsets.push(offset);
        }

        valid_offsets
    }

    pub fn is_match(&self, text: &str) -> bool {
        return self.first(text).is_some();
    }
}

#[cfg(test)]
mod regex_spec {
    use super::Regex;

    #[test]
    fn matches_simple_examples() {
        assert!(Regex::from("ab?c").is_match("zac"));
        assert!(Regex::from("ab?c").is_match("abbbc"));
        assert!(Regex::from("a?").is_match(""));
        assert!(Regex::from("a+").is_match("a"));
        assert!(Regex::from("ab+").is_match("abbbb"));
    }

    #[test]
    fn does_not_match() {
        assert!(!Regex::from("ab?c").is_match("z"));
        assert!(!Regex::from("a+").is_match(""));
        assert!(!Regex::from("ab+").is_match("bbbb"));
    }

    #[test]
    fn matches_character_class() {
        assert!(Regex::from("[abc]").is_match("a"));
        assert!(Regex::from("[abc]").is_match("b"));
        assert!(Regex::from("[abc]").is_match("c"));
        assert!(!Regex::from("[abc]").is_match("["));
        assert!(!Regex::from("[abc]").is_match("]"));
        assert!(!Regex::from("[abc]").is_match("z"));
    }

    #[test]
    fn backtracks_to_find_match() {
        assert!(Regex::from("[bc]?c").is_match("cb"));
        assert!(Regex::from("[bc]?c").is_match("cc"));
        assert!(Regex::from("[bc]?c").is_match("c"));
        assert!(!Regex::from("[bc]?c").is_match("b"));
    }

    #[test]
    fn matches_zero_or_more() {
        let regex = Regex::from("ab*");
        assert!(regex.is_match("abbbb"));
        assert!(regex.is_match("ab"));
        assert!(regex.is_match("a"));
        assert!(!regex.is_match("bb"));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.

use container::Container;
use default::Default;
use rand::{Rng, SeedableRng};

/// How many bytes of entropy the underling RNG is allowed to generate
/// before it is reseeded.
static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;

/// A wrapper around any RNG which reseeds the underlying RNG after it
/// has generated a certain number of random bytes.
pub struct ReseedingRng<R, Rsdr> {
    priv rng: R,
    priv generation_threshold: uint,
    priv bytes_generated: uint,
    /// Controls the behaviour when reseeding the RNG.
    reseeder: Rsdr
}

impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
    /// Create a new `ReseedingRng` with the given parameters.
    ///
    /// # Arguments
    ///
    /// * `rng`: the random number generator to use.
    /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
    /// * `reseeder`: the reseeding object to use.
    pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
        ReseedingRng {
            rng: rng,
            generation_threshold: generation_threshold,
            bytes_generated: 0,
            reseeder: reseeder
        }
    }

    /// Reseed the internal RNG if the number of bytes that have been
    /// generated exceed the threshold.
    pub fn reseed_if_necessary(&mut self) {
        if self.bytes_generated >= self.generation_threshold {
            self.reseeder.reseed(&mut self.rng);
            self.bytes_generated = 0;
        }
    }
}

impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
    fn next_u32(&mut self) -> u32 {
        self.reseed_if_necessary();
        self.bytes_generated += 4;
        self.rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.reseed_if_necessary();
        self.bytes_generated += 8;
        self.rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.reseed_if_necessary();
        self.bytes_generated += dest.len();
        self.rng.fill_bytes(dest)
    }
}

impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R>>
     SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
    fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
        self.rng.reseed(seed);
        self.reseeder = rsdr;
        self.bytes_generated = 0;
    }
    /// Create a new `ReseedingRng` from the given reseeder and
    /// seed. This uses a default value for `generation_threshold`.
    fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
        ReseedingRng {
            rng: SeedableRng::from_seed(seed),
            generation_threshold: DEFAULT_GENERATION_THRESHOLD,
            bytes_generated: 0,
            reseeder: rsdr
        }
    }
}

/// Something that can be used to reseed an RNG via `ReseedingRng`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::{Rng, SeedableRng};
/// use std::rand::reseeding::{Reseeder, ReseedingRng};
///
/// struct TickTockReseeder { tick: bool }
/// impl Reseeder<rand::StdRng> for TickTockReseeder {
///     fn reseed(&mut self, rng: &mut rand::StdRng) {
///         let val = if self.tick {0} else {1};
///         rng.reseed(&[val]);
///         self.tick = !self.tick;
///     }
/// }
/// fn main() {
///     let rsdr = TickTockReseeder { tick: true };
///     let mut rng = ReseedingRng::new(rand::StdRng::new(), 10, rsdr);
///
///     // this will repeat, because it gets reseeded very regularly.
///     println!("{}", rng.gen_ascii_str(100));
/// }
///
/// ```
pub trait Reseeder<R> {
    /// Reseed the given RNG.
    fn reseed(&mut self, rng: &mut R);
}

/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
pub struct ReseedWithDefault;

impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
    fn reseed(&mut self, rng: &mut R) {
        *rng = Default::default();
    }
}
impl Default for ReseedWithDefault {
    fn default() -> ReseedWithDefault { ReseedWithDefault }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use rand::{SeedableRng, Rng};

    struct Counter {
        i: u32
    }

    impl Rng for Counter {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            // very random
            self.i - 1
        }
    }
    impl Default for Counter {
        fn default() -> Counter {
            Counter { i: 0 }
        }
    }
    impl SeedableRng<u32> for Counter {
        fn reseed(&mut self, seed: u32) {
            self.i = seed;
        }
        fn from_seed(seed: u32) -> Counter {
            Counter { i: seed }
        }
    }
    type MyRng = ReseedingRng<Counter, ReseedWithDefault>;

    #[test]
    fn test_reseeding() {
        let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);

        let mut i = 0;
        for _ in range(0, 1000) {
            assert_eq!(rs.next_u32(), i % 100);
            i += 1;
        }
    }

    #[test]
    fn test_rng_seeded() {
        let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
    }

    #[test]
    fn test_rng_reseed() {
        let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
        let string1 = r.gen_ascii_str(100);

        r.reseed((ReseedWithDefault, 3));

        let string2 = r.gen_ascii_str(100);
        assert_eq!(string1, string2);
    }

    static fill_bytes_v_len: uint = 13579;
    #[test]
    fn test_rng_fill_bytes() {
        use rand::task_rng;
        let mut v = ~[0u8, .. fill_bytes_v_len];
        task_rng().fill_bytes(v);

        // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
        // recursed.
        assert_eq!(v.len(), fill_bytes_v_len);

        // To test that `fill_bytes` actually did something, check that the
        // average of `v` is not 0.
        let mut sum = 0.0;
        for &x in v.iter() {
            sum += x as f64;
        }
        assert!(sum / v.len() as f64 != 0.0);
    }
}
<commit_msg>Remove std::default::Default from the prelude<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.

use container::Container;
use default::Default;
use rand::{Rng, SeedableRng};

/// How many bytes of entropy the underling RNG is allowed to generate
/// before it is reseeded.
static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;

/// A wrapper around any RNG which reseeds the underlying RNG after it
/// has generated a certain number of random bytes.
pub struct ReseedingRng<R, Rsdr> {
    priv rng: R,
    priv generation_threshold: uint,
    priv bytes_generated: uint,
    /// Controls the behaviour when reseeding the RNG.
    reseeder: Rsdr
}

impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
    /// Create a new `ReseedingRng` with the given parameters.
    ///
    /// # Arguments
    ///
    /// * `rng`: the random number generator to use.
    /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
    /// * `reseeder`: the reseeding object to use.
    pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
        ReseedingRng {
            rng: rng,
            generation_threshold: generation_threshold,
            bytes_generated: 0,
            reseeder: reseeder
        }
    }

    /// Reseed the internal RNG if the number of bytes that have been
    /// generated exceed the threshold.
    pub fn reseed_if_necessary(&mut self) {
        if self.bytes_generated >= self.generation_threshold {
            self.reseeder.reseed(&mut self.rng);
            self.bytes_generated = 0;
        }
    }
}

impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
    fn next_u32(&mut self) -> u32 {
        self.reseed_if_necessary();
        self.bytes_generated += 4;
        self.rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.reseed_if_necessary();
        self.bytes_generated += 8;
        self.rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.reseed_if_necessary();
        self.bytes_generated += dest.len();
        self.rng.fill_bytes(dest)
    }
}

impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R>>
     SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
    fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
        self.rng.reseed(seed);
        self.reseeder = rsdr;
        self.bytes_generated = 0;
    }
    /// Create a new `ReseedingRng` from the given reseeder and
    /// seed. This uses a default value for `generation_threshold`.
    fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
        ReseedingRng {
            rng: SeedableRng::from_seed(seed),
            generation_threshold: DEFAULT_GENERATION_THRESHOLD,
            bytes_generated: 0,
            reseeder: rsdr
        }
    }
}

/// Something that can be used to reseed an RNG via `ReseedingRng`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::{Rng, SeedableRng};
/// use std::rand::reseeding::{Reseeder, ReseedingRng};
///
/// struct TickTockReseeder { tick: bool }
/// impl Reseeder<rand::StdRng> for TickTockReseeder {
///     fn reseed(&mut self, rng: &mut rand::StdRng) {
///         let val = if self.tick {0} else {1};
///         rng.reseed(&[val]);
///         self.tick = !self.tick;
///     }
/// }
/// fn main() {
///     let rsdr = TickTockReseeder { tick: true };
///     let mut rng = ReseedingRng::new(rand::StdRng::new(), 10, rsdr);
///
///     // this will repeat, because it gets reseeded very regularly.
///     println!("{}", rng.gen_ascii_str(100));
/// }
///
/// ```
pub trait Reseeder<R> {
    /// Reseed the given RNG.
    fn reseed(&mut self, rng: &mut R);
}

/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
pub struct ReseedWithDefault;

impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
    fn reseed(&mut self, rng: &mut R) {
        *rng = Default::default();
    }
}
impl Default for ReseedWithDefault {
    fn default() -> ReseedWithDefault { ReseedWithDefault }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use default::Default;
    use rand::{SeedableRng, Rng};

    struct Counter {
        i: u32
    }

    impl Rng for Counter {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            // very random
            self.i - 1
        }
    }
    impl Default for Counter {
        fn default() -> Counter {
            Counter { i: 0 }
        }
    }
    impl SeedableRng<u32> for Counter {
        fn reseed(&mut self, seed: u32) {
            self.i = seed;
        }
        fn from_seed(seed: u32) -> Counter {
            Counter { i: seed }
        }
    }
    type MyRng = ReseedingRng<Counter, ReseedWithDefault>;

    #[test]
    fn test_reseeding() {
        let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);

        let mut i = 0;
        for _ in range(0, 1000) {
            assert_eq!(rs.next_u32(), i % 100);
            i += 1;
        }
    }

    #[test]
    fn test_rng_seeded() {
        let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
    }

    #[test]
    fn test_rng_reseed() {
        let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
        let string1 = r.gen_ascii_str(100);

        r.reseed((ReseedWithDefault, 3));

        let string2 = r.gen_ascii_str(100);
        assert_eq!(string1, string2);
    }

    static fill_bytes_v_len: uint = 13579;
    #[test]
    fn test_rng_fill_bytes() {
        use rand::task_rng;
        let mut v = ~[0u8, .. fill_bytes_v_len];
        task_rng().fill_bytes(v);

        // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
        // recursed.
        assert_eq!(v.len(), fill_bytes_v_len);

        // To test that `fill_bytes` actually did something, check that the
        // average of `v` is not 0.
        let mut sum = 0.0;
        for &x in v.iter() {
            sum += x as f64;
        }
        assert!(sum / v.len() as f64 != 0.0);
    }
}
<|endoftext|>


<commit_before>//! Developer note:
//!
//! This is a set of embed builders for rich embeds.
//!
//! These are used in the [`ChannelId::send_message`] and
//! [`ExecuteWebhook::embeds`] methods, both as part of builders.
//!
//! The only builder that should be exposed is [`CreateEmbed`]. The rest of
//! these have no real reason for being exposed, but are for completeness' sake.
//!
//! Documentation for embeds can be found [here].
//!
//! [`ChannelId::send_message`]: ../model/id/struct.ChannelId.html#method.send_message
//! [`CreateEmbed`]: struct.CreateEmbed.html
//! [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
//! [here]: https://discordapp.com/developers/docs/resources/channel#embed-object

use chrono::{DateTime, TimeZone};
use internal::prelude::*;
use model::channel::Embed;
use serde_json::Value;
use std::{
    default::Default,
    fmt::Display
};
use utils::{self, VecMap};

#[cfg(feature = "utils")]
use utils::Colour;

/// A builder to create a fake [`Embed`] object, for use with the
/// [`ChannelId::send_message`] and [`ExecuteWebhook::embeds`] methods.
///
/// # Examples
///
/// Refer to the documentation for [`ChannelId::send_message`] for a very in-depth
/// example on how to use this.
///
/// [`ChannelId::send_message`]: ../model/id/struct.ChannelId.html#method.send_message
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
#[derive(Clone, Debug)]
pub struct CreateEmbed(pub VecMap<&'static str, Value>);

impl CreateEmbed {
    /// Set the author of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedAuthor`] for more
    /// information.
    ///
    /// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html
    pub fn author<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor {
        let map = utils::vecmap_to_json_map(f(CreateEmbedAuthor::default()).0);

        self.0.insert("author", Value::Object(map));

        self
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    #[cfg(feature = "utils")]
    #[inline]
    pub fn color<C: Into<Colour>>(self, colour: C) -> Self { self.colour(colour.into()) }

    /// Set the colour of the left-hand side of the embed.
    #[cfg(feature = "utils")]
    pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
        self.0.insert(
            "color",
            Value::Number(Number::from(u64::from(colour.into().0))),
        );

        self
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    #[cfg(not(feature = "utils"))]
    #[inline]
    pub fn color(self, colour: u32) -> Self { self.colour(colour) }

    /// Set the colour of the left-hand side of the embed.
    #[cfg(not(feature = "utils"))]
    pub fn colour(mut self, colour: u32) -> Self {
        self.0
            .insert("color", Value::Number(Number::from(colour)));

        self
    }

    /// Set the description of the embed.
    ///
    /// **Note**: This can't be longer than 2048 characters.
    pub fn description<D: Display>(mut self, description: D) -> Self {
        self.0.insert(
            "description",
            Value::String(description.to_string()),
        );

        self
    }

    /// Set a field. Note that this will not overwrite other fields, and will
    /// add to them.
    ///
    /// Refer to the documentation for [`CreateEmbedField`] for more
    /// information.
    ///
    /// **Note**: Maximum amount of characters you can put is 256 in a field
    /// name and 1024 in a field value and a field is inline by default.
    ///
    /// [`CreateEmbedField`]: struct.CreateEmbedField.html
    pub fn field<T, U>(mut self, name: T, value: U, inline: bool) -> Self
        where T: Display, U: Display {
        {
            let entry = self.0
                .entry("fields")
                .or_insert_with(|| Value::Array(vec![]));

            if let Value::Array(ref mut inner) = *entry {
                inner.push(json!({
                    "inline": inline,
                    "name": name.to_string(),
                    "value": value.to_string(),
                }));
            }
        }

        self
    }

    /// Adds multiple fields at once.
    ///
    /// This is sugar to reduce the need of calling [`field`] manually multiple times.
    ///
    /// [`field`]: #method.field
    pub fn fields<T, U, It>(mut self, fields: It) -> Self
        where It: IntoIterator<Item=(T, U, bool)>,
              T: Display,
              U: Display {
        for field in fields {
            self = self.field(field.0.to_string(), field.1.to_string(), field.2);
        }

        self
    }

    /// Set the footer of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedFooter`] for more
    /// information.
    ///
    /// [`CreateEmbedFooter`]: struct.CreateEmbedFooter.html
    pub fn footer<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedFooter) -> CreateEmbedFooter {
        let footer = f(CreateEmbedFooter::default()).0;
        let map = utils::vecmap_to_json_map(footer);

        self.0.insert("footer", Value::Object(map));

        self
    }

    fn url_object(mut self, name: &'static str, url: &str) -> Self {
        let obj = json!({
            "url": url.to_string()
        });

        self.0.insert(name, obj);

        self
    }

    /// Set the image associated with the embed. This only supports HTTP(S).
    #[inline]
    pub fn image<S: AsRef<str>>(self, url: S) -> Self {
        self.url_object("image", url.as_ref())
    }

    /// Set the thumbnail of the embed. This only supports HTTP(S).
    #[inline]
    pub fn thumbnail<S: AsRef<str>>(self, url: S) -> Self {
        self.url_object("thumbnail", url.as_ref())
    }

    /// Set the timestamp.
    ///
    /// You may pass a direct string:
    ///
    /// - `2017-01-03T23:00:00`
    /// - `2004-06-08T16:04:23`
    /// - `2004-06-08T16:04:23`
    ///
    /// This timestamp must be in ISO-8601 format. It must also be in UTC format.
    ///
    /// You can also pass anything that implements `chrono::TimeZone`.
    ///
    /// # Examples
    ///
    /// Passing a string timestamp:
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::channel::Message;
    ///
    /// struct Handler;
    ///
    /// impl EventHandler for Handler {
    ///     fn message(&self, _: Context, msg: Message) {
    ///         if msg.content == "~embed" {
    ///             let _ = msg.channel_id.send_message(|m| m
    ///              .embed(|e| e
    ///                     .title("hello")
    ///                     .timestamp("2004-06-08T16:04:23")));
    ///         }
    ///     }
    /// }
    ///
    /// let mut client = Client::new("token", Handler).unwrap();
    ///
    /// client.start().unwrap();
    /// ```
    ///
    /// Creating a join-log:
    ///
    /// Note: this example isn't efficient and is for demonstrative purposes.
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::guild::Member;
    /// use serenity::model::id::GuildId;
    ///
    /// struct Handler;
    ///
    /// impl EventHandler for Handler {
    ///     fn guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) {
    ///         use serenity::CACHE;
    ///         let cache = CACHE.read();
    ///
    ///         if let Some(guild) = cache.guild(guild_id) {
    ///             let guild = guild.read();
    ///
    ///             let channel_search = guild
    ///                 .channels
    ///                 .values()
    ///                 .find(|c| c.read().name == "join-log");
    ///
    ///             if let Some(channel) = channel_search {
    ///                 let user = member.user.read();
    ///
    ///                 let _ = channel.read().send_message(|m| m
    ///                     .embed(|e| {
    ///                         let mut e = e
    ///                             .author(|a| a.icon_url(&user.face()).name(&user.name))
    ///                             .title("Member Join");
    ///
    ///                         if let Some(ref joined_at) = member.joined_at {
    ///                             e = e.timestamp(joined_at);
    ///                         }
    ///
    ///                         e
    ///                     }));
    ///             }
    ///         }
    ///     }
    /// }
    ///
    /// let mut client = Client::new("token", Handler).unwrap();
    ///
    /// client.start().unwrap();
    /// ```
    pub fn timestamp<T: Into<Timestamp>>(mut self, timestamp: T) -> Self {
        self.0
            .insert("timestamp", Value::String(timestamp.into().ts));

        self
    }

    /// Set the title of the embed.
    pub fn title<D: Display>(mut self, title: D) -> Self {
        self.0
            .insert("title", Value::String(title.to_string()));

        self
    }

    /// Set the URL to direct to when clicking on the title.
    pub fn url<S: AsRef<str>>(mut self, url: S) -> Self {
        self.0
            .insert("url", Value::String(url.as_ref().to_string()));

        self
    }

    /// Same as calling [`image`] with "attachment://filename.(jpg, png)".
    ///
    /// Note however, you have to be sure you set an attachment (with [`ChannelId::send_files`])
    /// with the provided filename. Or else this won't work.
    ///
    /// [`ChannelId::send_files`]: ../model/id/struct.ChannelId.html#send_files
    pub fn attachment<S: AsRef<str>>(self, filename: S) -> Self {
        self.image(&format!("attachment://{}", filename.as_ref()))
    }
}

impl Default for CreateEmbed {
    /// Creates a builder with default values, setting the `type` to `rich`.
    fn default() -> CreateEmbed {
        let mut map = VecMap::new();
        map.insert("type", Value::String("rich".to_string()));

        CreateEmbed(map)
    }
}

impl From<Embed> for CreateEmbed {
    /// Converts the fields of an embed into the values for a new embed builder.
    ///
    /// Some values - such as Proxy URLs - are not preserved.
    fn from(embed: Embed) -> CreateEmbed {
        let mut b = CreateEmbed::default().colour(embed.colour);

        if let Some(author) = embed.author {
            b = b.author(move |mut a| {
                a = a.name(&author.name);

                if let Some(icon_url) = author.icon_url {
                    a = a.icon_url(&icon_url);
                }

                if let Some(url) = author.url {
                    a = a.url(&url);
                }

                a
            });
        }

        if let Some(description) = embed.description {
            b = b.description(&description);
        }

        for field in embed.fields {
            b = b.field(field.name, field.value, field.inline);
        }

        if let Some(image) = embed.image {
            b = b.image(&image.url);
        }

        if let Some(timestamp) = embed.timestamp {
            b = b.timestamp(timestamp);
        }

        if let Some(thumbnail) = embed.thumbnail {
            b = b.thumbnail(&thumbnail.url);
        }

        if let Some(url) = embed.url {
            b = b.url(&url);
        }

        if let Some(title) = embed.title {
            b = b.title(&title);
        }

        if let Some(footer) = embed.footer {
            b = b.footer(move |mut f| {
                f = f.text(&footer.text);

                if let Some(icon_url) = footer.icon_url {
                    f = f.icon_url(&icon_url);
                }

                f
            });
        }

        b
    }
}

/// A builder to create a fake [`Embed`] object's author, for use with the
/// [`CreateEmbed::author`] method.
///
/// Requires that you specify a [`name`].
///
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author
/// [`name`]: #method.name
#[derive(Clone, Debug, Default)]
pub struct CreateEmbedAuthor(pub VecMap<&'static str, Value>);

impl CreateEmbedAuthor {
    /// Set the URL of the author's icon.
    pub fn icon_url(mut self, icon_url: &str) -> Self {
        self.0.insert("icon_url", Value::String(icon_url.to_string()));

        self
    }

    /// Set the author's name.
    pub fn name(mut self, name: &str) -> Self {
        self.0.insert("name", Value::String(name.to_string()));

        self
    }

    /// Set the author's URL.
    pub fn url(mut self, url: &str) -> Self {
        self.0.insert("url", Value::String(url.to_string()));

        self
    }
}

/// A builder to create a fake [`Embed`] object's footer, for use with the
/// [`CreateEmbed::footer`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer
#[derive(Clone, Debug, Default)]
pub struct CreateEmbedFooter(pub VecMap<&'static str, Value>);

impl CreateEmbedFooter {
    /// Set the icon URL's value. This only supports HTTP(S).
    pub fn icon_url(mut self, icon_url: &str) -> Self {
        self.0.insert("icon_url", Value::String(icon_url.to_string()));

        self
    }

    /// Set the footer's text.
    pub fn text<D: Display>(mut self, text: D) -> Self {
        self.0.insert("text", Value::String(text.to_string()));

        self
    }
}

#[derive(Clone, Debug)]
pub struct Timestamp {
    pub ts: String,
}

impl From<String> for Timestamp {
    fn from(ts: String) -> Self {
        Timestamp {
            ts,
        }
    }
}

impl<'a> From<&'a str> for Timestamp {
    fn from(ts: &'a str) -> Self {
        Timestamp {
            ts: ts.to_string(),
        }
    }
}

impl<'a, Tz: TimeZone> From<&'a DateTime<Tz>> for Timestamp
    where Tz::Offset: Display {
    fn from(dt: &'a DateTime<Tz>) -> Self {
        Timestamp {
            ts: dt.to_rfc3339(),
        }
    }
}
<commit_msg>Remove link to a nonexistant struct<commit_after>//! Developer note:
//!
//! This is a set of embed builders for rich embeds.
//!
//! These are used in the [`ChannelId::send_message`] and
//! [`ExecuteWebhook::embeds`] methods, both as part of builders.
//!
//! The only builder that should be exposed is [`CreateEmbed`]. The rest of
//! these have no real reason for being exposed, but are for completeness' sake.
//!
//! Documentation for embeds can be found [here].
//!
//! [`ChannelId::send_message`]: ../model/id/struct.ChannelId.html#method.send_message
//! [`CreateEmbed`]: struct.CreateEmbed.html
//! [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
//! [here]: https://discordapp.com/developers/docs/resources/channel#embed-object

use chrono::{DateTime, TimeZone};
use internal::prelude::*;
use model::channel::Embed;
use serde_json::Value;
use std::{
    default::Default,
    fmt::Display
};
use utils::{self, VecMap};

#[cfg(feature = "utils")]
use utils::Colour;

/// A builder to create a fake [`Embed`] object, for use with the
/// [`ChannelId::send_message`] and [`ExecuteWebhook::embeds`] methods.
///
/// # Examples
///
/// Refer to the documentation for [`ChannelId::send_message`] for a very in-depth
/// example on how to use this.
///
/// [`ChannelId::send_message`]: ../model/id/struct.ChannelId.html#method.send_message
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
#[derive(Clone, Debug)]
pub struct CreateEmbed(pub VecMap<&'static str, Value>);

impl CreateEmbed {
    /// Set the author of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedAuthor`] for more
    /// information.
    ///
    /// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html
    pub fn author<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor {
        let map = utils::vecmap_to_json_map(f(CreateEmbedAuthor::default()).0);

        self.0.insert("author", Value::Object(map));

        self
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    #[cfg(feature = "utils")]
    #[inline]
    pub fn color<C: Into<Colour>>(self, colour: C) -> Self { self.colour(colour.into()) }

    /// Set the colour of the left-hand side of the embed.
    #[cfg(feature = "utils")]
    pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
        self.0.insert(
            "color",
            Value::Number(Number::from(u64::from(colour.into().0))),
        );

        self
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    #[cfg(not(feature = "utils"))]
    #[inline]
    pub fn color(self, colour: u32) -> Self { self.colour(colour) }

    /// Set the colour of the left-hand side of the embed.
    #[cfg(not(feature = "utils"))]
    pub fn colour(mut self, colour: u32) -> Self {
        self.0
            .insert("color", Value::Number(Number::from(colour)));

        self
    }

    /// Set the description of the embed.
    ///
    /// **Note**: This can't be longer than 2048 characters.
    pub fn description<D: Display>(mut self, description: D) -> Self {
        self.0.insert(
            "description",
            Value::String(description.to_string()),
        );

        self
    }

    /// Set a field. Note that this will not overwrite other fields, and will
    /// add to them.
    ///
    /// **Note**: Maximum amount of characters you can put is 256 in a field
    /// name and 1024 in a field value and a field is inline by default.
    pub fn field<T, U>(mut self, name: T, value: U, inline: bool) -> Self
        where T: Display, U: Display {
        {
            let entry = self.0
                .entry("fields")
                .or_insert_with(|| Value::Array(vec![]));

            if let Value::Array(ref mut inner) = *entry {
                inner.push(json!({
                    "inline": inline,
                    "name": name.to_string(),
                    "value": value.to_string(),
                }));
            }
        }

        self
    }

    /// Adds multiple fields at once.
    ///
    /// This is sugar to reduce the need of calling [`field`] manually multiple times.
    ///
    /// [`field`]: #method.field
    pub fn fields<T, U, It>(mut self, fields: It) -> Self
        where It: IntoIterator<Item=(T, U, bool)>,
              T: Display,
              U: Display {
        for field in fields {
            self = self.field(field.0.to_string(), field.1.to_string(), field.2);
        }

        self
    }

    /// Set the footer of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedFooter`] for more
    /// information.
    ///
    /// [`CreateEmbedFooter`]: struct.CreateEmbedFooter.html
    pub fn footer<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedFooter) -> CreateEmbedFooter {
        let footer = f(CreateEmbedFooter::default()).0;
        let map = utils::vecmap_to_json_map(footer);

        self.0.insert("footer", Value::Object(map));

        self
    }

    fn url_object(mut self, name: &'static str, url: &str) -> Self {
        let obj = json!({
            "url": url.to_string()
        });

        self.0.insert(name, obj);

        self
    }

    /// Set the image associated with the embed. This only supports HTTP(S).
    #[inline]
    pub fn image<S: AsRef<str>>(self, url: S) -> Self {
        self.url_object("image", url.as_ref())
    }

    /// Set the thumbnail of the embed. This only supports HTTP(S).
    #[inline]
    pub fn thumbnail<S: AsRef<str>>(self, url: S) -> Self {
        self.url_object("thumbnail", url.as_ref())
    }

    /// Set the timestamp.
    ///
    /// You may pass a direct string:
    ///
    /// - `2017-01-03T23:00:00`
    /// - `2004-06-08T16:04:23`
    /// - `2004-06-08T16:04:23`
    ///
    /// This timestamp must be in ISO-8601 format. It must also be in UTC format.
    ///
    /// You can also pass anything that implements `chrono::TimeZone`.
    ///
    /// # Examples
    ///
    /// Passing a string timestamp:
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::channel::Message;
    ///
    /// struct Handler;
    ///
    /// impl EventHandler for Handler {
    ///     fn message(&self, _: Context, msg: Message) {
    ///         if msg.content == "~embed" {
    ///             let _ = msg.channel_id.send_message(|m| m
    ///              .embed(|e| e
    ///                     .title("hello")
    ///                     .timestamp("2004-06-08T16:04:23")));
    ///         }
    ///     }
    /// }
    ///
    /// let mut client = Client::new("token", Handler).unwrap();
    ///
    /// client.start().unwrap();
    /// ```
    ///
    /// Creating a join-log:
    ///
    /// Note: this example isn't efficient and is for demonstrative purposes.
    ///
    /// ```rust,no_run
    /// use serenity::prelude::*;
    /// use serenity::model::guild::Member;
    /// use serenity::model::id::GuildId;
    ///
    /// struct Handler;
    ///
    /// impl EventHandler for Handler {
    ///     fn guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) {
    ///         use serenity::CACHE;
    ///         let cache = CACHE.read();
    ///
    ///         if let Some(guild) = cache.guild(guild_id) {
    ///             let guild = guild.read();
    ///
    ///             let channel_search = guild
    ///                 .channels
    ///                 .values()
    ///                 .find(|c| c.read().name == "join-log");
    ///
    ///             if let Some(channel) = channel_search {
    ///                 let user = member.user.read();
    ///
    ///                 let _ = channel.read().send_message(|m| m
    ///                     .embed(|e| {
    ///                         let mut e = e
    ///                             .author(|a| a.icon_url(&user.face()).name(&user.name))
    ///                             .title("Member Join");
    ///
    ///                         if let Some(ref joined_at) = member.joined_at {
    ///                             e = e.timestamp(joined_at);
    ///                         }
    ///
    ///                         e
    ///                     }));
    ///             }
    ///         }
    ///     }
    /// }
    ///
    /// let mut client = Client::new("token", Handler).unwrap();
    ///
    /// client.start().unwrap();
    /// ```
    pub fn timestamp<T: Into<Timestamp>>(mut self, timestamp: T) -> Self {
        self.0
            .insert("timestamp", Value::String(timestamp.into().ts));

        self
    }

    /// Set the title of the embed.
    pub fn title<D: Display>(mut self, title: D) -> Self {
        self.0
            .insert("title", Value::String(title.to_string()));

        self
    }

    /// Set the URL to direct to when clicking on the title.
    pub fn url<S: AsRef<str>>(mut self, url: S) -> Self {
        self.0
            .insert("url", Value::String(url.as_ref().to_string()));

        self
    }

    /// Same as calling [`image`] with "attachment://filename.(jpg, png)".
    ///
    /// Note however, you have to be sure you set an attachment (with [`ChannelId::send_files`])
    /// with the provided filename. Or else this won't work.
    ///
    /// [`ChannelId::send_files`]: ../model/id/struct.ChannelId.html#send_files
    pub fn attachment<S: AsRef<str>>(self, filename: S) -> Self {
        self.image(&format!("attachment://{}", filename.as_ref()))
    }
}

impl Default for CreateEmbed {
    /// Creates a builder with default values, setting the `type` to `rich`.
    fn default() -> CreateEmbed {
        let mut map = VecMap::new();
        map.insert("type", Value::String("rich".to_string()));

        CreateEmbed(map)
    }
}

impl From<Embed> for CreateEmbed {
    /// Converts the fields of an embed into the values for a new embed builder.
    ///
    /// Some values - such as Proxy URLs - are not preserved.
    fn from(embed: Embed) -> CreateEmbed {
        let mut b = CreateEmbed::default().colour(embed.colour);

        if let Some(author) = embed.author {
            b = b.author(move |mut a| {
                a = a.name(&author.name);

                if let Some(icon_url) = author.icon_url {
                    a = a.icon_url(&icon_url);
                }

                if let Some(url) = author.url {
                    a = a.url(&url);
                }

                a
            });
        }

        if let Some(description) = embed.description {
            b = b.description(&description);
        }

        for field in embed.fields {
            b = b.field(field.name, field.value, field.inline);
        }

        if let Some(image) = embed.image {
            b = b.image(&image.url);
        }

        if let Some(timestamp) = embed.timestamp {
            b = b.timestamp(timestamp);
        }

        if let Some(thumbnail) = embed.thumbnail {
            b = b.thumbnail(&thumbnail.url);
        }

        if let Some(url) = embed.url {
            b = b.url(&url);
        }

        if let Some(title) = embed.title {
            b = b.title(&title);
        }

        if let Some(footer) = embed.footer {
            b = b.footer(move |mut f| {
                f = f.text(&footer.text);

                if let Some(icon_url) = footer.icon_url {
                    f = f.icon_url(&icon_url);
                }

                f
            });
        }

        b
    }
}

/// A builder to create a fake [`Embed`] object's author, for use with the
/// [`CreateEmbed::author`] method.
///
/// Requires that you specify a [`name`].
///
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author
/// [`name`]: #method.name
#[derive(Clone, Debug, Default)]
pub struct CreateEmbedAuthor(pub VecMap<&'static str, Value>);

impl CreateEmbedAuthor {
    /// Set the URL of the author's icon.
    pub fn icon_url(mut self, icon_url: &str) -> Self {
        self.0.insert("icon_url", Value::String(icon_url.to_string()));

        self
    }

    /// Set the author's name.
    pub fn name(mut self, name: &str) -> Self {
        self.0.insert("name", Value::String(name.to_string()));

        self
    }

    /// Set the author's URL.
    pub fn url(mut self, url: &str) -> Self {
        self.0.insert("url", Value::String(url.to_string()));

        self
    }
}

/// A builder to create a fake [`Embed`] object's footer, for use with the
/// [`CreateEmbed::footer`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../model/channel/struct.Embed.html
/// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer
#[derive(Clone, Debug, Default)]
pub struct CreateEmbedFooter(pub VecMap<&'static str, Value>);

impl CreateEmbedFooter {
    /// Set the icon URL's value. This only supports HTTP(S).
    pub fn icon_url(mut self, icon_url: &str) -> Self {
        self.0.insert("icon_url", Value::String(icon_url.to_string()));

        self
    }

    /// Set the footer's text.
    pub fn text<D: Display>(mut self, text: D) -> Self {
        self.0.insert("text", Value::String(text.to_string()));

        self
    }
}

#[derive(Clone, Debug)]
pub struct Timestamp {
    pub ts: String,
}

impl From<String> for Timestamp {
    fn from(ts: String) -> Self {
        Timestamp {
            ts,
        }
    }
}

impl<'a> From<&'a str> for Timestamp {
    fn from(ts: &'a str) -> Self {
        Timestamp {
            ts: ts.to_string(),
        }
    }
}

impl<'a, Tz: TimeZone> From<&'a DateTime<Tz>> for Timestamp
    where Tz::Offset: Display {
    fn from(dt: &'a DateTime<Tz>) -> Self {
        Timestamp {
            ts: dt.to_rfc3339(),
        }
    }
}
<|endoftext|>