<commit_before>use std::io::net::ip::{SocketAddr, IpAddr};

use http::server::{Server, Config};
use http::server;

use super::ingot::Ingot;
use super::furnace::Furnace;
use super::response::Response;
use super::request::Request;

pub struct Iron<Rq, Rs, F> {
    pub furnace: F,
    ip: Option<IpAddr>,
    port: Option<u16>
}

impl<Rq, Rs, F: Clone> Clone for Iron<Rq, Rs, F> {
    fn clone(&self) -> Iron<Rq, Rs, F> {
        Iron {
            furnace: self.furnace.clone(),
            ip: self.ip.clone(),
            port: self.port
        }
    }
}

impl<'a, Rq: Request, Rs: Response<'a>, F: Furnace<'a, Rq, Rs>>
        Iron<Rq, Rs, F> {
    pub fn smelt<I: Ingot<'a, Rq, Rs>>(&mut self, ingot: I) {
        self.furnace.smelt(ingot);
    }

    pub fn listen(mut self, ip: IpAddr, port: u16) {
        self.ip = Some(ip);
        self.port = Some(port);
        self.serve_forever();
    }

    pub fn new<'a, Rq, Rs>() -> Iron<Rq, Rs, F> {
        let furnace = Furnace::new();
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }

    pub fn from_furnace<Rq, Rs, F>(furnace: F) -> Iron<Rq, Rs, F> {
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }
}

impl<'a,
     Rq: Request,
     Rs: Response<'a>,
     F: Furnace<'a, Rq, Rs>>
        Server for Iron<Rq, Rs, F> {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr {
            ip: self.ip.unwrap(),
            port: self.port.unwrap()
        } }
    }

    fn handle_request(&self, _req: &server::Request, _res: &mut server::ResponseWriter) {
        // coerce allllllll that
    }
}

<commit_msg>(feat) Implemented handle_request (unsafe).<commit_after>use std::io::net::ip::{SocketAddr, IpAddr};
use std::mem;

use http::server::{Server, Config};
use http::server;

use super::ingot::Ingot;
use super::furnace::Furnace;
use super::response::Response;
use super::request::Request;

pub struct Iron<Rq, Rs, F> {
    pub furnace: F,
    ip: Option<IpAddr>,
    port: Option<u16>
}

impl<Rq, Rs, F: Clone> Clone for Iron<Rq, Rs, F> {
    fn clone(&self) -> Iron<Rq, Rs, F> {
        Iron {
            furnace: self.furnace.clone(),
            ip: self.ip.clone(),
            port: self.port
        }
    }
}

impl<'a, Rq: Request, Rs: Response<'a>, F: Furnace<'a, Rq, Rs>>
        Iron<Rq, Rs, F> {
    pub fn smelt<I: Ingot<'a, Rq, Rs>>(&mut self, ingot: I) {
        self.furnace.smelt(ingot);
    }

    pub fn listen(mut self, ip: IpAddr, port: u16) {
        self.ip = Some(ip);
        self.port = Some(port);
        self.serve_forever();
    }

    pub fn new<'a, Rq, Rs>() -> Iron<Rq, Rs, F> {
        let furnace = Furnace::new();
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }

    pub fn from_furnace<Rq, Rs, F>(furnace: F) -> Iron<Rq, Rs, F> {
        Iron {
            furnace: furnace,
            ip: None,
            port: None
        }
    }
}

impl<'a,
     Rq: Request,
     Rs: Response<'a>,
     F: Furnace<'a, Rq, Rs>>
        Server for Iron<Rq, Rs, F> {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr {
            ip: self.ip.unwrap(),
            port: self.port.unwrap()
        } }
    }

    fn handle_request(&self, req: &server::Request, res: &mut server::ResponseWriter) {
        let request = &mut Request::from_http(req);
        // TODO/FIXME: Replace unsafe block
        let response: &mut Rs = unsafe { mem::transmute(res) };
        let mut furnace = self.furnace.clone();
        furnace.forge(request, response, None);
    }
}
<|endoftext|>


<commit_before>///! Handle `cargo add` arguments

use semver;
use std::error::Error;
use cargo_edit::Dependency;
use fetch_version::get_latest_version;

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

/// Errors when parsing CLI arguments
quick_error! {
    #[derive(Debug)]
    pub enum ArgParseError {
        /// Internal error parsing args to TOML
        BuildingDependency {
            description("Error build a dependency description from arguments")
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name
    pub arg_crate: String,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_ver: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build depenency from arguments
    pub fn parse_dependency(&self) -> Result<Dependency, Box<Error>> {
        if crate_name_has_version(&self.arg_crate) {
            return parse_crate_name_with_version(&self.arg_crate);
        }

        let dependency = Dependency::new(&self.arg_crate).set_optional(self.flag_optional);

        let dependency = if let Some(ref version) = self.flag_ver {
            try!(semver::VersionReq::parse(&version));
            dependency.set_version(version)
        } else if let Some(ref repo) = self.flag_git {
            dependency.set_git(repo)
        } else if let Some(ref path) = self.flag_path {
            dependency.set_path(path)
        } else {
            let v = try!(get_latest_version(&self.arg_crate));
            dependency.set_version(&v)
        };

        Ok(dependency)
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            flag_dev: false,
            flag_build: false,
            flag_ver: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains("@")
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    let xs: Vec<&str> = name.splitn(2, "@").collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

#[cfg(test)]
mod tests {
    use cargo_edit::Dependency;
    use super::*;

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_ver: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependency().unwrap(),
                   Dependency::new("demo").set_version("0.4.2"));
    }
}
<commit_msg>Remove Unused ArgParseError<commit_after>///! Handle `cargo add` arguments

use semver;
use std::error::Error;
use cargo_edit::Dependency;
use fetch_version::get_latest_version;

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name
    pub arg_crate: String,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_ver: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build depenency from arguments
    pub fn parse_dependency(&self) -> Result<Dependency, Box<Error>> {
        if crate_name_has_version(&self.arg_crate) {
            return parse_crate_name_with_version(&self.arg_crate);
        }

        let dependency = Dependency::new(&self.arg_crate).set_optional(self.flag_optional);

        let dependency = if let Some(ref version) = self.flag_ver {
            try!(semver::VersionReq::parse(&version));
            dependency.set_version(version)
        } else if let Some(ref repo) = self.flag_git {
            dependency.set_git(repo)
        } else if let Some(ref path) = self.flag_path {
            dependency.set_path(path)
        } else {
            let v = try!(get_latest_version(&self.arg_crate));
            dependency.set_version(&v)
        };

        Ok(dependency)
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            flag_dev: false,
            flag_build: false,
            flag_ver: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains("@")
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    let xs: Vec<&str> = name.splitn(2, "@").collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

#[cfg(test)]
mod tests {
    use cargo_edit::Dependency;
    use super::*;

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_ver: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependency().unwrap(),
                   Dependency::new("demo").set_version("0.4.2"));
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code, unused_imports))]

extern crate arguments;
extern crate mcpat;

#[macro_use]
extern crate recorder;

mod dynamic;
mod statik;
mod support;

use arguments::Arguments;
use std::{env, process};
use std::fmt::Display;
use std::io::{self, Write};

const USAGE: &'static str = "
Usage: recorder <command> [options]

Commands:
    dynamic        Record the power consumed by a system on a chip.
    static         Record the area occupied by a system on a chip.

Options:
    --help         Display the usage information of a particular command.
";

fn main() {
    let Arguments { options, orphans, .. } = match arguments::parse(env::args()) {
        Ok(arguments) => arguments,
        _ => usage(USAGE),
    };
    if orphans.len() != 1 {
        usage(USAGE);
    }
    let result = match &orphans[0][..] {
        "dynamic" => dynamic::execute(&options),
        "static" => statik::execute(&options),
        _ => fail("the command is unknown"),
    };
    match result {
        Err(error) => fail(error),
        _ => {},
    }
}

#[allow(unused_must_use)]
fn fail<T: Display>(error: T) -> ! {
    io::stderr().write_fmt(format_args!("Error: {}.\n", error));
    process::exit(1);
}

#[allow(unused_must_use)]
fn usage(message: &str) -> ! {
    io::stderr().write_fmt(format_args!("{}\n", message.trim()));
    process::exit(0);
}
<commit_msg>Tidy up a bit<commit_after>#![cfg_attr(test, allow(dead_code, unused_imports))]

extern crate arguments;
extern crate mcpat;

#[macro_use]
extern crate recorder;

mod dynamic;
mod statik;
mod support;

use recorder::{Error, Result};

const USAGE: &'static str = "
Usage: recorder <command> [options]

Commands:
    dynamic        Record the power consumed by a system on a chip.
    static         Record the area occupied by a system on a chip.
";

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.orphans.len() != 1 {
        usage(USAGE);
    }
    match &arguments.orphans[0][..] {
        "dynamic" => dynamic::execute(&arguments.options),
        "static" => statik::execute(&arguments.options),
        _ => raise!("the command is unknown"),
    }
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    stderr().write_all(format!("Error: {}.\n", &*error).as_bytes()).unwrap();
    std::process::exit(1);
}

fn usage(message: &str) -> ! {
    println!("{}\n", message.trim());
    std::process::exit(0);
}
<|endoftext|>


<commit_before>use super::block_tokenizer::{BlockTokenizer, Line, LineType};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum HeadingLevel {
    Level1,
    Level2,
    Level3,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ListType {
    Unordered,
    Ordered,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Block {
    Heading {
        level: HeadingLevel,
        content: String,
    },
    Text { content: String },
    FencedBlock {
        decorator: Option<String>,
        content: String,
    },
    List {
        list_type: ListType,
        items: Vec<String>,
    },
}

#[derive(Debug)]
pub struct BlockParser {
    tokenizer: BlockTokenizer,
}

#[derive(Debug)]
pub struct TextAccumulator {}

impl BlockParser {
    pub fn new(tokenizer: BlockTokenizer) -> Self {
        BlockParser { tokenizer }
    }

    fn parse_text(&mut self) -> Option<Block> {
        None
    }
}

impl Iterator for BlockParser {
    type Item = Block;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.tokenizer.peek() {
                None => return None,
                Some(LineType::Blank) => continue,
                Some(LineType::Text) => return self.parse_text(),
                _ => return None,
            };
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block_tokenizer::BlockTokenizer;

    #[test]
    fn it_works() {
        let mut parser = BlockParser::new(BlockTokenizer::new("foo bar"));

        assert_eq!(Some(Block::Text { content: "foo bar".to_string() }), parser.next());
    }
}<commit_msg>Remove unused import<commit_after>use super::block_tokenizer::{BlockTokenizer, LineType};

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum HeadingLevel {
    Level1,
    Level2,
    Level3,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ListType {
    Unordered,
    Ordered,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Block {
    Heading {
        level: HeadingLevel,
        content: String,
    },
    Text { content: String },
    FencedBlock {
        decorator: Option<String>,
        content: String,
    },
    List {
        list_type: ListType,
        items: Vec<String>,
    },
}

#[derive(Debug)]
pub struct BlockParser {
    tokenizer: BlockTokenizer,
}

#[derive(Debug)]
pub struct TextAccumulator {}

impl BlockParser {
    pub fn new(tokenizer: BlockTokenizer) -> Self {
        BlockParser { tokenizer }
    }

    fn parse_text(&mut self) -> Option<Block> {
        None
    }
}

impl Iterator for BlockParser {
    type Item = Block;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.tokenizer.peek() {
                None => return None,
                Some(LineType::Blank) => continue,
                Some(LineType::Text) => return self.parse_text(),
                _ => return None,
            };
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block_tokenizer::BlockTokenizer;

    #[test]
    fn it_works() {
        let mut parser = BlockParser::new(BlockTokenizer::new("foo bar"));

        assert_eq!(Some(Block::Text { content: "foo bar".to_string() }), parser.next());
    }
}<|endoftext|>


<commit_before>//! lint on blocks unnecessarily using >= with a + 1 or - 1

use rustc::lint::*;
use syntax::ast::*;

use utils::{span_lint_and_then, snippet_opt};

/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
///
///
/// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x >= y + 1
/// ```
///
/// Could be written:
///
/// ```rust
/// x > y
/// ```
declare_lint! {
    pub INT_PLUS_ONE,
    Allow,
    "instead of using x >= y + 1, use x > y"
}

pub struct IntPlusOne;

impl LintPass for IntPlusOne {
    fn get_lints(&self) -> LintArray {
        lint_array!(INT_PLUS_ONE)
    }
}

// cases:
// BinOpKind::Ge
// x >= y + 1
// x - 1 >= y
//
// BinOpKind::Le
// x + 1 <= y
// x <= y - 1

enum Side {
    LHS,
    RHS,
}

impl IntPlusOne {
    #[allow(cast_sign_loss)]
    fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
        if let LitKind::Int(value, ..) = lit.node {
            return value == (target_value as u128)
        }
        false
    }

    fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<(bool, Option<String>)> {
        match (binop, &lhs.node, &rhs.node) {
            // case where `x - 1 >= ...` or `-1 + x >= ...`
            (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
                match (lhskind.node, &lhslhs.node, &lhsrhs.node) {
                    // `-1 + x`
                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => {
                        Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)))
                    },
                    // `x - 1`
                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)))
                    }
                    _ => None
                }
            },
            // case where `... >= y + 1` or `... >= 1 + y`
            (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => {
                match (&rhslhs.node, &rhsrhs.node) {
                    // `y + 1` and `1 + y`
                    (&ExprKind::Lit(ref lit), _) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)))
                    },
                    (_, &ExprKind::Lit(ref lit)) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)))
                    },
                    _ => None
                }
            },
            // case where `x + 1 <= ...` or `1 + x <= ...`
            (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => {
                match (&lhslhs.node, &lhsrhs.node) {
                    // `1 + x` and `x + 1`
                    (&ExprKind::Lit(ref lit), _) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)))
                    },
                    (_, &ExprKind::Lit(ref lit)) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)))
                    },
                    _ => None
                }
            },
            // case where `... >= y - 1` or `... >= -1 + y`
            (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
                match (rhskind.node, &rhslhs.node, &rhsrhs.node) {
                    // `-1 + y`
                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => {
                        Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)))
                    },
                    // `y - 1`
                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => {
                        Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)))
                    },
                    _ => None
                }
            },
            _ => None
        }
    }

    fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option<String> {
        let binop_string = match binop {
            BinOpKind::Ge => ">",
            BinOpKind::Le => "<",
            _ => return None
        };
        if let Some(snippet) = snippet_opt(cx, node.span) {
            if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
                let rec = match side {
                    Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
                    Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
                };
                return rec;
            }
        }
        None
    }

    fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) {
        span_lint_and_then(cx,
                           INT_PLUS_ONE,
                           block.span,
                           "Unnecessary `>= y + 1` or `x - 1 >=`",
                           |db| {
            db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
        });
    }
}

impl EarlyLintPass for IntPlusOne {
    fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) {
        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node {
            match self.check_binop(cx, kind.node, lhs, rhs) {
                Some((should_emit, Some(ref rec))) if should_emit => self.emit_warning(cx, item, rec.clone()),
                _ => ()
            }
        }
    }
}
<commit_msg>Change rtype of int_plus_one detection to Option<String><commit_after>//! lint on blocks unnecessarily using >= with a + 1 or - 1

use rustc::lint::*;
use syntax::ast::*;

use utils::{span_lint_and_then, snippet_opt};

/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
///
///
/// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x >= y + 1
/// ```
///
/// Could be written:
///
/// ```rust
/// x > y
/// ```
declare_lint! {
    pub INT_PLUS_ONE,
    Allow,
    "instead of using x >= y + 1, use x > y"
}

pub struct IntPlusOne;

impl LintPass for IntPlusOne {
    fn get_lints(&self) -> LintArray {
        lint_array!(INT_PLUS_ONE)
    }
}

// cases:
// BinOpKind::Ge
// x >= y + 1
// x - 1 >= y
//
// BinOpKind::Le
// x + 1 <= y
// x <= y - 1

enum Side {
    LHS,
    RHS,
}

impl IntPlusOne {
    #[allow(cast_sign_loss)]
    fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
        if let LitKind::Int(value, ..) = lit.node {
            return value == (target_value as u128)
        }
        false
    }

    fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
        match (binop, &lhs.node, &rhs.node) {
            // case where `x - 1 >= ...` or `-1 + x >= ...`
            (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
                match (lhskind.node, &lhslhs.node, &lhsrhs.node) {
                    // `-1 + x`
                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
                    // `x - 1`
                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
                    _ => None
                }
            },
            // case where `... >= y + 1` or `... >= 1 + y`
            (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => {
                match (&rhslhs.node, &rhsrhs.node) {
                    // `y + 1` and `1 + y`
                    (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
                    (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
                    _ => None
                }
            },
            // case where `x + 1 <= ...` or `1 + x <= ...`
            (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => {
                match (&lhslhs.node, &lhsrhs.node) {
                    // `1 + x` and `x + 1`
                    (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
                    (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
                    _ => None
                }
            },
            // case where `... >= y - 1` or `... >= -1 + y`
            (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
                match (rhskind.node, &rhslhs.node, &rhsrhs.node) {
                    // `-1 + y`
                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
                    // `y - 1`
                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
                    _ => None
                }
            },
            _ => None
        }
    }

    fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option<String> {
        let binop_string = match binop {
            BinOpKind::Ge => ">",
            BinOpKind::Le => "<",
            _ => return None
        };
        if let Some(snippet) = snippet_opt(cx, node.span) {
            if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
                let rec = match side {
                    Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
                    Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
                };
                return rec;
            }
        }
        None
    }

    fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) {
        span_lint_and_then(cx,
                           INT_PLUS_ONE,
                           block.span,
                           "Unnecessary `>= y + 1` or `x - 1 >=`",
                           |db| {
            db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
        });
    }
}

impl EarlyLintPass for IntPlusOne {
    fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) {
        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node {
            if let Some(ref rec) = self.check_binop(cx, kind.node, lhs, rhs) {
                self.emit_warning(cx, item, rec.clone());
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::descriptor::field_descriptor_proto;
use crate::descriptor::FieldDescriptorProto;
use crate::json::json_name;
use crate::message::Message;
use crate::reflect::acc::v2::map::MapFieldAccessorHolder;
use crate::reflect::acc::v2::repeated::RepeatedFieldAccessorHolder;
use crate::reflect::acc::v2::singular::SingularFieldAccessorHolder;
use crate::reflect::acc::v2::AccessorV2;
use crate::reflect::acc::Accessor;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::map::ReflectMapMut;
use crate::reflect::map::ReflectMapRef;
use crate::reflect::reflect_eq::{ReflectEq, ReflectEqMode};
use crate::reflect::repeated::ReflectRepeatedMut;
use crate::reflect::repeated::ReflectRepeatedRef;
use crate::reflect::value::ReflectValueMut;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeDynamic;

/// Reference to a value stored in a field, optional, repeated or map.
// TODO: implement Eq
pub enum ReflectFieldRef<'a> {
    /// Singular field, optional or required in proto3 and just plain field in proto3
    Optional(Option<ReflectValueRef<'a>>),
    /// Repeated field
    Repeated(ReflectRepeatedRef<'a>),
    /// Map field
    Map(ReflectMapRef<'a>),
}

impl<'a> ReflectEq for ReflectFieldRef<'a> {
    fn reflect_eq(&self, that: &Self, mode: &ReflectEqMode) -> bool {
        match (self, that) {
            (ReflectFieldRef::Optional(a), ReflectFieldRef::Optional(b)) => match (a, b) {
                (Some(av), Some(bv)) => av.reflect_eq(&bv, mode),
                (None, None) => true,
                _ => false,
            },
            (ReflectFieldRef::Repeated(a), ReflectFieldRef::Repeated(b)) => a.reflect_eq(b, mode),
            (ReflectFieldRef::Map(a), ReflectFieldRef::Map(b)) => a.reflect_eq(b, mode),
            _ => false,
        }
    }
}

/// Reflective representation of field type
pub enum RuntimeFieldType {
    /// Singular field (required, optional for proto2 or singular for proto3)
    Singular(&'static dyn RuntimeTypeDynamic),
    /// Repeated field
    Repeated(&'static dyn RuntimeTypeDynamic),
    /// Map field
    Map(
        &'static dyn RuntimeTypeDynamic,
        &'static dyn RuntimeTypeDynamic,
    ),
}

fn _assert_sync<'a>() {
    fn _assert_send_sync<T: Sync>() {}
    _assert_send_sync::<ReflectFieldRef<'a>>();
}

/// Field descriptor.
///
/// Can be used for runtime reflection.
pub struct FieldDescriptor {
    proto: &'static FieldDescriptorProto,
    accessor: FieldAccessor,
    json_name: String,
}

impl FieldDescriptor {
    pub(crate) fn new(
        accessor: FieldAccessor,
        proto: &'static FieldDescriptorProto,
    ) -> FieldDescriptor {
        assert_eq!(proto.get_name(), accessor.name);
        let json_name = if !proto.get_json_name().is_empty() {
            proto.get_json_name().to_string()
        } else {
            json_name(proto.get_name())
        };
        FieldDescriptor {
            proto,
            accessor,
            // probably could be lazy-init
            json_name,
        }
    }

    /// Get `.proto` description of field
    pub fn proto(&self) -> &'static FieldDescriptorProto {
        self.proto
    }

    /// Field name as specified in `.proto` file
    pub fn name(&self) -> &str {
        self.accessor.name
    }

    /// JSON field name.
    ///
    /// Can be different from `.proto` field name.
    ///
    /// See [JSON mapping][json] for details.
    ///
    /// [json]: https://developers.google.com/protocol-buffers/docs/proto3#json
    pub fn json_name(&self) -> &str {
        &self.json_name
    }

    /// If this field repeated?
    pub fn is_repeated(&self) -> bool {
        self.proto.get_label() == field_descriptor_proto::Label::LABEL_REPEATED
    }

    /// If this field a map field?
    pub fn is_map(&self) -> bool {
        match self.accessor.accessor {
            Accessor::V2(AccessorV2::Map(..)) => true,
            Accessor::V2(..) => false,
        }
    }

    /// Check if field is set in given message.
    ///
    /// For repeated field or map field return `true` if
    /// collection is not empty.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type.
    pub fn has_field(&self, m: &dyn Message) -> bool {
        match self.accessor.accessor {
            Accessor::V2(AccessorV2::Singular(ref a)) => a.accessor.get_field(m).is_some(),
            Accessor::V2(AccessorV2::Repeated(ref a)) => a.accessor.get_reflect(m).len() != 0,
            Accessor::V2(AccessorV2::Map(ref a)) => a.accessor.get_reflect(m).len() != 0,
        }
    }

    // accessors

    fn singular(&self) -> &SingularFieldAccessorHolder {
        match self.accessor.accessor {
            Accessor::V2(AccessorV2::Singular(ref a)) => a,
            Accessor::V2(..) => panic!("not a singular field: {}", self.name()),
        }
    }

    fn repeated(&self) -> &RepeatedFieldAccessorHolder {
        match self.accessor.accessor {
            Accessor::V2(AccessorV2::Repeated(ref a)) => a,
            Accessor::V2(..) => panic!("not a repeated field: {}", self.name()),
        }
    }

    fn map(&self) -> &MapFieldAccessorHolder {
        match self.accessor.accessor {
            Accessor::V2(AccessorV2::Map(ref a)) => a,
            Accessor::V2(..) => panic!("not a map field: {}", self.name()),
        }
    }

    /// Get message field or default instance if field is unset.
    ///
    /// # Panics
    /// If this field belongs to a different message type or
    /// field type is not message.
    pub fn get_message<'a>(&self, m: &'a dyn Message) -> &'a dyn Message {
        match self.get_singular_field_or_default(m) {
            ReflectValueRef::Message(m) => m,
            _ => panic!("not message"),
        }
    }

    /// Get a mutable reference to a message field.
    /// Initialize field with default message if unset.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or
    /// field type is not singular message.
    pub fn mut_message<'a>(&self, m: &'a mut dyn Message) -> &'a mut dyn Message {
        match self.mut_singular_field_or_default(m) {
            ReflectValueMut::Message(m) => m,
        }
    }

    /// Get singular field value.
    ///
    /// Return field default value if field is unset.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or fields is not singular.
    pub fn get_singular_field_or_default<'a>(&self, m: &'a dyn Message) -> ReflectValueRef<'a> {
        self.singular().accessor.get_field_or_default(m)
    }

    // Not public because it is not implemented for all types
    fn mut_singular_field_or_default<'a>(&self, m: &'a mut dyn Message) -> ReflectValueMut<'a> {
        self.singular().accessor.mut_field_or_default(m)
    }

    /// Runtime representation of singular field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not singular.
    pub fn singular_runtime_type(&self) -> &dyn RuntimeTypeDynamic {
        self.singular().element_type
    }

    /// Set singular field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or
    /// field is not singular or value is of different type.
    pub fn set_singular_field(&self, m: &mut dyn Message, value: ReflectValueBox) {
        self.singular().accessor.set_field(m, value)
    }

    /// Dynamic representation of field type.
    pub fn runtime_field_type(&self) -> RuntimeFieldType {
        use self::AccessorV2::*;
        match self.accessor.accessor {
            Accessor::V2(Singular(ref a)) => RuntimeFieldType::Singular(a.element_type),
            Accessor::V2(Repeated(ref a)) => RuntimeFieldType::Repeated(a.element_type),
            Accessor::V2(Map(ref a)) => RuntimeFieldType::Map(a.key_type, a.value_type),
        }
    }

    /// Get field of any type.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type.
    pub fn get_reflect<'a>(&self, m: &'a dyn Message) -> ReflectFieldRef<'a> {
        use self::AccessorV2::*;
        match self.accessor.accessor {
            Accessor::V2(Singular(ref a)) => ReflectFieldRef::Optional(a.accessor.get_field(m)),
            Accessor::V2(Repeated(ref a)) => ReflectFieldRef::Repeated(a.accessor.get_reflect(m)),
            Accessor::V2(Map(ref a)) => ReflectFieldRef::Map(a.accessor.get_reflect(m)),
        }
    }

    // repeated

    /// Get repeated field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not repeated.
    pub fn get_repeated<'a>(&self, m: &'a dyn Message) -> ReflectRepeatedRef<'a> {
        self.repeated().accessor.get_reflect(m)
    }

    /// Get a mutable reference to `repeated` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `repeated`.
    pub fn mut_repeated<'a>(&self, m: &'a mut dyn Message) -> ReflectRepeatedMut<'a> {
        self.repeated().accessor.mut_reflect(m)
    }

    // map

    /// Get `map` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `map`.
    pub fn get_map<'a>(&self, m: &'a dyn Message) -> ReflectMapRef<'a> {
        self.map().accessor.get_reflect(m)
    }

    /// Get a mutable reference to `map` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `map`.
    pub fn mut_map<'a>(&self, m: &'a mut dyn Message) -> ReflectMapMut<'a> {
        self.map().accessor.mut_reflect(m)
    }
}
<commit_msg>Refactoring FieldAccessor<commit_after>use crate::descriptor::field_descriptor_proto;
use crate::descriptor::FieldDescriptorProto;
use crate::json::json_name;
use crate::message::Message;
use crate::reflect::acc::v2::map::MapFieldAccessorHolder;
use crate::reflect::acc::v2::repeated::RepeatedFieldAccessorHolder;
use crate::reflect::acc::v2::singular::SingularFieldAccessorHolder;
use crate::reflect::acc::v2::AccessorV2;
use crate::reflect::acc::Accessor;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::map::ReflectMapMut;
use crate::reflect::map::ReflectMapRef;
use crate::reflect::reflect_eq::{ReflectEq, ReflectEqMode};
use crate::reflect::repeated::ReflectRepeatedMut;
use crate::reflect::repeated::ReflectRepeatedRef;
use crate::reflect::value::ReflectValueMut;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeDynamic;

/// Reference to a value stored in a field, optional, repeated or map.
// TODO: implement Eq
pub enum ReflectFieldRef<'a> {
    /// Singular field, optional or required in proto3 and just plain field in proto3
    Optional(Option<ReflectValueRef<'a>>),
    /// Repeated field
    Repeated(ReflectRepeatedRef<'a>),
    /// Map field
    Map(ReflectMapRef<'a>),
}

impl<'a> ReflectEq for ReflectFieldRef<'a> {
    fn reflect_eq(&self, that: &Self, mode: &ReflectEqMode) -> bool {
        match (self, that) {
            (ReflectFieldRef::Optional(a), ReflectFieldRef::Optional(b)) => match (a, b) {
                (Some(av), Some(bv)) => av.reflect_eq(&bv, mode),
                (None, None) => true,
                _ => false,
            },
            (ReflectFieldRef::Repeated(a), ReflectFieldRef::Repeated(b)) => a.reflect_eq(b, mode),
            (ReflectFieldRef::Map(a), ReflectFieldRef::Map(b)) => a.reflect_eq(b, mode),
            _ => false,
        }
    }
}

/// Reflective representation of field type
pub enum RuntimeFieldType {
    /// Singular field (required, optional for proto2 or singular for proto3)
    Singular(&'static dyn RuntimeTypeDynamic),
    /// Repeated field
    Repeated(&'static dyn RuntimeTypeDynamic),
    /// Map field
    Map(
        &'static dyn RuntimeTypeDynamic,
        &'static dyn RuntimeTypeDynamic,
    ),
}

fn _assert_sync<'a>() {
    fn _assert_send_sync<T: Sync>() {}
    _assert_send_sync::<ReflectFieldRef<'a>>();
}

/// Field descriptor.
///
/// Can be used for runtime reflection.
pub struct FieldDescriptor {
    proto: &'static FieldDescriptorProto,
    accessor: Accessor,
    json_name: String,
}

impl FieldDescriptor {
    pub(crate) fn new(
        accessor: FieldAccessor,
        proto: &'static FieldDescriptorProto,
    ) -> FieldDescriptor {
        assert_eq!(proto.get_name(), accessor.name);
        let json_name = if !proto.get_json_name().is_empty() {
            proto.get_json_name().to_string()
        } else {
            json_name(proto.get_name())
        };
        FieldDescriptor {
            proto,
            accessor: accessor.accessor,
            // probably could be lazy-init
            json_name,
        }
    }

    /// Get `.proto` description of field
    pub fn proto(&self) -> &'static FieldDescriptorProto {
        self.proto
    }

    /// Field name as specified in `.proto` file
    pub fn name(&self) -> &str {
        self.proto.get_name()
    }

    /// JSON field name.
    ///
    /// Can be different from `.proto` field name.
    ///
    /// See [JSON mapping][json] for details.
    ///
    /// [json]: https://developers.google.com/protocol-buffers/docs/proto3#json
    pub fn json_name(&self) -> &str {
        &self.json_name
    }

    /// If this field repeated?
    pub fn is_repeated(&self) -> bool {
        self.proto.get_label() == field_descriptor_proto::Label::LABEL_REPEATED
    }

    /// If this field a map field?
    pub fn is_map(&self) -> bool {
        match self.accessor {
            Accessor::V2(AccessorV2::Map(..)) => true,
            Accessor::V2(..) => false,
        }
    }

    /// Check if field is set in given message.
    ///
    /// For repeated field or map field return `true` if
    /// collection is not empty.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type.
    pub fn has_field(&self, m: &dyn Message) -> bool {
        match self.accessor {
            Accessor::V2(AccessorV2::Singular(ref a)) => a.accessor.get_field(m).is_some(),
            Accessor::V2(AccessorV2::Repeated(ref a)) => a.accessor.get_reflect(m).len() != 0,
            Accessor::V2(AccessorV2::Map(ref a)) => a.accessor.get_reflect(m).len() != 0,
        }
    }

    // accessors

    fn singular(&self) -> &SingularFieldAccessorHolder {
        match self.accessor {
            Accessor::V2(AccessorV2::Singular(ref a)) => a,
            Accessor::V2(..) => panic!("not a singular field: {}", self.name()),
        }
    }

    fn repeated(&self) -> &RepeatedFieldAccessorHolder {
        match self.accessor {
            Accessor::V2(AccessorV2::Repeated(ref a)) => a,
            Accessor::V2(..) => panic!("not a repeated field: {}", self.name()),
        }
    }

    fn map(&self) -> &MapFieldAccessorHolder {
        match self.accessor {
            Accessor::V2(AccessorV2::Map(ref a)) => a,
            Accessor::V2(..) => panic!("not a map field: {}", self.name()),
        }
    }

    /// Get message field or default instance if field is unset.
    ///
    /// # Panics
    /// If this field belongs to a different message type or
    /// field type is not message.
    pub fn get_message<'a>(&self, m: &'a dyn Message) -> &'a dyn Message {
        match self.get_singular_field_or_default(m) {
            ReflectValueRef::Message(m) => m,
            _ => panic!("not message"),
        }
    }

    /// Get a mutable reference to a message field.
    /// Initialize field with default message if unset.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or
    /// field type is not singular message.
    pub fn mut_message<'a>(&self, m: &'a mut dyn Message) -> &'a mut dyn Message {
        match self.mut_singular_field_or_default(m) {
            ReflectValueMut::Message(m) => m,
        }
    }

    /// Get singular field value.
    ///
    /// Return field default value if field is unset.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or fields is not singular.
    pub fn get_singular_field_or_default<'a>(&self, m: &'a dyn Message) -> ReflectValueRef<'a> {
        self.singular().accessor.get_field_or_default(m)
    }

    // Not public because it is not implemented for all types
    fn mut_singular_field_or_default<'a>(&self, m: &'a mut dyn Message) -> ReflectValueMut<'a> {
        self.singular().accessor.mut_field_or_default(m)
    }

    /// Runtime representation of singular field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not singular.
    pub fn singular_runtime_type(&self) -> &dyn RuntimeTypeDynamic {
        self.singular().element_type
    }

    /// Set singular field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or
    /// field is not singular or value is of different type.
    pub fn set_singular_field(&self, m: &mut dyn Message, value: ReflectValueBox) {
        self.singular().accessor.set_field(m, value)
    }

    /// Dynamic representation of field type.
    pub fn runtime_field_type(&self) -> RuntimeFieldType {
        use self::AccessorV2::*;
        match self.accessor {
            Accessor::V2(Singular(ref a)) => RuntimeFieldType::Singular(a.element_type),
            Accessor::V2(Repeated(ref a)) => RuntimeFieldType::Repeated(a.element_type),
            Accessor::V2(Map(ref a)) => RuntimeFieldType::Map(a.key_type, a.value_type),
        }
    }

    /// Get field of any type.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type.
    pub fn get_reflect<'a>(&self, m: &'a dyn Message) -> ReflectFieldRef<'a> {
        use self::AccessorV2::*;
        match self.accessor {
            Accessor::V2(Singular(ref a)) => ReflectFieldRef::Optional(a.accessor.get_field(m)),
            Accessor::V2(Repeated(ref a)) => ReflectFieldRef::Repeated(a.accessor.get_reflect(m)),
            Accessor::V2(Map(ref a)) => ReflectFieldRef::Map(a.accessor.get_reflect(m)),
        }
    }

    // repeated

    /// Get repeated field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not repeated.
    pub fn get_repeated<'a>(&self, m: &'a dyn Message) -> ReflectRepeatedRef<'a> {
        self.repeated().accessor.get_reflect(m)
    }

    /// Get a mutable reference to `repeated` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `repeated`.
    pub fn mut_repeated<'a>(&self, m: &'a mut dyn Message) -> ReflectRepeatedMut<'a> {
        self.repeated().accessor.mut_reflect(m)
    }

    // map

    /// Get `map` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `map`.
    pub fn get_map<'a>(&self, m: &'a dyn Message) -> ReflectMapRef<'a> {
        self.map().accessor.get_reflect(m)
    }

    /// Get a mutable reference to `map` field.
    ///
    /// # Panics
    ///
    /// If this field belongs to a different message type or field is not `map`.
    pub fn mut_map<'a>(&self, m: &'a mut dyn Message) -> ReflectMapMut<'a> {
        self.map().accessor.mut_reflect(m)
    }
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license

use std::ops::{Deref, DerefMut};
use std::slice;
use std::collections::BTreeMap;

use sys::{Configuration, Particle, ParticleKind, UnitCell};
use sys::Composition;

#[derive(Clone)]
pub struct System {
    configuration: Configuration,
    kinds: BTreeMap<String, ParticleKind>,
}

impl System {
    /// Create a new empty `System`
    pub fn new() -> System {
        System {
            configuration: Configuration::new(),
            kinds: BTreeMap::new(),
        }
    }

    /// Create an empty system with a specific unit cell
    pub fn with_cell(cell: UnitCell) -> System {
        let mut configuration = Configuration::new();
        configuration.cell = cell;
        System {
            configuration: configuration,
            kinds: BTreeMap::new(),
        }
    }

    fn get_kind(&mut self, name: &str) -> ParticleKind {
        match self.kinds.get(name).cloned() {
            Some(kind) => kind,
            None => {
                let kind = ParticleKind(self.kinds.len() as u32);
                let _ = self.kinds.insert(String::from(name), kind);
                kind
            }
        }
    }

    /// Insert a particle at the end of the internal list.
    pub fn add_particle(&mut self, mut particle: Particle) {
        if particle.kind == ParticleKind::invalid() {
            particle.kind = self.get_kind(particle.name());
        }
        self.configuration.add_particle(particle);
    }

    /// Get the number of particles of each kind in the configuration
    pub fn composition(&self) -> Composition {
        let mut composition = Composition::new();
        composition.resize(self.kinds.len());
        for particle in self {
            composition[particle.kind] += 1;
        }
        return composition;
    }

    /// Get a list of all the particles kinds in the system.
    pub fn particle_kinds(&self) -> Vec<ParticleKind> {
        self.kinds.values().cloned().collect()
    }
}

impl Deref for System {
    type Target = Configuration;

    fn deref(&self) -> &Configuration {
        &self.configuration
    }
}

impl DerefMut for System {
    fn deref_mut(&mut self) -> &mut Configuration {
        &mut self.configuration
    }
}

impl<'a> IntoIterator for &'a System {
    type Item = &'a Particle;
    type IntoIter = slice::Iter<'a, Particle>;

    #[inline]
    fn into_iter(self) -> slice::Iter<'a, Particle> {
        self.configuration.iter()
    }
}

impl<'a> IntoIterator for &'a mut System {
    type Item = &'a mut Particle;
    type IntoIter = slice::IterMut<'a, Particle>;

    #[inline]
    fn into_iter(self) -> slice::IterMut<'a, Particle> {
        self.configuration.iter_mut()
    }
}

#[cfg(test)]
mod tests {
    use super::System;
    use sys::*;

    #[test]
    fn deref() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        assert_eq!(system.molecules().len(), 3);

        // This uses deref_mut
        let _ = system.add_bond(0, 1);
        let _ = system.add_bond(2, 1);

        // This uses deref
        assert_eq!(system.molecules().len(), 1);
    }

    #[test]
    fn add_particle() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));

        assert_eq!(system[0].kind, ParticleKind(0));
        assert_eq!(system[1].kind, ParticleKind(1));
        assert_eq!(system[2].kind, ParticleKind(0));
    }

    #[test]
    fn particle_kinds() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("C"));
        system.add_particle(Particle::new("U"));

        let kinds = system.particle_kinds();
        assert_eq!(kinds.len(), 4);
        assert!(kinds.contains(&ParticleKind(0)));
        assert!(kinds.contains(&ParticleKind(1)));
        assert!(kinds.contains(&ParticleKind(2)));
        assert!(kinds.contains(&ParticleKind(3)));
    }

    #[test]
    fn composition() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("C"));
        system.add_particle(Particle::new("U"));
        system.add_particle(Particle::new("H"));

        let composition = system.composition();
        assert_eq!(composition.len(), 4);
        assert_eq!(composition[ParticleKind(0)], 3);
        assert_eq!(composition[ParticleKind(1)], 2);
        assert_eq!(composition[ParticleKind(2)], 1);
        assert_eq!(composition[ParticleKind(3)], 1);
    }
}
<commit_msg>Add interaction to the system<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 Lumol's contributors — BSD license

use std::ops::{Deref, DerefMut};
use std::slice;
use std::collections::BTreeMap;

use energy::{PairInteraction, BondPotential, AnglePotential, DihedralPotential};
use energy::{GlobalPotential, CoulombicPotential};

use sys::{Configuration, Particle, ParticleKind, UnitCell};
use sys::Composition;

use sys2::Interactions;

/// The `System` type hold all the data about a simulated system.
///
/// This data contains:
///
///   - an unit cell, containing the system;
///   - a list of particles in the system;
///   - a list of molecules in the system;
///   - a list of interactions, associating particles kinds and potentials
///
/// In the implementation, the particles contained in a molecule are guaranteed
/// to be contiguous in memory. This allow for faster access when iterating
/// over molecules, and easier molecule removal from the system.
#[derive(Clone)]
pub struct System {
    configuration: Configuration,
    interactions: Interactions,
    kinds: BTreeMap<String, ParticleKind>,
}

impl System {
    /// Create a new empty `System`
    pub fn new() -> System {
        System::with_configuration(Configuration::new())
    }

    /// Create an empty system with a specific unit cell
    pub fn with_cell(cell: UnitCell) -> System {
        let mut configuration = Configuration::new();
        configuration.cell = cell;
        System::with_configuration(configuration)
    }

    /// Create a system with the specified `configuration`
    fn with_configuration(configuration: Configuration) -> System {
        System {
            configuration: configuration,
            kinds: BTreeMap::new(),
            interactions: Interactions::new(),
        }
    }

    fn get_kind(&mut self, name: &str) -> ParticleKind {
        match self.kinds.get(name).cloned() {
            Some(kind) => kind,
            None => {
                let kind = ParticleKind(self.kinds.len() as u32);
                let _ = self.kinds.insert(String::from(name), kind);
                kind
            }
        }
    }

    /// Insert a particle at the end of the internal list.
    pub fn add_particle(&mut self, mut particle: Particle) {
        if particle.kind == ParticleKind::invalid() {
            particle.kind = self.get_kind(particle.name());
        }
        self.configuration.add_particle(particle);
    }

    /// Get the number of particles of each kind in the configuration
    pub fn composition(&self) -> Composition {
        let mut composition = Composition::new();
        composition.resize(self.kinds.len());
        for particle in self {
            composition[particle.kind] += 1;
        }
        return composition;
    }

    /// Get a list of all the particles kinds in the system.
    pub fn particle_kinds(&self) -> Vec<ParticleKind> {
        self.kinds.values().cloned().collect()
    }
}

/// Functions related to interactions
impl System {
    /// Add the `potential` pair interaction for the pair `(i, j)`
    pub fn add_pair_potential(&mut self, i: &str, j: &str, potential: PairInteraction) {
        let kind_i = self.get_kind(i);
        let kind_j = self.get_kind(j);
        self.interactions.add_pair(kind_i, kind_j, potential)
    }

    /// Add the `potential` bonded interaction for the pair `(i, j)`
    pub fn add_bond_potential(&mut self, i: &str, j: &str, potential: Box<BondPotential>) {
        let kind_i = self.get_kind(i);
        let kind_j = self.get_kind(j);
        self.interactions.add_bond(kind_i, kind_j, potential)
    }

    /// Add the `potential` angle interaction for the angle `(i, j, k)`
    pub fn add_angle_potential(&mut self, i: &str, j: &str, k: &str, potential: Box<AnglePotential>) {
        let kind_i = self.get_kind(i);
        let kind_j = self.get_kind(j);
        let kind_k = self.get_kind(k);
        self.interactions.add_angle(kind_i, kind_j, kind_k, potential)
    }

    /// Add the `potential` dihedral interaction for the dihedral angle `(i, j,
    /// k, m)`
    pub fn add_dihedral_potential(&mut self, i: &str, j: &str, k: &str, m: &str, potential: Box<DihedralPotential>) {
        let kind_i = self.get_kind(i);
        let kind_j = self.get_kind(j);
        let kind_k = self.get_kind(k);
        let kind_m = self.get_kind(m);
        self.interactions.add_dihedral(kind_i, kind_j, kind_k, kind_m, potential)
    }

    /// Set the coulombic interaction for all pairs to `potential`
    pub fn set_coulomb_potential(&mut self, potential: Box<CoulombicPotential>) {
        self.interactions.coulomb = Some(potential);
    }

    /// Add the `potential` global interaction
    pub fn add_global_potential(&mut self, potential: Box<GlobalPotential>) {
        self.interactions.globals.push(potential);
    }

    /// Get the list of pair potential acting between the particles at indexes
    /// `i` and `j`.
    pub fn pair_potentials(&self, i: usize, j: usize) -> &[PairInteraction] {
        let kind_i = self[i].kind;
        let kind_j = self[j].kind;
        let pairs = self.interactions.pairs(kind_i, kind_j);
        if pairs.is_empty() {
            warn_once!(
                "No potential defined for the pair ({}, {})",
                self[i].name(), self[j].name()
            );
        }
        return pairs;
    }

    /// Get the list of bonded potential acting between the particles at indexes
    /// `i` and `j`.
    pub fn bond_potentials(&self, i: usize, j: usize) -> &[Box<BondPotential>] {
        let kind_i = self[i].kind;
        let kind_j = self[j].kind;
        let bonds = self.interactions.bonds(kind_i, kind_j);
        if bonds.is_empty() {
            warn_once!(
                "No potential defined for the bond ({}, {})",
                self[i].name(), self[j].name()
            );
        }
        return bonds;
    }

    /// Get the list of angle interaction acting between the particles at
    /// indexes `i`, `j` and `k`.
    pub fn angle_potentials(&self, i: usize, j: usize, k: usize) -> &[Box<AnglePotential>] {
        let kind_i = self[i].kind;
        let kind_j = self[j].kind;
        let kind_k = self[k].kind;
        let angles = self.interactions.angles(kind_i, kind_j, kind_k);
        if angles.is_empty() {
            warn_once!(
                "No potential defined for the angle ({}, {}, {})",
                self[i].name(), self[j].name(), self[k].name()
            );
        }
        return angles;
    }

    /// Get the list of dihedral angles interaction acting between the particles
    /// at indexes `i`, `j`, `k` and `m`.
    pub fn dihedral_potentials(&self, i: usize, j: usize, k: usize, m: usize) -> &[Box<DihedralPotential>] {
        let kind_i = self[i].kind;
        let kind_j = self[j].kind;
        let kind_k = self[k].kind;
        let kind_m = self[m].kind;
        let dihedrals = self.interactions.dihedrals(kind_i, kind_j, kind_k, kind_m);
        if dihedrals.is_empty() {
            warn_once!(
                "No potential defined for the dihedral angle ({}, {}, {}, {})",
                self[i].name(), self[j].name(), self[k].name(), self[m].name()
            );
        }
        return dihedrals;
    }

    /// Get the coulombic interaction for the system
    pub fn coulomb_potential(&self) -> Option<&Box<CoulombicPotential>> {
        self.interactions.coulomb.as_ref()
    }

    /// Get all global interactions for the system
    pub fn global_potentials(&self) -> &[Box<GlobalPotential>] {
        &self.interactions.globals
    }

    /// Get maximum cutoff from `coulomb`, `pairs` and `global` interactions.
    pub fn maximum_cutoff(&self) -> Option<f64> {
        self.interactions.maximum_cutoff()
    }
}

impl Deref for System {
    type Target = Configuration;

    fn deref(&self) -> &Configuration {
        &self.configuration
    }
}

impl DerefMut for System {
    fn deref_mut(&mut self) -> &mut Configuration {
        &mut self.configuration
    }
}

impl<'a> IntoIterator for &'a System {
    type Item = &'a Particle;
    type IntoIter = slice::Iter<'a, Particle>;

    #[inline]
    fn into_iter(self) -> slice::Iter<'a, Particle> {
        self.configuration.iter()
    }
}

impl<'a> IntoIterator for &'a mut System {
    type Item = &'a mut Particle;
    type IntoIter = slice::IterMut<'a, Particle>;

    #[inline]
    fn into_iter(self) -> slice::IterMut<'a, Particle> {
        self.configuration.iter_mut()
    }
}

#[cfg(test)]
mod tests {
    use super::System;
    use sys::*;

    #[test]
    fn deref() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        assert_eq!(system.molecules().len(), 3);

        // This uses deref_mut
        let _ = system.add_bond(0, 1);
        let _ = system.add_bond(2, 1);

        // This uses deref
        assert_eq!(system.molecules().len(), 1);
    }

    #[test]
    fn add_particle() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));

        assert_eq!(system[0].kind, ParticleKind(0));
        assert_eq!(system[1].kind, ParticleKind(1));
        assert_eq!(system[2].kind, ParticleKind(0));
    }

    #[test]
    fn particle_kinds() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("C"));
        system.add_particle(Particle::new("U"));

        let kinds = system.particle_kinds();
        assert_eq!(kinds.len(), 4);
        assert!(kinds.contains(&ParticleKind(0)));
        assert!(kinds.contains(&ParticleKind(1)));
        assert!(kinds.contains(&ParticleKind(2)));
        assert!(kinds.contains(&ParticleKind(3)));
    }

    #[test]
    fn composition() {
        let mut system = System::new();
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("O"));
        system.add_particle(Particle::new("H"));
        system.add_particle(Particle::new("C"));
        system.add_particle(Particle::new("U"));
        system.add_particle(Particle::new("H"));

        let composition = system.composition();
        assert_eq!(composition.len(), 4);
        assert_eq!(composition[ParticleKind(0)], 3);
        assert_eq!(composition[ParticleKind(1)], 2);
        assert_eq!(composition[ParticleKind(2)], 1);
        assert_eq!(composition[ParticleKind(3)], 1);
    }

    #[test]
    fn missing_interaction() {
        let mut system = System::new();
        system.add_particle(Particle::new("He"));
        system.add_particle(Particle::new("He"));
        system.add_particle(Particle::new("He"));
        system.add_particle(Particle::new("He"));
        assert_eq!(system.pair_potentials(0, 0).len(), 0);
        assert_eq!(system.bond_potentials(0, 0).len(), 0);
        assert_eq!(system.angle_potentials(0, 0, 0).len(), 0);
        assert_eq!(system.dihedral_potentials(0, 0, 0, 0).len(), 0);
    }
}
<|endoftext|>


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

extern crate cryptocurrency;
extern crate exonum;
#[macro_use]
extern crate exonum_testkit;

use exonum::crypto::{self, PublicKey, SecretKey};
use exonum::messages::Message;
use exonum_testkit::{ApiKind, TestKit, TestKitApi, TestKitBuilder};

use cryptocurrency::{TxCreateWallet, TxTransfer, TransactionResponse, Wallet, CurrencyService};

struct CryptocurrencyApi {
    inner: TestKitApi,
}

impl CryptocurrencyApi {
    fn create_wallet(&self, name: &str) -> (TxCreateWallet, SecretKey) {
        let (pubkey, key) = crypto::gen_keypair();
        // Create a presigned transaction
        let tx = TxCreateWallet::new(&pubkey, name, &key);

        let tx_info: TransactionResponse = self.inner.post(
            ApiKind::Service("cryptocurrency"),
            "v1/wallets",
            &tx,
        );
        assert_eq!(tx_info.tx_hash, tx.hash());
        (tx, key)
    }

    fn get_wallet(&self, pubkey: &PublicKey) -> Wallet {
        self.inner.get(
            ApiKind::Service("cryptocurrency"),
            &format!("v1/wallet/{}", pubkey.to_string()),
        )
    }
}

fn create_testkit() -> (TestKit, CryptocurrencyApi) {
    let testkit = TestKitBuilder::validator()
        .with_service(CurrencyService)
        .create();
    let api = CryptocurrencyApi { inner: testkit.api() };
    (testkit, api)
}

#[test]
fn test_create_wallet() {
    let (mut testkit, api) = create_testkit();
    let (tx, _) = api.create_wallet("Alice");
    testkit.create_block();

    // Check that the user indeed is persisted by the service
    let wallet = api.get_wallet(tx.pub_key());
    assert_eq!(wallet.pub_key(), tx.pub_key());
    assert_eq!(wallet.name(), tx.name());
    assert_eq!(wallet.balance(), 100);
}

#[test]
fn test_transfer() {
    let (mut testkit, api) = create_testkit();
    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    testkit.create_block();

    // Check that the initial Alice's and Bob's balances persisted by the service
    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    testkit.create_block_with_transactions(txvec![tx]);

    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 90);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 110);
}
<commit_msg>Tweak tests and add couple new ones<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cryptocurrency;
extern crate exonum;
extern crate exonum_testkit;

use exonum::crypto::{self, PublicKey, SecretKey};
use exonum::messages::Message;
use exonum_testkit::{ApiKind, TestKit, TestKitApi, TestKitBuilder};

// Import datatypes used in tests from the crate where the service is defined.
use cryptocurrency::{TxCreateWallet, TxTransfer, TransactionResponse, Wallet, CurrencyService};

/// Wrapper for the cryptocurrency service API allowing to easily use it
/// (compared to `TestKitApi` calls).
struct CryptocurrencyApi {
    inner: TestKitApi,
}

impl CryptocurrencyApi {
    /// Generates a wallet creation transaction with a random key pair, sends it over HTTP,
    /// and checks the synchronous result (i.e., the hash of the transaction returned
    /// within the `TransactionResponse` struct).
    /// Note that the transaction is not immediately added to the blockchain, but rather is put
    /// to the pool of unconfirmed transactions.
    fn create_wallet(&self, name: &str) -> (TxCreateWallet, SecretKey) {
        let (pubkey, key) = crypto::gen_keypair();
        // Create a presigned transaction
        let tx = TxCreateWallet::new(&pubkey, name, &key);

        let tx_info: TransactionResponse = self.inner.post(
            ApiKind::Service("cryptocurrency"),
            "v1/wallets",
            &tx,
        );
        assert_eq!(tx_info.tx_hash, tx.hash());
        (tx, key)
    }

    /// Sends a transfer transaction over HTTP and checks the synchronous result.
    fn transfer(&self, tx: &TxTransfer) {
        let tx_info: TransactionResponse = self.inner.post(
            ApiKind::Service("cryptocurrency"),
            "v1/wallets/transfer",
            tx,
        );
        assert_eq!(tx_info.tx_hash, tx.hash());
    }

    /// Gets the state of a particular wallet using an HTTP request.
    fn get_wallet(&self, pubkey: &PublicKey) -> Wallet {
        self.inner.get(
            ApiKind::Service("cryptocurrency"),
            &format!("v1/wallet/{}", pubkey.to_string()),
        )
    }

    /// Asserts that a wallet with the specified public key is not known to the blockchain.
    fn assert_no_wallet(&self, pubkey: &PublicKey) {
        let err: String = self.inner.get_err(
            ApiKind::Service("cryptocurrency"),
            &format!("v1/wallet/{}", pubkey.to_string()),
        );
        assert_eq!(err, "Wallet not found".to_string());
    }
}

/// Creates a testkit together with the API wrapper defined above.
fn create_testkit() -> (TestKit, CryptocurrencyApi) {
    let testkit = TestKitBuilder::validator()
        .with_service(CurrencyService)
        .create();
    let api = CryptocurrencyApi { inner: testkit.api() };
    (testkit, api)
}

/// Check that the wallet creation transaction works when invoked via API.
#[test]
fn test_create_wallet() {
    let (mut testkit, api) = create_testkit();
    // Create and send a transaction via API
    let (tx, _) = api.create_wallet("Alice");
    testkit.create_block();

    // Check that the user indeed is persisted by the service
    let wallet = api.get_wallet(tx.pub_key());
    assert_eq!(wallet.pub_key(), tx.pub_key());
    assert_eq!(wallet.name(), tx.name());
    assert_eq!(wallet.balance(), 100);
}

/// Check that the transfer transaction works as intended.
#[test]
fn test_transfer() {
    // Create 2 wallets.
    let (mut testkit, api) = create_testkit();
    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    testkit.create_block();

    // Check that the initial Alice's and Bob's balances persisted by the service.
    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds by invoking the corresponding API method.
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // transferred amount
        0, // seed
        &key_alice,
    );
    api.transfer(&tx);
    testkit.create_block();

    // After the transfer transaction is included into a block, we may check new wallet
    // balances.
    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 90);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 110);
}

/// Check that a transfer from a non-existing wallet fails as expected.
#[test]
fn test_transfer_from_nonexisting_wallet() {
    let (mut testkit, api) = create_testkit();

    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    // Do not commit Alice's transaction, so Alice's wallet does not exist
    // when a transfer occurs.
    testkit.create_block_with_tx_hashes(&[tx_bob.hash()]);

    api.assert_no_wallet(tx_alice.pub_key());
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // transfer amount
        0, // seed
        &key_alice,
    );
    api.transfer(&tx);
    testkit.create_block_with_tx_hashes(&[tx.hash()]);

    // Check that Bob's balance doesn't change
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);
}

/// Check that a transfer to a non-existing wallet fails as expected.
#[test]
fn test_transfer_to_nonexisting_wallet() {
    let (mut testkit, api) = create_testkit();

    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    // Do not commit Bob's transaction, so Bob's wallet does not exist
    // when a transfer occurs.
    testkit.create_block_with_tx_hashes(&[tx_alice.hash()]);

    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    api.assert_no_wallet(tx_bob.pub_key());

    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // transfer amount
        0, // seed
        &key_alice,
    );
    api.transfer(&tx);
    testkit.create_block_with_tx_hashes(&[tx.hash()]);

    // Check that Alice's balance doesn't change
    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
}

/// Check that an overcharge does not lead to changes in sender's and receiver's balances.
#[test]
fn test_transfer_overcharge() {
    let (mut testkit, api) = create_testkit();

    let (tx_alice, key_alice) = api.create_wallet("Alice");
    let (tx_bob, _) = api.create_wallet("Bob");
    testkit.create_block();

    // Transfer funds. The transfer amount (110) is more than Alice has (100).
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        110, // transfer amount
        0, // seed
        &key_alice,
    );
    api.transfer(&tx);
    testkit.create_block();

    let wallet = api.get_wallet(tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = api.get_wallet(tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);
}
<|endoftext|>


<commit_before>#![allow(unused_variables, unused_imports, dead_code)]

#[macro_use]
extern crate nom;
extern crate m3u8_rs;

use std::fs;
use std::path;
use m3u8_rs::*;
use m3u8_rs::playlist::*;
use std::io::Read;
use std::fs::File;
use nom::*;
use std::collections::HashMap;

fn all_sample_m3u_playlists() -> Vec<path::PathBuf> {
    fs::read_dir("sample-playlists\\").unwrap()
        .filter_map(Result::ok)
        .map(|dir| dir.path())
        .filter(|path| path.extension().map_or(false, |ext| ext == "m3u8"))
        .collect()
}

fn getm3u(path: &str) -> String {
    let mut buf = String::new();
    let mut file = fs::File::open(path).expect("Can't find m3u8.");
    let u = file.read_to_string(&mut buf).expect("Can't read file");
    buf
}

fn get_sample_playlist(name: &str) -> String {
    getm3u(&(String::from("sample-playlists\\") + name))
}

// -----------------------------------------------------------------------------------------------
// Playlist

fn print_parse_playlist_test(playlist_name: &str) -> bool {
    let input: String = get_sample_playlist(playlist_name);
    println!("Parsing playlist file: {:?}", playlist_name);
    let parsed = parse_playlist(input.as_bytes());

    if let IResult::Done(i,o) = parsed {
        println!("{:?}", o);
        true
    }
    else {
        println!("Parsing failed:\n {:?}", parsed);
        false
    }
}

#[test]
fn playlist_master_with_alternatives() {
    assert!(print_parse_playlist_test("master-with-alternatives.m3u8"));
}

#[test]
fn playlist_master_with_i_frame_stream_inf() {
    assert!(print_parse_playlist_test("master-with-i-frame-stream-inf.m3u8"));
}

#[test]
fn playlist_master_with_multiple_codecs() {
    assert!(print_parse_playlist_test("master-with-multiple-codecs.m3u8"));
}

// -- Media playlists

#[test]
fn playlist_media_standard() {
    assert!(print_parse_playlist_test("mediaplaylist.m3u8"));
}

#[test]
fn playlist_media_without_segments() {
    assert!(print_parse_playlist_test("media-playlist-without-segments.m3u8"));
}

// -----------------------------------------------------------------------------------------------
// Playlist with no newline end

#[test]
fn playlist_not_ending_in_newline_master() {
    assert!(print_parse_playlist_test("master-not-ending-in-newline.m3u8"));
}

#[test]
fn playlist_not_ending_in_newline_media() {
    assert!(print_parse_playlist_test("media-not-ending-in-newline.m3u8"));
}

// -----------------------------------------------------------------------------------------------
// Playlist type detection tests

#[test]
fn playlist_type_is_master() {
    let input = get_sample_playlist("master.m3u8");
    let result = is_master_playlist(input.as_bytes());
    assert_eq!(true, result);
}

// #[test]
// fn playlist_type_with_unkown_tag() {
//     let input = get_sample_playlist("!!");
//     let result = is_master_playlist(input.as_bytes());
//     println!("Playlist_type_with_unkown_tag is master playlist: {:?}", result);
//     assert_eq!(true, result);
// }

#[test]
fn playlist_types() {
    for path_buf in all_sample_m3u_playlists() {
        let path = path_buf.to_str().unwrap();
        let input = getm3u(path);
        let is_master = is_master_playlist(input.as_bytes());

        assert!(path.to_lowercase().contains("master") == is_master);

        println!("{:?} = {:?}", path, is_master);
    }
}

// -----------------------------------------------------------------------------------------------
// Variant

#[test]
fn variant_stream() {
    let input = b"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"xxx\"\n";
    let result = variant_stream_tag(input);
    println!("{:?}", result);
}

// -----------------------------------------------------------------------------------------------
// Other

#[test]
fn test_key_value_pairs_trailing_equals() {
    let res = key_value_pairs(b"BANDWIDTH=395000,CODECS=\"avc1.4d001f,mp4a.40.2\"\r\nrest=");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pairs_multiple_quoted_values() {
    assert_eq!(
        key_value_pairs(b"BANDWIDTH=86000,URI=\"low/iframe.m3u8\",PROGRAM-ID=1,RESOLUTION=\"1x1\",VIDEO=1\nrest"),
        IResult::Done(
            "\nrest".as_bytes(),
            vec![
                ("BANDWIDTH".to_string(), "86000".to_string()),
                ("URI".to_string(), "low/iframe.m3u8".to_string()),
                ("PROGRAM-ID".to_string(), "1".to_string()),
                ("RESOLUTION".to_string(), "1x1".to_string()),
                ("VIDEO".to_string(), "1".to_string())
            ].into_iter().collect::<HashMap<String,String>>()
        )
    );
}

#[test]
fn test_key_value_pairs_quotes() {
    let res = key_value_pairs(b"BANDWIDTH=300000,CODECS=\"avc1.42c015,mp4a.40.2\"\r\nrest");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pairs() {
    let res = key_value_pairs(b"BANDWIDTH=300000,RESOLUTION=22x22,VIDEO=1\r\nrest=");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pair() {
    assert_eq!(
        key_value_pair(b"PROGRAM-ID=1,rest"),
        IResult::Done(
            "rest".as_bytes(),
            ("PROGRAM-ID".to_string(), "1".to_string())
        )
    );
}

#[test]
fn comment() {
    assert_eq!(
        comment_tag(b"#Hello\nxxx"),
        IResult::Done("xxx".as_bytes(), "Hello".to_string())
    );
}

#[test]
fn quotes() {
    assert_eq!(
        quoted(b"\"value\"rest"),
        IResult::Done("rest".as_bytes(), "value".to_string())
    );
}

#[test]
fn consume_empty_line() {
    let line = consume_line(b"\r\nrest");
    println!("{:?}", line);
}

#[test]
fn float_() {
    assert_eq!(
        float(b"33.22rest"),
        IResult::Done("rest".as_bytes(), 33.22f32)
    );
}

#[test]
fn float_no_decimal() {
    assert_eq!(
        float(b"33rest"),
        IResult::Done("rest".as_bytes(), 33f32)
    );
}

#[test]
fn float_should_ignore_trailing_dot() {
    assert_eq!(
        float(b"33.rest"),
        IResult::Done(".rest".as_bytes(), 33f32)
    );
}

#[test]
fn parse_duration_title() {
    assert_eq!(
        duration_title_tag(b"2.002,title\nrest"),
        IResult::Done("rest".as_bytes(), (2.002f32, Some("title".to_string())))
    );
}

// -----------------------------------------------------------------------------------------------
// Creating playlists

fn print_create_and_parse_playlist(playlist_original: &mut Playlist) -> Playlist {
    let mut utf8: Vec<u8> = Vec::new();
    playlist_original.write_to(&mut utf8).unwrap();

    let m3u8_str: &str = std::str::from_utf8(&utf8).unwrap();

    let playlist_parsed = match *playlist_original {
        Playlist::MasterPlaylist(_) =>
            Playlist::MasterPlaylist(parse_master_playlist_res(m3u8_str.as_bytes()).unwrap()),
        Playlist::MediaPlaylist(_) =>
            Playlist::MediaPlaylist(parse_media_playlist_res(m3u8_str.as_bytes()).unwrap()),
    };

    print!("\n\n---- utf8 result\n\n{}", m3u8_str);
    print!("\n---- Original\n\n{:?}", playlist_original);
    print!("\n\n---- Parsed\n\n{:?}\n\n", playlist_parsed);

    playlist_parsed
}

#[test]
fn create_and_parse_master_playlist_empty() {
    let mut playlist_original = Playlist::MasterPlaylist(MasterPlaylist { ..Default::default() });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_master_playlist_full() {

    let mut playlist_original = Playlist::MasterPlaylist(MasterPlaylist {
        version: 6,
        variants: vec![
            VariantStream {
                is_i_frame: false,
                uri: "masterplaylist-uri".into(),
                bandwidth: "10010010".into(),
                average_bandwidth: Some("10010010".into()),
                codecs: "TheCODEC".into(),
                resolution: Some("1000x3000".into()),
                frame_rate: Some("60".into()),
                audio: Some("audio".into()),
                video: Some("video".into()),
                subtitles: Some("subtitles".into()),
                closed_captions: Some("closed_captions".into()),
                alternatives: vec! [
                    AlternativeMedia {
                        media_type: AlternativeMediaType::Audio,
                        uri: Some("alt-media-uri".into()),
                        group_id: "group-id".into(),
                        language: Some("language".into()),
                        assoc_language: Some("assoc-language".into()),
                        name: "Xmedia".into(),
                        default: true, // Its absence indicates an implicit value of NO
                        autoselect: true, // Its absence indicates an implicit value of NO
                        forced: true, // Its absence indicates an implicit value of NO
                        instream_id: Some("instream_id".into()),
                        characteristics: Some("characteristics".into()),
                    }
                ]
            }
        ],
        session_data: Some(SessionData {
            data_id: "****".into(),
            value: "%%%%".into(),
            uri: "++++".into(),
            language: Some("SessionDataLanguage".into()),
        }),
        session_key: Some(SessionKey(Key {
            method: "AES-128".into(),
            uri: Some("https://secure.domain.com".into()),
            iv: Some("0xb059217aa2649ce170b734".into()),
            keyformat: Some("xXkeyformatXx".into()),
            keyformatversions: Some("xXFormatVers".into()),
        })),
        start: Some(Start {
            time_offset: "123123123".into(),
            precise: Some("YES".into()),
        }),
        independent_segments: true,
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_empty() {
    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist { ..Default::default() });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_single_segment() {
    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
        segments: vec![
            MediaSegment {
                uri: "20140311T113819-01-338559live.ts".into(),
                duration: 2.002,
                title: Some("hey".into()),
                ..Default::default()
            },
        ],
         ..Default::default()
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_full() {

    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
        version: 4,
        target_duration: 3.0,
        media_sequence: 338559,
        discontinuity_sequence: 1234,
        end_list: true,
        playlist_type: Some(MediaPlaylistType::Vod),
        i_frames_only: true,
        start: Some(Start {
            time_offset: "9999".into(),
            precise: Some("YES".into()),
        }),
        independent_segments: true,
        segments: vec![
            MediaSegment {
                uri: "20140311T113819-01-338559live.ts".into(),
                duration: 2.002,
                title: Some("338559".into()),
                byte_range: Some(ByteRange::from("137116@497036")),
                discontinuity: true,
                key: Some(Key {
                    method: "AES-128".into(),
                    uri: Some("https://secure.domain.com".into()),
                    iv: Some("0xb059217aa2649ce170b734".into()),
                    keyformat: Some("xXkeyformatXx".into()),
                    keyformatversions: Some("xXFormatVers".into()),
                }),
                map: Some(Map {
                    uri: "www.map-uri.com".into(),
                    byte_range: Some(ByteRange::from("137116@497036")),
                }),
                program_date_time: Some("broodlordinfestorgg".into()),
                daterange: None,
            },
        ],
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}<commit_msg>Make tests run on non-windows machines<commit_after>#![allow(unused_variables, unused_imports, dead_code)]

#[macro_use]
extern crate nom;
extern crate m3u8_rs;

use std::fs;
use std::path;
use m3u8_rs::*;
use m3u8_rs::playlist::*;
use std::io::Read;
use std::fs::File;
use nom::*;
use std::collections::HashMap;

fn all_sample_m3u_playlists() -> Vec<path::PathBuf> {
    let path: std::path::PathBuf = ["sample-playlists"].iter().collect();
    fs::read_dir(path.to_str().unwrap()).unwrap()
        .filter_map(Result::ok)
        .map(|dir| dir.path())
        .filter(|path| path.extension().map_or(false, |ext| ext == "m3u8"))
        .collect()
}

fn getm3u(path: &str) -> String {
    let mut buf = String::new();
    let mut file = fs::File::open(path).expect(&format!("Can't find m3u8: {}", path));
    let u = file.read_to_string(&mut buf).expect("Can't read file");
    buf
}

fn get_sample_playlist(name: &str) -> String {
    let path: std::path::PathBuf = ["sample-playlists", name].iter().collect();
    getm3u(path.to_str().unwrap())
}

// -----------------------------------------------------------------------------------------------
// Playlist

fn print_parse_playlist_test(playlist_name: &str) -> bool {
    let input: String = get_sample_playlist(playlist_name);
    println!("Parsing playlist file: {:?}", playlist_name);
    let parsed = parse_playlist(input.as_bytes());

    if let IResult::Done(i,o) = parsed {
        println!("{:?}", o);
        true
    }
    else {
        println!("Parsing failed:\n {:?}", parsed);
        false
    }
}

#[test]
fn playlist_master_with_alternatives() {
    assert!(print_parse_playlist_test("master-with-alternatives.m3u8"));
}

#[test]
fn playlist_master_with_i_frame_stream_inf() {
    assert!(print_parse_playlist_test("master-with-i-frame-stream-inf.m3u8"));
}

#[test]
fn playlist_master_with_multiple_codecs() {
    assert!(print_parse_playlist_test("master-with-multiple-codecs.m3u8"));
}

// -- Media playlists

#[test]
fn playlist_media_standard() {
    assert!(print_parse_playlist_test("mediaplaylist.m3u8"));
}

#[test]
fn playlist_media_without_segments() {
    assert!(print_parse_playlist_test("media-playlist-without-segments.m3u8"));
}

// -----------------------------------------------------------------------------------------------
// Playlist with no newline end

#[test]
fn playlist_not_ending_in_newline_master() {
    assert!(print_parse_playlist_test("master-not-ending-in-newline.m3u8"));
}

#[test]
fn playlist_not_ending_in_newline_media() {
    assert!(print_parse_playlist_test("media-not-ending-in-newline.m3u8"));
}

// -----------------------------------------------------------------------------------------------
// Playlist type detection tests

#[test]
fn playlist_type_is_master() {
    let input = get_sample_playlist("master.m3u8");
    let result = is_master_playlist(input.as_bytes());
    assert_eq!(true, result);
}

// #[test]
// fn playlist_type_with_unkown_tag() {
//     let input = get_sample_playlist("!!");
//     let result = is_master_playlist(input.as_bytes());
//     println!("Playlist_type_with_unkown_tag is master playlist: {:?}", result);
//     assert_eq!(true, result);
// }

#[test]
fn playlist_types() {
    for path_buf in all_sample_m3u_playlists() {
        let path = path_buf.to_str().unwrap();
        let input = getm3u(path);
        let is_master = is_master_playlist(input.as_bytes());

        assert!(path.to_lowercase().contains("master") == is_master);

        println!("{:?} = {:?}", path, is_master);
    }
}

// -----------------------------------------------------------------------------------------------
// Variant

#[test]
fn variant_stream() {
    let input = b"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"xxx\"\n";
    let result = variant_stream_tag(input);
    println!("{:?}", result);
}

// -----------------------------------------------------------------------------------------------
// Other

#[test]
fn test_key_value_pairs_trailing_equals() {
    let res = key_value_pairs(b"BANDWIDTH=395000,CODECS=\"avc1.4d001f,mp4a.40.2\"\r\nrest=");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pairs_multiple_quoted_values() {
    assert_eq!(
        key_value_pairs(b"BANDWIDTH=86000,URI=\"low/iframe.m3u8\",PROGRAM-ID=1,RESOLUTION=\"1x1\",VIDEO=1\nrest"),
        IResult::Done(
            "\nrest".as_bytes(),
            vec![
                ("BANDWIDTH".to_string(), "86000".to_string()),
                ("URI".to_string(), "low/iframe.m3u8".to_string()),
                ("PROGRAM-ID".to_string(), "1".to_string()),
                ("RESOLUTION".to_string(), "1x1".to_string()),
                ("VIDEO".to_string(), "1".to_string())
            ].into_iter().collect::<HashMap<String,String>>()
        )
    );
}

#[test]
fn test_key_value_pairs_quotes() {
    let res = key_value_pairs(b"BANDWIDTH=300000,CODECS=\"avc1.42c015,mp4a.40.2\"\r\nrest");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pairs() {
    let res = key_value_pairs(b"BANDWIDTH=300000,RESOLUTION=22x22,VIDEO=1\r\nrest=");
    println!("{:?}\n\n", res);
}

#[test]
fn test_key_value_pair() {
    assert_eq!(
        key_value_pair(b"PROGRAM-ID=1,rest"),
        IResult::Done(
            "rest".as_bytes(),
            ("PROGRAM-ID".to_string(), "1".to_string())
        )
    );
}

#[test]
fn comment() {
    assert_eq!(
        comment_tag(b"#Hello\nxxx"),
        IResult::Done("xxx".as_bytes(), "Hello".to_string())
    );
}

#[test]
fn quotes() {
    assert_eq!(
        quoted(b"\"value\"rest"),
        IResult::Done("rest".as_bytes(), "value".to_string())
    );
}

#[test]
fn consume_empty_line() {
    let line = consume_line(b"\r\nrest");
    println!("{:?}", line);
}

#[test]
fn float_() {
    assert_eq!(
        float(b"33.22rest"),
        IResult::Done("rest".as_bytes(), 33.22f32)
    );
}

#[test]
fn float_no_decimal() {
    assert_eq!(
        float(b"33rest"),
        IResult::Done("rest".as_bytes(), 33f32)
    );
}

#[test]
fn float_should_ignore_trailing_dot() {
    assert_eq!(
        float(b"33.rest"),
        IResult::Done(".rest".as_bytes(), 33f32)
    );
}

#[test]
fn parse_duration_title() {
    assert_eq!(
        duration_title_tag(b"2.002,title\nrest"),
        IResult::Done("rest".as_bytes(), (2.002f32, Some("title".to_string())))
    );
}

// -----------------------------------------------------------------------------------------------
// Creating playlists

fn print_create_and_parse_playlist(playlist_original: &mut Playlist) -> Playlist {
    let mut utf8: Vec<u8> = Vec::new();
    playlist_original.write_to(&mut utf8).unwrap();

    let m3u8_str: &str = std::str::from_utf8(&utf8).unwrap();

    let playlist_parsed = match *playlist_original {
        Playlist::MasterPlaylist(_) =>
            Playlist::MasterPlaylist(parse_master_playlist_res(m3u8_str.as_bytes()).unwrap()),
        Playlist::MediaPlaylist(_) =>
            Playlist::MediaPlaylist(parse_media_playlist_res(m3u8_str.as_bytes()).unwrap()),
    };

    print!("\n\n---- utf8 result\n\n{}", m3u8_str);
    print!("\n---- Original\n\n{:?}", playlist_original);
    print!("\n\n---- Parsed\n\n{:?}\n\n", playlist_parsed);

    playlist_parsed
}

#[test]
fn create_and_parse_master_playlist_empty() {
    let mut playlist_original = Playlist::MasterPlaylist(MasterPlaylist { ..Default::default() });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_master_playlist_full() {

    let mut playlist_original = Playlist::MasterPlaylist(MasterPlaylist {
        version: 6,
        variants: vec![
            VariantStream {
                is_i_frame: false,
                uri: "masterplaylist-uri".into(),
                bandwidth: "10010010".into(),
                average_bandwidth: Some("10010010".into()),
                codecs: "TheCODEC".into(),
                resolution: Some("1000x3000".into()),
                frame_rate: Some("60".into()),
                audio: Some("audio".into()),
                video: Some("video".into()),
                subtitles: Some("subtitles".into()),
                closed_captions: Some("closed_captions".into()),
                alternatives: vec! [
                    AlternativeMedia {
                        media_type: AlternativeMediaType::Audio,
                        uri: Some("alt-media-uri".into()),
                        group_id: "group-id".into(),
                        language: Some("language".into()),
                        assoc_language: Some("assoc-language".into()),
                        name: "Xmedia".into(),
                        default: true, // Its absence indicates an implicit value of NO
                        autoselect: true, // Its absence indicates an implicit value of NO
                        forced: true, // Its absence indicates an implicit value of NO
                        instream_id: Some("instream_id".into()),
                        characteristics: Some("characteristics".into()),
                    }
                ]
            }
        ],
        session_data: Some(SessionData {
            data_id: "****".into(),
            value: "%%%%".into(),
            uri: "++++".into(),
            language: Some("SessionDataLanguage".into()),
        }),
        session_key: Some(SessionKey(Key {
            method: "AES-128".into(),
            uri: Some("https://secure.domain.com".into()),
            iv: Some("0xb059217aa2649ce170b734".into()),
            keyformat: Some("xXkeyformatXx".into()),
            keyformatversions: Some("xXFormatVers".into()),
        })),
        start: Some(Start {
            time_offset: "123123123".into(),
            precise: Some("YES".into()),
        }),
        independent_segments: true,
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_empty() {
    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist { ..Default::default() });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_single_segment() {
    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
        segments: vec![
            MediaSegment {
                uri: "20140311T113819-01-338559live.ts".into(),
                duration: 2.002,
                title: Some("hey".into()),
                ..Default::default()
            },
        ],
         ..Default::default()
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}

#[test]
fn create_and_parse_media_playlist_full() {

    let mut playlist_original = Playlist::MediaPlaylist(MediaPlaylist {
        version: 4,
        target_duration: 3.0,
        media_sequence: 338559,
        discontinuity_sequence: 1234,
        end_list: true,
        playlist_type: Some(MediaPlaylistType::Vod),
        i_frames_only: true,
        start: Some(Start {
            time_offset: "9999".into(),
            precise: Some("YES".into()),
        }),
        independent_segments: true,
        segments: vec![
            MediaSegment {
                uri: "20140311T113819-01-338559live.ts".into(),
                duration: 2.002,
                title: Some("338559".into()),
                byte_range: Some(ByteRange::from("137116@497036")),
                discontinuity: true,
                key: Some(Key {
                    method: "AES-128".into(),
                    uri: Some("https://secure.domain.com".into()),
                    iv: Some("0xb059217aa2649ce170b734".into()),
                    keyformat: Some("xXkeyformatXx".into()),
                    keyformatversions: Some("xXFormatVers".into()),
                }),
                map: Some(Map {
                    uri: "www.map-uri.com".into(),
                    byte_range: Some(ByteRange::from("137116@497036")),
                }),
                program_date_time: Some("broodlordinfestorgg".into()),
                daterange: None,
            },
        ],
    });
    let playlist_parsed = print_create_and_parse_playlist(&mut playlist_original);
    assert_eq!(playlist_original, playlist_parsed);
}
<|endoftext|>