<commit_before>use iron::middleware::Handler;
use router::Router;
use std::collections::HashSet;

const DOC_RUST_LANG_ORG_REDIRECTS: &[&str] = &["alloc", "core", "proc_macro", "std", "test"];

pub(super) fn build_routes() -> Routes {
    let mut routes = Routes::new();

    routes.static_resource("/style.css", super::style_css_handler);
    routes.static_resource("/robots.txt", super::sitemap::robots_txt_handler);
    routes.static_resource("/sitemap.xml", super::sitemap::sitemap_handler);
    routes.static_resource("/opensearch.xml", super::opensearch_xml_handler);

    routes.internal_page("/", super::releases::home_page);

    routes.internal_page("/about", super::sitemap::about_handler);
    routes.internal_page("/about/metrics", super::metrics::metrics_handler);

    routes.internal_page("/releases", super::releases::recent_releases_handler);
    routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
    routes.internal_page("/releases/:author", super::releases::author_handler);
    routes.internal_page("/releases/:author/:page", super::releases::author_handler);
    routes.internal_page("/releases/activity", super::releases::activity_handler);
    routes.internal_page("/releases/search", super::releases::search_handler);
    routes.internal_page("/releases/queue", super::releases::build_queue_handler);
    routes.internal_page(
        "/releases/recent/:page",
        super::releases::recent_releases_handler,
    );
    routes.internal_page(
        "/releases/stars",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/stars/:page",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/recent-failures",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/recent-failures/:page",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/failures",
        super::releases::releases_failures_by_stars_handler,
    );
    routes.internal_page(
        "/releases/failures/:page",
        super::releases::releases_failures_by_stars_handler,
    );

    routes.internal_page("/crate/:name", super::crate_details::crate_details_handler);
    routes.internal_page(
        "/crate/:name/:version",
        super::crate_details::crate_details_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds",
        super::builds::build_list_handler,
    );
    routes.static_resource(
        "/crate/:name/:version/builds.json",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds/:id",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source",
        SimpleRedirect::new(|url| url.set_path(&format!("{}/", url.path()))),
    );
    routes.internal_page(
        "/crate/:name/:version/source/",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source/*",
        super::source::source_browser_handler,
    );

    routes.rustdoc_page("/:crate", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/badge.svg", super::rustdoc::badge_handler);
    routes.rustdoc_page(
        "/:crate/:version",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/settings.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/all.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/*.html",
        super::rustdoc::rustdoc_html_server_handler,
    );

    for redirect in DOC_RUST_LANG_ORG_REDIRECTS {
        routes.internal_page(
            &format!("/{}", redirect),
            super::rustdoc::RustLangRedirector::new(redirect),
        );
    }

    routes
}

pub(super) struct Routes {
    get: Vec<(String, Box<dyn Handler>)>,
    rustdoc_get: Vec<(String, Box<dyn Handler>)>,
    page_prefixes: HashSet<String>,
}

impl Routes {
    fn new() -> Self {
        Self {
            get: Vec::new(),
            rustdoc_get: Vec::new(),
            page_prefixes: HashSet::new(),
        }
    }

    pub(super) fn page_prefixes(&self) -> HashSet<String> {
        self.page_prefixes.clone()
    }

    pub(super) fn iron_router(mut self) -> Router {
        let mut router = Router::new();
        for (pattern, handler) in self.get.drain(..) {
            router.get(&pattern, handler, calculate_id(&pattern));
        }

        // All rustdoc pages have the prefixes of other docs.rs pages blacklisted. This prevents,
        // for example, a crate named "about" from hijacking /about/0.1.0/index.html.
        let blacklist = self.page_prefixes();
        for (pattern, handler) in self.rustdoc_get.drain(..) {
            router.get(
                &pattern,
                BlockBlacklistedPrefixes::new(blacklist.clone(), handler),
                calculate_id(&pattern),
            );
        }

        router
    }

    /// A static resource is a normal page without any special behavior on the router side.
    fn static_resource(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));
    }

    /// Internal pages are docs.rs's own pages, instead of the documentation of a crate uploaded by
    /// an user. The router adds these extra things when adding a new internal page:
    ///
    /// - The first component of the page's URL will be registered as a "page prefix". Page
    /// prefixes are blacklisted by rustdoc pages, to prevent a crate named the same as a prefix
    /// from hijacking docs.rs's own URLs.
    ///
    /// - If the page URL doesn't end with a slash, a redirect from the URL with the trailing slash
    /// to the one without is automatically added.
    fn internal_page(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));

        // Automatically add another route ending with / that redirects to the slash-less route.
        if !pattern.ends_with('/') {
            let pattern = format!("{}/", pattern);
            self.get.push((
                pattern.to_string(),
                Box::new(SimpleRedirect::new(|url| {
                    url.set_path(&url.path().trim_end_matches('/').to_string())
                })),
            ));
        }

        // Register the prefix if it's not the home page and the first path component is not a
        // pattern or a wildcard.
        if pattern != "/" {
            if let Some(first_component) = pattern.trim_matches('/').split('/').next() {
                if !first_component.contains('*') && !first_component.starts_with(':') {
                    self.page_prefixes.insert(first_component.to_string());
                }
            }
        }
    }

    /// A rustdoc page is a page serving generated documentation. It's similar to a static
    /// resource, but path prefixes are automatically blacklisted (see internal pages to learn more
    /// about page prefixes).
    fn rustdoc_page(&mut self, pattern: &str, handler: impl Handler) {
        self.rustdoc_get
            .push((pattern.to_string(), Box::new(handler)));
    }
}

#[derive(Copy, Clone)]
struct SimpleRedirect {
    url_mangler: fn(&mut iron::url::Url),
}

impl SimpleRedirect {
    fn new(url_mangler: fn(&mut iron::url::Url)) -> Self {
        Self { url_mangler }
    }
}

impl Handler for SimpleRedirect {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        let mut url: iron::url::Url = req.url.clone().into();
        (self.url_mangler)(&mut url);
        Ok(iron::Response::with((
            iron::status::Found,
            iron::modifiers::Redirect(iron::Url::parse(&url.to_string()).unwrap()),
        )))
    }
}

/// Iron Middleware that prevents requests to blacklisted prefixes.
///
/// In our application, a prefix is blacklisted if a docs.rs page exists below it. For example,
/// since /releases/queue is a docs.rs page, /releases is a blacklisted prefix.
///
/// The middleware must be used for all the pages serving crates at the top level, to prevent a
/// crate from putting their own content in an URL that's supposed to be used by docs.rs.
pub(super) struct BlockBlacklistedPrefixes {
    blacklist: HashSet<String>,
    handler: Box<dyn Handler>,
}

impl BlockBlacklistedPrefixes {
    pub(super) fn new(blacklist: HashSet<String>, handler: Box<dyn Handler>) -> Self {
        Self { blacklist, handler }
    }
}

impl Handler for BlockBlacklistedPrefixes {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        if let Some(prefix) = req.url.path().get(0) {
            if self.blacklist.contains(*prefix) {
                return Err(iron::IronError::new(
                    super::error::Nope::CrateNotFound,
                    iron::status::NotFound,
                ));
            }
        }
        self.handler.handle(req)
    }
}

/// Automatically generate a Route ID from a pattern. Every non-alphanumeric character is replaced
/// with `_`.
fn calculate_id(pattern: &str) -> String {
    pattern
        .chars()
        .map(|c| if c.is_alphanumeric() { c } else { '_' })
        .collect()
}
<commit_msg>web: add more comments to Routes<commit_after>use iron::middleware::Handler;
use router::Router;
use std::collections::HashSet;

const DOC_RUST_LANG_ORG_REDIRECTS: &[&str] = &["alloc", "core", "proc_macro", "std", "test"];

pub(super) fn build_routes() -> Routes {
    let mut routes = Routes::new();

    routes.static_resource("/style.css", super::style_css_handler);
    routes.static_resource("/robots.txt", super::sitemap::robots_txt_handler);
    routes.static_resource("/sitemap.xml", super::sitemap::sitemap_handler);
    routes.static_resource("/opensearch.xml", super::opensearch_xml_handler);

    routes.internal_page("/", super::releases::home_page);

    routes.internal_page("/about", super::sitemap::about_handler);
    routes.internal_page("/about/metrics", super::metrics::metrics_handler);

    routes.internal_page("/releases", super::releases::recent_releases_handler);
    routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
    routes.internal_page("/releases/:author", super::releases::author_handler);
    routes.internal_page("/releases/:author/:page", super::releases::author_handler);
    routes.internal_page("/releases/activity", super::releases::activity_handler);
    routes.internal_page("/releases/search", super::releases::search_handler);
    routes.internal_page("/releases/queue", super::releases::build_queue_handler);
    routes.internal_page(
        "/releases/recent/:page",
        super::releases::recent_releases_handler,
    );
    routes.internal_page(
        "/releases/stars",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/stars/:page",
        super::releases::releases_by_stars_handler,
    );
    routes.internal_page(
        "/releases/recent-failures",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/recent-failures/:page",
        super::releases::releases_recent_failures_handler,
    );
    routes.internal_page(
        "/releases/failures",
        super::releases::releases_failures_by_stars_handler,
    );
    routes.internal_page(
        "/releases/failures/:page",
        super::releases::releases_failures_by_stars_handler,
    );

    routes.internal_page("/crate/:name", super::crate_details::crate_details_handler);
    routes.internal_page(
        "/crate/:name/:version",
        super::crate_details::crate_details_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds",
        super::builds::build_list_handler,
    );
    routes.static_resource(
        "/crate/:name/:version/builds.json",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/builds/:id",
        super::builds::build_list_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source",
        SimpleRedirect::new(|url| url.set_path(&format!("{}/", url.path()))),
    );
    routes.internal_page(
        "/crate/:name/:version/source/",
        super::source::source_browser_handler,
    );
    routes.internal_page(
        "/crate/:name/:version/source/*",
        super::source::source_browser_handler,
    );

    routes.rustdoc_page("/:crate", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/", super::rustdoc::rustdoc_redirector_handler);
    routes.rustdoc_page("/:crate/badge.svg", super::rustdoc::badge_handler);
    routes.rustdoc_page(
        "/:crate/:version",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/settings.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/all.html",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target",
        super::rustdoc::rustdoc_redirector_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/",
        super::rustdoc::rustdoc_html_server_handler,
    );
    routes.rustdoc_page(
        "/:crate/:version/:target/*.html",
        super::rustdoc::rustdoc_html_server_handler,
    );

    for redirect in DOC_RUST_LANG_ORG_REDIRECTS {
        routes.internal_page(
            &format!("/{}", redirect),
            super::rustdoc::RustLangRedirector::new(redirect),
        );
    }

    routes
}

/// This wrapper class aids the construction of iron's Router, with docs.rs-specific additions to
/// it. Routes are supposed to be added by the build_routes function, which calls methods in this
/// struct depending on the type of route being added.
pub(super) struct Routes {
    /// Normal GET routes.
    get: Vec<(String, Box<dyn Handler>)>,
    /// GET routes serving rustdoc content. The BlockBlacklistedPrefixes middleware is added
    /// automatically to all of them.
    rustdoc_get: Vec<(String, Box<dyn Handler>)>,
    /// Prefixes of all the internal routes. This data is used to power the
    /// BlockBlacklistedPrefixes middleware.
    page_prefixes: HashSet<String>,
}

impl Routes {
    fn new() -> Self {
        Self {
            get: Vec::new(),
            rustdoc_get: Vec::new(),
            page_prefixes: HashSet::new(),
        }
    }

    pub(super) fn page_prefixes(&self) -> HashSet<String> {
        self.page_prefixes.clone()
    }

    pub(super) fn iron_router(mut self) -> Router {
        let mut router = Router::new();
        for (pattern, handler) in self.get.drain(..) {
            router.get(&pattern, handler, calculate_id(&pattern));
        }

        // All rustdoc pages have the prefixes of other docs.rs pages blacklisted. This prevents,
        // for example, a crate named "about" from hijacking /about/0.1.0/index.html.
        let blacklist = self.page_prefixes();
        for (pattern, handler) in self.rustdoc_get.drain(..) {
            router.get(
                &pattern,
                BlockBlacklistedPrefixes::new(blacklist.clone(), handler),
                calculate_id(&pattern),
            );
        }

        router
    }

    /// A static resource is a normal page without any special behavior on the router side.
    fn static_resource(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));
    }

    /// Internal pages are docs.rs's own pages, instead of the documentation of a crate uploaded by
    /// an user. The router adds these extra things when adding a new internal page:
    ///
    /// - The first component of the page's URL will be registered as a "page prefix". Page
    /// prefixes are blacklisted by rustdoc pages, to prevent a crate named the same as a prefix
    /// from hijacking docs.rs's own URLs.
    ///
    /// - If the page URL doesn't end with a slash, a redirect from the URL with the trailing slash
    /// to the one without is automatically added.
    fn internal_page(&mut self, pattern: &str, handler: impl Handler) {
        self.get.push((pattern.to_string(), Box::new(handler)));

        // Automatically add another route ending with / that redirects to the slash-less route.
        if !pattern.ends_with('/') {
            let pattern = format!("{}/", pattern);
            self.get.push((
                pattern.to_string(),
                Box::new(SimpleRedirect::new(|url| {
                    url.set_path(&url.path().trim_end_matches('/').to_string())
                })),
            ));
        }

        // Register the prefix if it's not the home page and the first path component is not a
        // pattern or a wildcard.
        if pattern != "/" {
            if let Some(first_component) = pattern.trim_matches('/').split('/').next() {
                if !first_component.contains('*') && !first_component.starts_with(':') {
                    self.page_prefixes.insert(first_component.to_string());
                }
            }
        }
    }

    /// A rustdoc page is a page serving generated documentation. It's similar to a static
    /// resource, but path prefixes are automatically blacklisted (see internal pages to learn more
    /// about page prefixes).
    fn rustdoc_page(&mut self, pattern: &str, handler: impl Handler) {
        self.rustdoc_get
            .push((pattern.to_string(), Box::new(handler)));
    }
}

#[derive(Copy, Clone)]
struct SimpleRedirect {
    url_mangler: fn(&mut iron::url::Url),
}

impl SimpleRedirect {
    fn new(url_mangler: fn(&mut iron::url::Url)) -> Self {
        Self { url_mangler }
    }
}

impl Handler for SimpleRedirect {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        let mut url: iron::url::Url = req.url.clone().into();
        (self.url_mangler)(&mut url);
        Ok(iron::Response::with((
            iron::status::Found,
            iron::modifiers::Redirect(iron::Url::parse(&url.to_string()).unwrap()),
        )))
    }
}

/// Iron Middleware that prevents requests to blacklisted prefixes.
///
/// In our application, a prefix is blacklisted if a docs.rs page exists below it. For example,
/// since /releases/queue is a docs.rs page, /releases is a blacklisted prefix.
///
/// The middleware must be used for all the pages serving crates at the top level, to prevent a
/// crate from putting their own content in an URL that's supposed to be used by docs.rs.
pub(super) struct BlockBlacklistedPrefixes {
    blacklist: HashSet<String>,
    handler: Box<dyn Handler>,
}

impl BlockBlacklistedPrefixes {
    pub(super) fn new(blacklist: HashSet<String>, handler: Box<dyn Handler>) -> Self {
        Self { blacklist, handler }
    }
}

impl Handler for BlockBlacklistedPrefixes {
    fn handle(&self, req: &mut iron::Request) -> iron::IronResult<iron::Response> {
        if let Some(prefix) = req.url.path().get(0) {
            if self.blacklist.contains(*prefix) {
                return Err(iron::IronError::new(
                    super::error::Nope::CrateNotFound,
                    iron::status::NotFound,
                ));
            }
        }
        self.handler.handle(req)
    }
}

/// Automatically generate a Route ID from a pattern. Every non-alphanumeric character is replaced
/// with `_`.
fn calculate_id(pattern: &str) -> String {
    pattern
        .chars()
        .map(|c| if c.is_alphanumeric() { c } else { '_' })
        .collect()
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::result;

// TODO use ::diag;
use ::front::ast;

pub type Result<'a, T> = result::Result<T, TypeError<'a>>;

pub struct Context<'a> {
    pub current: &'a ast::Node<ast::Function>,
    pub functions: &'a ast::Functions,
}

pub fn deduce<'a>(ctx: &Context, expr: &'a ast::Node<ast::Expression>) -> Result<'a, ast::Type> {
    match expr.node {
        ast::Expression::Literal { ref lit } => Ok(lit.get_type()),

        ast::Expression::Variable { ref var } => Ok(var.type_),

        ast::Expression::Call { ref function, .. } => {
            // check if call is valid (argument count and types)
            try!(check_call(ctx, expr));

            // use target function's return type
            Ok(ctx.functions.get(function).expect("call to unknown function").node.ret_type)
        }

        ast::Expression::Unary { ref op, ref expr } => {
            let e = try!(deduce(ctx, expr));
            match *op {
                ast::UnaryOp::NOT if e == ast::Type::Bool => Ok(e),

                ast::UnaryOp::MINUS if [ast::Type::Int, ast::Type::Float].contains(&e) => Ok(e),

                _ => {
                    Err(TypeError::UnsupportedOperator {
                        expr: expr,
                        op: ast::Op::UnaryOp(*op),
                        type_: e,
                    })
                }
            }
        }

        ast::Expression::Binary { ref op, ref left, ref right } => {
            let t = try!(deduce(ctx, left));

            try!(expect(ctx, right, t));

            match *op {
                // `+`, `-`, `*`, `/` supported for numbers
                ast::BinaryOp::ADD | ast::BinaryOp::SUB | ast::BinaryOp::MUL |
                ast::BinaryOp::DIV if [ast::Type::Int, ast::Type::Float].contains(&t) => Ok(t),

                // `<`, `<=` supported for numbers
                ast::BinaryOp::LT | ast::BinaryOp::LE if [ast::Type::Int, ast::Type::Float]
                    .contains(&t) => Ok(t),

                // `==` supported for bool and numbers
                ast::BinaryOp::EQ if [ast::Type::Bool, ast::Type::Int, ast::Type::Float]
                    .contains(&t) => Ok(ast::Type::Bool),

                _ => {
                    Err(TypeError::UnsupportedOperator {
                        expr: expr,
                        op: ast::Op::BinaryOp(*op),
                        type_: t,
                    })
                }
            }
        }

        ast::Expression::Parenthesis { ref expr } => deduce(ctx, expr),
    }
}

pub fn expect<'a>(ctx: &Context,
                  expr: &'a ast::Node<ast::Expression>,
                  expected: ast::Type)
                  -> Result<'a, ()> {
    let deduced = try!(deduce(ctx, expr));
    if deduced != expected {
        Err(TypeError::TypeMismatch {
            expr: expr,
            expected: expected,
            actual: deduced,
        })
    } else {
        Ok(())
    }
}

pub fn check_function<'a>(ctx: &Context<'a>) -> Result<'a, ()> {
    check_statement(ctx, &ctx.current.node.body)
}

pub fn check_statement<'a>(ctx: &Context, stmt: &'a ast::Node<ast::Statement>) -> Result<'a, ()> {
    match stmt.node {
        ast::Statement::Assignment { ref var, ref expr } => expect(ctx, expr, var.type_),

        ast::Statement::Return { ref expr } => {
            if let Some(ref expr) = *expr {
                expect(ctx, expr, ctx.current.node.ret_type)
            } else if ctx.current.node.ret_type != ast::Type::Void {
                Err(TypeError::InvalidReturnValue { stmt: stmt })
            } else {
                Ok(())
            }
        }

        ast::Statement::If { ref cond, ref on_true, ref on_false } => {
            try!(expect(ctx, cond, ast::Type::Bool));
            try!(check_statement(ctx, on_true));
            if let Some(ref stmt) = *on_false {
                try!(check_statement(ctx, stmt));
            }
            Ok(())
        }

        ast::Statement::While { ref cond, ref body } => {
            try!(expect(ctx, cond, ast::Type::Bool));
            check_statement(ctx, body)
        }

        ast::Statement::Compound { ref stmts, .. } => {
            for stmt in stmts {
                try!(check_statement(ctx, stmt));
            }
            Ok(())
        }
        _ => Ok(()),
    }
}

pub fn check_call<'a>(ctx: &Context, expr: &'a ast::Node<ast::Expression>) -> Result<'a, ()> {
    match expr.node {
        ast::Expression::Call { ref function, ref args } => {
            // call target checks should be done in a previous phase
            let target = &ctx.functions.get(function).expect("call to unknown function").node;

            // check count
            if target.args.len() != args.len() {
                return Err(TypeError::WrongArgumentCount {
                    call: expr,
                    expected: target.args.len(),
                    actual: args.len(),
                });
            }

            for (target_arg, arg) in target.args.iter().zip(args.iter()) {
                // check type
                try!(expect(ctx, arg, target_arg.type_))
            }
            Ok(())
        }

        // don't care about other nodes
        _ => Ok(()),
    }
}

#[derive(PartialEq, Debug)]
pub enum TypeError<'a> {
    TypeMismatch {
        expr: &'a ast::Node<ast::Expression>,
        expected: ast::Type,
        actual: ast::Type,
    },
    WrongArgumentCount {
        call: &'a ast::Node<ast::Expression>,
        expected: usize,
        actual: usize,
    },
    UnsupportedOperator {
        expr: &'a ast::Node<ast::Expression>,
        op: ast::Op,
        type_: ast::Type,
    },
    InvalidReturnValue {
        stmt: &'a ast::Node<ast::Statement>,
    },
}

impl<'a> fmt::Display for TypeError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TypeError::TypeMismatch { ref expr, ref expected, ref actual } => {
                write!(f,
                       "{}.{} TypeMismatch: expected `{:?}` got `{:?}`",
                       expr.pos.line,
                       expr.pos.col,
                       expected,
                       actual)
            }
            TypeError::WrongArgumentCount { ref call, ref expected, ref actual } => {
                write!(f,
                       "{}.{} WrongArgumentCount: expected `{}` got `{}`",
                       call.pos.line,
                       call.pos.col,
                       expected,
                       actual)
            }
            TypeError::UnsupportedOperator { ref expr, ref op, ref type_ } => {
                write!(f,
                       "{}.{} UnsupportedOperator: `{:?}` for `{:?}`",
                       expr.pos.line,
                       expr.pos.col,
                       op,
                       type_)
            }
            TypeError::InvalidReturnValue { ref stmt } => {
                write!(f,
                       "{}.{} InvalidReturnValue: Return value given in void function",
                       stmt.pos.line,
                       stmt.pos.col)
            }
        }
    }
}

impl<'a> Error for TypeError<'a> {
    fn description(&self) -> &str {
        match *self {
            TypeError::TypeMismatch { .. } => "encountered unexpected type",
            TypeError::WrongArgumentCount { .. } => "number of arguments does not match",
            TypeError::UnsupportedOperator { .. } => "operator cannot be used with given type",
            TypeError::InvalidReturnValue { .. } => "return value given in void function",
        }
    }
}
<commit_msg>Analysis: Fix type deduction error<commit_after>use std::error::Error;
use std::fmt;
use std::result;

// TODO use ::diag;
use ::front::ast;

pub type Result<'a, T> = result::Result<T, TypeError<'a>>;

pub struct Context<'a> {
    pub current: &'a ast::Node<ast::Function>,
    pub functions: &'a ast::Functions,
}

pub fn deduce<'a>(ctx: &Context, expr: &'a ast::Node<ast::Expression>) -> Result<'a, ast::Type> {
    match expr.node {
        ast::Expression::Literal { ref lit } => Ok(lit.get_type()),

        ast::Expression::Variable { ref var } => Ok(var.type_),

        ast::Expression::Call { ref function, .. } => {
            // check if call is valid (argument count and types)
            try!(check_call(ctx, expr));

            // use target function's return type
            Ok(ctx.functions.get(function).expect("call to unknown function").node.ret_type)
        }

        ast::Expression::Unary { ref op, ref expr } => {
            let e = try!(deduce(ctx, expr));
            match *op {
                ast::UnaryOp::NOT if e == ast::Type::Bool => Ok(e),

                ast::UnaryOp::MINUS if [ast::Type::Int, ast::Type::Float].contains(&e) => Ok(e),

                _ => {
                    Err(TypeError::UnsupportedOperator {
                        expr: expr,
                        op: ast::Op::UnaryOp(*op),
                        type_: e,
                    })
                }
            }
        }

        ast::Expression::Binary { ref op, ref left, ref right } => {
            let t = try!(deduce(ctx, left));

            try!(expect(ctx, right, t));

            match *op {
                // `+`, `-`, `*`, `/` supported for numbers
                ast::BinaryOp::ADD | ast::BinaryOp::SUB | ast::BinaryOp::MUL |
                ast::BinaryOp::DIV if [ast::Type::Int, ast::Type::Float].contains(&t) => Ok(t),

                // `<`, `<=` supported for numbers
                ast::BinaryOp::LT | ast::BinaryOp::LE if [ast::Type::Int, ast::Type::Float]
                    .contains(&t) => Ok(ast::Type::Bool),

                // `==` supported for bool and numbers
                ast::BinaryOp::EQ if [ast::Type::Bool, ast::Type::Int, ast::Type::Float]
                    .contains(&t) => Ok(ast::Type::Bool),

                _ => {
                    Err(TypeError::UnsupportedOperator {
                        expr: expr,
                        op: ast::Op::BinaryOp(*op),
                        type_: t,
                    })
                }
            }
        }

        ast::Expression::Parenthesis { ref expr } => deduce(ctx, expr),
    }
}

pub fn expect<'a>(ctx: &Context,
                  expr: &'a ast::Node<ast::Expression>,
                  expected: ast::Type)
                  -> Result<'a, ()> {
    let deduced = try!(deduce(ctx, expr));
    if deduced != expected {
        Err(TypeError::TypeMismatch {
            expr: expr,
            expected: expected,
            actual: deduced,
        })
    } else {
        Ok(())
    }
}

pub fn check_function<'a>(ctx: &Context<'a>) -> Result<'a, ()> {
    check_statement(ctx, &ctx.current.node.body)
}

pub fn check_statement<'a>(ctx: &Context, stmt: &'a ast::Node<ast::Statement>) -> Result<'a, ()> {
    match stmt.node {
        ast::Statement::Assignment { ref var, ref expr } => expect(ctx, expr, var.type_),

        ast::Statement::Return { ref expr } => {
            if let Some(ref expr) = *expr {
                expect(ctx, expr, ctx.current.node.ret_type)
            } else if ctx.current.node.ret_type != ast::Type::Void {
                Err(TypeError::InvalidReturnValue { stmt: stmt })
            } else {
                Ok(())
            }
        }

        ast::Statement::If { ref cond, ref on_true, ref on_false } => {
            try!(expect(ctx, cond, ast::Type::Bool));
            try!(check_statement(ctx, on_true));
            if let Some(ref stmt) = *on_false {
                try!(check_statement(ctx, stmt));
            }
            Ok(())
        }

        ast::Statement::While { ref cond, ref body } => {
            try!(expect(ctx, cond, ast::Type::Bool));
            check_statement(ctx, body)
        }

        ast::Statement::Compound { ref stmts, .. } => {
            for stmt in stmts {
                try!(check_statement(ctx, stmt));
            }
            Ok(())
        }
        _ => Ok(()),
    }
}

pub fn check_call<'a>(ctx: &Context, expr: &'a ast::Node<ast::Expression>) -> Result<'a, ()> {
    match expr.node {
        ast::Expression::Call { ref function, ref args } => {
            // call target checks should be done in a previous phase
            let target = &ctx.functions.get(function).expect("call to unknown function").node;

            // check count
            if target.args.len() != args.len() {
                return Err(TypeError::WrongArgumentCount {
                    call: expr,
                    expected: target.args.len(),
                    actual: args.len(),
                });
            }

            for (target_arg, arg) in target.args.iter().zip(args.iter()) {
                // check type
                try!(expect(ctx, arg, target_arg.type_))
            }
            Ok(())
        }

        // don't care about other nodes
        _ => Ok(()),
    }
}

#[derive(PartialEq, Debug)]
pub enum TypeError<'a> {
    TypeMismatch {
        expr: &'a ast::Node<ast::Expression>,
        expected: ast::Type,
        actual: ast::Type,
    },
    WrongArgumentCount {
        call: &'a ast::Node<ast::Expression>,
        expected: usize,
        actual: usize,
    },
    UnsupportedOperator {
        expr: &'a ast::Node<ast::Expression>,
        op: ast::Op,
        type_: ast::Type,
    },
    InvalidReturnValue {
        stmt: &'a ast::Node<ast::Statement>,
    },
}

impl<'a> fmt::Display for TypeError<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TypeError::TypeMismatch { ref expr, ref expected, ref actual } => {
                write!(f,
                       "{}.{} TypeMismatch: expected `{:?}` got `{:?}`",
                       expr.pos.line,
                       expr.pos.col,
                       expected,
                       actual)
            }
            TypeError::WrongArgumentCount { ref call, ref expected, ref actual } => {
                write!(f,
                       "{}.{} WrongArgumentCount: expected `{}` got `{}`",
                       call.pos.line,
                       call.pos.col,
                       expected,
                       actual)
            }
            TypeError::UnsupportedOperator { ref expr, ref op, ref type_ } => {
                write!(f,
                       "{}.{} UnsupportedOperator: `{:?}` for `{:?}`",
                       expr.pos.line,
                       expr.pos.col,
                       op,
                       type_)
            }
            TypeError::InvalidReturnValue { ref stmt } => {
                write!(f,
                       "{}.{} InvalidReturnValue: Return value given in void function",
                       stmt.pos.line,
                       stmt.pos.col)
            }
        }
    }
}

impl<'a> Error for TypeError<'a> {
    fn description(&self) -> &str {
        match *self {
            TypeError::TypeMismatch { .. } => "encountered unexpected type",
            TypeError::WrongArgumentCount { .. } => "number of arguments does not match",
            TypeError::UnsupportedOperator { .. } => "operator cannot be used with given type",
            TypeError::InvalidReturnValue { .. } => "return value given in void function",
        }
    }
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::fmt;
use core::fmt::Show;

use opengles::gl2;
use opengles::gl2::GLuint;

use glcommon::{check_gl_error, GLResult, FillDefaults, Defaults};

use log::logi;

use collections::vec::Vec;

#[deriving(PartialEq, Eq, Hash, Show)]
pub enum PixelFormat {
    RGBA = gl2::RGBA as int,
    RGB = gl2::RGB as int,
    ALPHA = gl2::ALPHA as int,
}

pub trait ToPixelFormat {
    fn to_pixelformat(&self) -> GLResult<PixelFormat>;
}

pub struct Texture {
    pub texture: GLuint,
    pub dimensions: (i32, i32),
}

pub struct BrushTexture {
    pub texture: Texture,
    pub source: (PixelFormat, (i32, i32), Vec<u8>),
}

impl Texture {
    pub fn new() -> Texture {
        let texture = gl2::gen_textures(1)[0];
        check_gl_error("gen_textures");
        Texture { texture: texture, dimensions: (0, 0) }
    }
    pub fn with_image(w: i32, h: i32, bytes: Option<&[u8]>, format: PixelFormat) -> Texture {
        let mut texture = Texture::new();
        texture.set_image(w, h, bytes, format);
        texture
    }

    pub fn set_image(&mut self, w: i32, h: i32, bytes: Option<&[u8]>, format: PixelFormat) {
        gl2::bind_texture(gl2::TEXTURE_2D, self.texture);
        check_gl_error("Texture.set_image bind_texture");
        gl2::tex_image_2d(gl2::TEXTURE_2D, 0, format as i32, w, h, 0, format as GLuint, gl2::UNSIGNED_BYTE, bytes);
        check_gl_error("Texture.set_image tex_image_2d");

        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_S, gl2::CLAMP_TO_EDGE as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_T, gl2::CLAMP_TO_EDGE as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MIN_FILTER, gl2::NEAREST as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MAG_FILTER, gl2::NEAREST as i32);
        check_gl_error("Texture.set_image tex_parameter_i");
        self.dimensions = (w,h);
    }
}

impl Drop for Texture {
    fn drop(&mut self) {
        gl2::delete_textures([self.texture].as_slice());
        logi!("deleted {} texture", self.dimensions);
    }
}

impl Show for Texture {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "texture 0x{:x}, dimensions {}", self.texture, self.dimensions)
    }
}

impl FillDefaults<(PixelFormat, (i32, i32), Vec<u8>), (PixelFormat, (i32, i32), Vec<u8>), BrushTexture> for BrushTexture {
    fn fill_defaults(init: (PixelFormat, (i32, i32), Vec<u8>)) -> Defaults<(PixelFormat, (i32, i32), Vec<u8>), BrushTexture> {
        Defaults { val: init }
    }
}
<commit_msg>impl Show for gltexture<commit_after>use core::prelude::*;
use core::fmt;
use core::fmt::Show;

use opengles::gl2;
use opengles::gl2::GLuint;

use glcommon::{check_gl_error, GLResult, FillDefaults, Defaults};

use log::logi;

use collections::vec::Vec;

#[deriving(PartialEq, Eq, Hash, Show)]
pub enum PixelFormat {
    RGBA = gl2::RGBA as int,
    RGB = gl2::RGB as int,
    ALPHA = gl2::ALPHA as int,
}

pub trait ToPixelFormat {
    fn to_pixelformat(&self) -> GLResult<PixelFormat>;
}

pub struct Texture {
    pub texture: GLuint,
    pub dimensions: (i32, i32),
}

pub struct BrushTexture {
    pub texture: Texture,
    pub source: (PixelFormat, (i32, i32), Vec<u8>),
}

impl Texture {
    pub fn new() -> Texture {
        let texture = gl2::gen_textures(1)[0];
        check_gl_error("gen_textures");
        Texture { texture: texture, dimensions: (0, 0) }
    }
    pub fn with_image(w: i32, h: i32, bytes: Option<&[u8]>, format: PixelFormat) -> Texture {
        let mut texture = Texture::new();
        texture.set_image(w, h, bytes, format);
        texture
    }

    pub fn set_image(&mut self, w: i32, h: i32, bytes: Option<&[u8]>, format: PixelFormat) {
        gl2::bind_texture(gl2::TEXTURE_2D, self.texture);
        check_gl_error("Texture.set_image bind_texture");
        gl2::tex_image_2d(gl2::TEXTURE_2D, 0, format as i32, w, h, 0, format as GLuint, gl2::UNSIGNED_BYTE, bytes);
        check_gl_error("Texture.set_image tex_image_2d");

        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_S, gl2::CLAMP_TO_EDGE as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_T, gl2::CLAMP_TO_EDGE as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MIN_FILTER, gl2::NEAREST as i32);
        gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MAG_FILTER, gl2::NEAREST as i32);
        check_gl_error("Texture.set_image tex_parameter_i");
        self.dimensions = (w,h);
    }
}

impl Drop for Texture {
    fn drop(&mut self) {
        gl2::delete_textures([self.texture].as_slice());
        logi!("deleted {} texture", self.dimensions);
    }
}

impl Show for Texture {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "texture 0x{:x}, dimensions {}", self.texture, self.dimensions)
    }
}

impl Show for BrushTexture {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "brushtexture 0x{:x}, dimensions {}", self.texture.texture, self.texture.dimensions)
    }
}

impl FillDefaults<(PixelFormat, (i32, i32), Vec<u8>), (PixelFormat, (i32, i32), Vec<u8>), BrushTexture> for BrushTexture {
    fn fill_defaults(init: (PixelFormat, (i32, i32), Vec<u8>)) -> Defaults<(PixelFormat, (i32, i32), Vec<u8>), BrushTexture> {
        Defaults { val: init }
    }
}
<|endoftext|>


<commit_before>use super::EndOffset;
use byteorder::{BigEndian, ByteOrder};
use headers::MacHeader;
use std::convert::From;
use std::default::Default;
use std::fmt;
use std::net::Ipv4Addr;
use std::slice;
use utils::Flow;

/// IP header using SSE
#[derive(Debug, Default)]
#[repr(C,packed)]
pub struct IpHeader {
    version_to_len: u32,
    id_to_foffset: u32,
    ttl_to_csum: u32,
    src_ip: u32,
    dst_ip: u32,
}

impl fmt::Display for IpHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let src = Ipv4Addr::from(self.src());
        let dst = Ipv4Addr::from(self.dst());
        write!(f,
               "{} > {} version: {} ihl: {} len: {} ttl: {} proto: {} csum: {}",
               src,
               dst,
               self.version(),
               self.ihl(),
               self.length(),
               self.ttl(),
               self.protocol(),
               self.csum())
    }
}

impl EndOffset for IpHeader {
    type PreviousHeader = MacHeader;
    #[inline]
    fn offset(&self) -> usize {
        if cfg!(feature = "performance") {
            20
        } else {
            self.ihl() as usize * 4
        }
    }

    #[inline]
    fn size() -> usize {
        // The struct itself is always 20 bytes.
        20
    }

    #[inline]
    fn payload_size(&self, _: usize) -> usize {
        (self.length() as usize) - self.offset()
    }

    #[inline]
    fn check_correct(&self, _prev: &MacHeader) -> bool {
        true
    }
}

impl IpHeader {
    #[inline]
    pub fn flow(&self) -> Option<Flow> {
        let protocol = self.protocol();
        let src_ip = self.src();
        let dst_ip = self.dst();
        if (protocol == 6 || protocol == 17) && self.payload_size(0) >= 32 {
            unsafe {
                let self_as_u8 = (self as *const IpHeader) as *const u8;
                let port_as_u8 = self_as_u8.offset(self.offset() as isize);
                let port_slice = slice::from_raw_parts(port_as_u8, 32);
                let dst_port = BigEndian::read_u16(&port_slice[..16]);
                let src_port = BigEndian::read_u16(&port_slice[16..]);
                Some(Flow {
                         src_ip: src_ip,
                         dst_ip: dst_ip,
                         src_port: src_port,
                         dst_port: dst_port,
                         proto: protocol,
                     })
            }
        } else {
            None
        }
    }

    #[inline]
    pub fn new() -> IpHeader {
        Default::default()
    }

    #[inline]
    pub fn src(&self) -> u32 {
        u32::from_be(self.src_ip)
    }

    #[inline]
    pub fn set_src(&mut self, src: u32) {
        self.src_ip = u32::to_be(src)
    }

    #[inline]
    pub fn dst(&self) -> u32 {
        u32::from_be(self.dst_ip)
    }

    #[inline]
    pub fn set_dst(&mut self, dst: u32) {
        self.dst_ip = u32::to_be(dst);
    }

    #[inline]
    pub fn ttl(&self) -> u8 {
        let ttlpcsum = self.ttl_to_csum;
        (ttlpcsum & 0x000000ff) as u8
    }

    #[inline]
    pub fn set_ttl(&mut self, ttl: u8) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0x000000ff;
        self.ttl_to_csum = blanked | (ttl as u32);
    }

    #[inline]
    pub fn protocol(&self) -> u8 {
        let ttlpcsum = self.ttl_to_csum;
        ((ttlpcsum & 0xff00) >> 8) as u8
    }

    #[inline]
    pub fn set_protocol(&mut self, protocol: u8) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0xff00;
        self.ttl_to_csum = blanked | ((protocol as u32) << 8);
    }

    #[inline]
    pub fn csum(&self) -> u16 {
        let ttlpcsum = self.ttl_to_csum;
        ((ttlpcsum & 0xffff0000) >> 16) as u16
    }

    #[inline]
    pub fn set_csum(&mut self, csum: u16) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0xffff0000;
        self.ttl_to_csum = blanked | ((u16::to_be(csum) as u32) << 16);
    }

    #[inline]
    pub fn id(&self) -> u16 {
        let id_flag_fragment = self.id_to_foffset;
        u16::from_be((id_flag_fragment & 0xffff) as u16)
    }

    #[inline]
    pub fn set_id(&mut self, id: u16) {
        let id_flag_fragment = self.id_to_foffset;
        let blanked = id_flag_fragment & !0xffff;
        self.id_to_foffset = blanked | (u16::to_be(id) as u32);
    }

    #[inline]
    pub fn flags(&self) -> u8 {
        let id_flag_fragment = self.id_to_foffset;
        let flag_fragment = (id_flag_fragment >> 21) as u16;
        (flag_fragment & 0x7) as u8
    }

    #[inline]
    pub fn set_flags(&mut self, flags: u8) {
        self.id_to_foffset = (self.id_to_foffset & !0x00e00000) | (((flags & 0x7) as u32) << (16 + 5));
    }

    #[inline]
    pub fn fragment_offset(&self) -> u16 {
        let id_flag_fragment = self.id_to_foffset;
        let flag_fragment = (id_flag_fragment & 0xffff) as u16;
        u16::from_be(((flag_fragment & !0xe) >> 3))
    }

    #[inline]
    pub fn set_fragment_offset(&mut self, offset: u16) {
        let offset_correct = offset as u32;
        let id_to_offset_le = u32::from_be(self.id_to_foffset);
        self.id_to_foffset = u32::to_be(id_to_offset_le & !0x1fff | offset_correct);
    }

    #[inline]
    pub fn version(&self) -> u8 {
        ((self.version_to_len & 0xf0) as u8) >> 4
    }

    #[inline]
    pub fn set_version(&mut self, version: u8) {
        self.version_to_len = (self.version_to_len & !0xf0) | (((version & 0xf) as u32) << 4);
    }

    #[inline]
    pub fn ihl(&self) -> u8 {
        (self.version_to_len & 0x0f) as u8
    }

    #[inline]
    pub fn set_ihl(&mut self, ihl: u8) {
        self.version_to_len = (self.version_to_len & !0x0f) | ((ihl & 0x0f) as u32);
    }

    #[inline]
    pub fn dscp(&self) -> u8 {
        ((self.version_to_len & 0xfc00) >> 10) as u8
    }

    #[inline]
    pub fn set_dscp(&mut self, dscp: u8) {
        self.version_to_len = (self.version_to_len & !0xfc00) | (((dscp & 0x3f) as u32) << 10);
    }

    #[inline]
    pub fn ecn(&self) -> u8 {
        ((self.version_to_len & 0x0300) >> 8) as u8
    }

    #[inline]
    pub fn set_ecn(&mut self, ecn: u8) {
        self.version_to_len = (self.version_to_len & !0x0300) | (((ecn & 0x03) as u32) << 8);
    }

    #[inline]
    pub fn length(&self) -> u16 {
        u16::from_be(((self.version_to_len & 0xffff0000) >> 16) as u16)
    }

    #[inline]
    pub fn set_length(&mut self, len: u16) {
        self.version_to_len = (self.version_to_len & !0xffff0000) | ((u16::to_be(len) as u32) << 16);
    }
}
<commit_msg>IpHeader::flow: use bytes, not bits for slicing (#53)<commit_after>use super::EndOffset;
use byteorder::{BigEndian, ByteOrder};
use headers::MacHeader;
use std::convert::From;
use std::default::Default;
use std::fmt;
use std::net::Ipv4Addr;
use std::slice;
use utils::Flow;

/// IP header using SSE
#[derive(Debug, Default)]
#[repr(C,packed)]
pub struct IpHeader {
    version_to_len: u32,
    id_to_foffset: u32,
    ttl_to_csum: u32,
    src_ip: u32,
    dst_ip: u32,
}

impl fmt::Display for IpHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let src = Ipv4Addr::from(self.src());
        let dst = Ipv4Addr::from(self.dst());
        write!(f,
               "{} > {} version: {} ihl: {} len: {} ttl: {} proto: {} csum: {}",
               src,
               dst,
               self.version(),
               self.ihl(),
               self.length(),
               self.ttl(),
               self.protocol(),
               self.csum())
    }
}

impl EndOffset for IpHeader {
    type PreviousHeader = MacHeader;
    #[inline]
    fn offset(&self) -> usize {
        if cfg!(feature = "performance") {
            20
        } else {
            self.ihl() as usize * 4
        }
    }

    #[inline]
    fn size() -> usize {
        // The struct itself is always 20 bytes.
        20
    }

    #[inline]
    fn payload_size(&self, _: usize) -> usize {
        (self.length() as usize) - self.offset()
    }

    #[inline]
    fn check_correct(&self, _prev: &MacHeader) -> bool {
        true
    }
}

impl IpHeader {
    #[inline]
    pub fn flow(&self) -> Option<Flow> {
        let protocol = self.protocol();
        let src_ip = self.src();
        let dst_ip = self.dst();
        if (protocol == 6 || protocol == 17) && self.payload_size(0) >= 4 {
            unsafe {
                let self_as_u8 = (self as *const IpHeader) as *const u8;
                let port_as_u8 = self_as_u8.offset(self.offset() as isize);
                let port_slice = slice::from_raw_parts(port_as_u8, 4);
                let dst_port = BigEndian::read_u16(&port_slice[..2]);
                let src_port = BigEndian::read_u16(&port_slice[2..]);
                Some(Flow {
                         src_ip: src_ip,
                         dst_ip: dst_ip,
                         src_port: src_port,
                         dst_port: dst_port,
                         proto: protocol,
                     })
            }
        } else {
            None
        }
    }

    #[inline]
    pub fn new() -> IpHeader {
        Default::default()
    }

    #[inline]
    pub fn src(&self) -> u32 {
        u32::from_be(self.src_ip)
    }

    #[inline]
    pub fn set_src(&mut self, src: u32) {
        self.src_ip = u32::to_be(src)
    }

    #[inline]
    pub fn dst(&self) -> u32 {
        u32::from_be(self.dst_ip)
    }

    #[inline]
    pub fn set_dst(&mut self, dst: u32) {
        self.dst_ip = u32::to_be(dst);
    }

    #[inline]
    pub fn ttl(&self) -> u8 {
        let ttlpcsum = self.ttl_to_csum;
        (ttlpcsum & 0x000000ff) as u8
    }

    #[inline]
    pub fn set_ttl(&mut self, ttl: u8) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0x000000ff;
        self.ttl_to_csum = blanked | (ttl as u32);
    }

    #[inline]
    pub fn protocol(&self) -> u8 {
        let ttlpcsum = self.ttl_to_csum;
        ((ttlpcsum & 0xff00) >> 8) as u8
    }

    #[inline]
    pub fn set_protocol(&mut self, protocol: u8) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0xff00;
        self.ttl_to_csum = blanked | ((protocol as u32) << 8);
    }

    #[inline]
    pub fn csum(&self) -> u16 {
        let ttlpcsum = self.ttl_to_csum;
        ((ttlpcsum & 0xffff0000) >> 16) as u16
    }

    #[inline]
    pub fn set_csum(&mut self, csum: u16) {
        let ttlpcsum = self.ttl_to_csum;
        let blanked = ttlpcsum & !0xffff0000;
        self.ttl_to_csum = blanked | ((u16::to_be(csum) as u32) << 16);
    }

    #[inline]
    pub fn id(&self) -> u16 {
        let id_flag_fragment = self.id_to_foffset;
        u16::from_be((id_flag_fragment & 0xffff) as u16)
    }

    #[inline]
    pub fn set_id(&mut self, id: u16) {
        let id_flag_fragment = self.id_to_foffset;
        let blanked = id_flag_fragment & !0xffff;
        self.id_to_foffset = blanked | (u16::to_be(id) as u32);
    }

    #[inline]
    pub fn flags(&self) -> u8 {
        let id_flag_fragment = self.id_to_foffset;
        let flag_fragment = (id_flag_fragment >> 21) as u16;
        (flag_fragment & 0x7) as u8
    }

    #[inline]
    pub fn set_flags(&mut self, flags: u8) {
        self.id_to_foffset = (self.id_to_foffset & !0x00e00000) | (((flags & 0x7) as u32) << (16 + 5));
    }

    #[inline]
    pub fn fragment_offset(&self) -> u16 {
        let id_flag_fragment = self.id_to_foffset;
        let flag_fragment = (id_flag_fragment & 0xffff) as u16;
        u16::from_be(((flag_fragment & !0xe) >> 3))
    }

    #[inline]
    pub fn set_fragment_offset(&mut self, offset: u16) {
        let offset_correct = offset as u32;
        let id_to_offset_le = u32::from_be(self.id_to_foffset);
        self.id_to_foffset = u32::to_be(id_to_offset_le & !0x1fff | offset_correct);
    }

    #[inline]
    pub fn version(&self) -> u8 {
        ((self.version_to_len & 0xf0) as u8) >> 4
    }

    #[inline]
    pub fn set_version(&mut self, version: u8) {
        self.version_to_len = (self.version_to_len & !0xf0) | (((version & 0xf) as u32) << 4);
    }

    #[inline]
    pub fn ihl(&self) -> u8 {
        (self.version_to_len & 0x0f) as u8
    }

    #[inline]
    pub fn set_ihl(&mut self, ihl: u8) {
        self.version_to_len = (self.version_to_len & !0x0f) | ((ihl & 0x0f) as u32);
    }

    #[inline]
    pub fn dscp(&self) -> u8 {
        ((self.version_to_len & 0xfc00) >> 10) as u8
    }

    #[inline]
    pub fn set_dscp(&mut self, dscp: u8) {
        self.version_to_len = (self.version_to_len & !0xfc00) | (((dscp & 0x3f) as u32) << 10);
    }

    #[inline]
    pub fn ecn(&self) -> u8 {
        ((self.version_to_len & 0x0300) >> 8) as u8
    }

    #[inline]
    pub fn set_ecn(&mut self, ecn: u8) {
        self.version_to_len = (self.version_to_len & !0x0300) | (((ecn & 0x03) as u32) << 8);
    }

    #[inline]
    pub fn length(&self) -> u16 {
        u16::from_be(((self.version_to_len & 0xffff0000) >> 16) as u16)
    }

    #[inline]
    pub fn set_length(&mut self, len: u16) {
        self.version_to_len = (self.version_to_len & !0xffff0000) | ((u16::to_be(len) as u32) << 16);
    }
}
<|endoftext|>


<commit_before><commit_msg>Change the order of parameters of lda()<commit_after><|endoftext|>


<commit_before><commit_msg>small fix for unused qualifier<commit_after><|endoftext|>


<commit_before>// #![feature(plugin)]
// #![plugin(clippy)]

#[macro_use]
extern crate hyper;
extern crate chrono;
extern crate url;
extern crate crypto;
extern crate rustc_serialize as serialize;
extern crate xml;
#[macro_use]
extern crate mime;
extern crate time;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate uuid;

use azure::core::lease::{LeaseState, LeaseStatus, LeaseAction};
use azure::storage::client::Client;
use azure::storage::blob::{Blob, BlobType, LIST_BLOB_OPTIONS_DEFAULT, PUT_OPTIONS_DEFAULT,
                           PUT_BLOCK_OPTIONS_DEFAULT, PUT_PAGE_OPTIONS_DEFAULT,
                           LEASE_BLOB_OPTIONS_DEFAULT};
use azure::storage::container::{Container, PublicAccess, LIST_CONTAINER_OPTIONS_DEFAULT};
use azure::core::ba512_range::BA512Range;

use std::fs;
use time::Duration;

// use azure::storage::container::PublicAccess;

#[macro_use]
pub mod azure;

// use chrono::datetime::DateTime;
use chrono::UTC;

use mime::Mime;

#[allow(unused_variables)]
fn main() {
    env_logger::init().unwrap();

    let azure_storage_account = match std::env::var("AZURE_STORAGE_ACCOUNT") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_STORAGE_ACCOUNT env variable first!");
        }
    };

    let azure_storage_key = match std::env::var("AZURE_STORAGE_KEY") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_STORAGE_KEY env variable first!");
        }
    };

    let client = Client::new(&azure_storage_account, &azure_storage_key, true);

    let policy_name = match std::env::var("AZURE_POLICY_NAME") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_POLICY_NAME env variable first!");
        }
    };

    let policy_key = match std::env::var("AZURE_POLICY_KEY") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_POLICY_KEY env variable first!");
        }
    };

    let sb_namespace = match std::env::var("AZURE_SERVICE_BUS_NAMESPACE") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_SERVICE_BUS_NAMESPACE env variable first!");
        }
    };

    let ev_name = match std::env::var("AZURE_EVENT_HUB_NAME") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_EVENT_HUB_NAME env variable first!");
        }
    };

    let mut eh_client = azure::service_bus::event_hub::Client::new(&sb_namespace,
                                                                   &ev_name,
                                                                   &policy_name,
                                                                   &policy_key);
    // "todeleh",
    // "write_policy",
    // "9GIzBhQhMKg/patjrI2XS6gSGn6ju2+N40CQEYmowJ8=");

    // client.create_container("balocco3", PublicAccess::Blob).unwrap();
    // // println!("{:?}", new);
    //

    info!("Beginning tests");

    for i in 0..20 {
        info!("Sending message {}", i);
        send_event(&mut eh_client);
    }

    // lease_blob(&client);

    // put_block_blob(&client);
    //
    // put_page_blob(&client);

    // {
    //     let vhds = ret.iter_mut().find(|x| x.name == "canotto").unwrap();
    //
    //     let blobs = vhds.list_blobs(&client, true, true, true, true).unwrap();
    //
    //     println!("len == {:?}", blobs.len());
    //
    //     for blob in &blobs {
    //         println!("{}, {} KB ({:?})",
    //                  blob.name,
    //                  (blob.content_length / 1024),
    //                  blob.lease_state)
    //     }
    //
    //     let (blob, mut stream) = vhds.get_blob(&client, "DataCollector01.csv", None, None, None)
    //                                  .unwrap();
    //     println!("blob == {:?}", blob);
    //
    //     let mut buffer = String::new();
    //     stream.read_to_string(&mut buffer).unwrap();
    //
    //     // println!("buffer == {:?}", buffer);
    // }

    // for i in 0..2 {
    //     use std::fs::metadata;
    //     use std::fs::File;
    //
    //     let file_name: &'static str = "C:\\temp\\prova.txt";
    //     let container_name: &'static str = "rust";
    //
    //     {
    //         let containers = Container::list(&client).unwrap();
    //
    //         let cont = containers.iter().find(|x| x.name == container_name);
    //         if let None = cont {
    //             Container::create(&client, container_name, PublicAccess::Blob).unwrap();
    //         }
    //     }
    //
    //     let metadata = metadata(file_name).unwrap();
    //     let mut file = File::open(file_name).unwrap();
    //
    //     let new_blob = Blob {
    //         name: format!("go_rust{}.txt", i),
    //         snapshot_time: None,
    //         last_modified: UTC::now(),
    //         etag: "".to_owned(),
    //         content_length: metadata.len(),
    //         content_type: "application/octet-stream".parse::<Mime>().unwrap(),
    //         content_encoding: None,
    //         content_language: None,
    //         content_md5: None,
    //         cache_control: None,
    //         x_ms_blob_sequence_number: None,
    //         blob_type: BlobType::BlockBlob,
    //         lease_status: LeaseStatus::Unlocked,
    //         lease_state: LeaseState::Available,
    //         lease_duration: None,
    //         copy_id: None,
    //         copy_status: None,
    //         copy_source: None,
    //         copy_progress: None,
    //         copy_completion: None,
    //         copy_status_description: None,
    //     };
    //
    //     new_blob.put(&client,
    //                  container_name,
    //                  None,
    //                  Some((&mut file, metadata.len())))
    //             .unwrap();
    //
    //     println!("{} created", new_blob.name);
    // }

    // bal2.delete(&client).unwrap();
    // println!("{:?} deleted!", bal2);

    // let ret = client.delete_container("balocco2").unwrap();
    // println!("{:?}", ret);
    // inc_a!("main");
}

#[allow(dead_code)]
fn send_event(cli: &mut azure::service_bus::event_hub::Client) {
    debug!("running send_event");
    let file_name = "C:\\temp\\samplein.json";

    let metadata = fs::metadata(file_name).unwrap();
    let mut file_handle = fs::File::open(file_name).unwrap();

    cli.send_event((&mut file_handle, metadata.len()), Duration::hours(1))
       .unwrap();
}

#[allow(dead_code)]
fn lease_blob(client: &Client) {
    println!("running lease_blob");

    let ret = Container::list(client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();
    let vhds = ret.iter().find(|x| x.name == "rust").unwrap();
    let blobs = Blob::list(&client, &vhds.name, &LIST_BLOB_OPTIONS_DEFAULT).unwrap();
    let blob = blobs.iter().find(|ref x| x.name == "go_rust12.txt").unwrap();

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

    let mut lbo = LEASE_BLOB_OPTIONS_DEFAULT.clone();
    lbo.lease_duration = Some(30);
    let ret = blob.lease(client, LeaseAction::Acquire, &lbo).unwrap();
    println!("ret == {:?}", ret);

}

#[allow(dead_code)]
fn list_blobs(client: &Client) {
    println!("running list_blobs");

    let mut lbo2 = LIST_BLOB_OPTIONS_DEFAULT.clone();
    lbo2.max_results = 15;

    loop {
        let uc = Blob::list(&client, "rust", &lbo2).unwrap();

        println!("uc {:?}\n\n", uc);

        if !uc.is_complete() {
            lbo2.next_marker = Some(uc.next_marker().unwrap().to_owned());
        } else {
            break;
        }
    }
}

#[allow(dead_code)]
fn list_containers(client: &Client) {
    println!("running list_containers");

    let mut lco = LIST_CONTAINER_OPTIONS_DEFAULT.clone();
    lco.max_results = 2;
    loop {
        let ret = Container::list(&client, &lco).unwrap();

        println!("ret {:?}\n\n", ret);

        if !ret.is_complete() {
            lco.next_marker = Some(ret.next_marker().unwrap().to_owned());
        } else {
            break;
        }
    }
}

#[allow(dead_code)]
fn put_block_blob(client: &Client) {
    use std::fs::metadata;
    use std::fs::File;

    println!("\nrunning put_block_blob");

    let blob_name: &'static str = "Win64OpenSSL-1_0_2e.exe";
    let file_name: &'static str = "C:\\temp\\Win64OpenSSL-1_0_2e.exe";
    let container_name: &'static str = "rust";
    let metadata = metadata(file_name).unwrap();
    let mut file = File::open(file_name).unwrap();

    let content_length = metadata.len();

    {
        let containers = Container::list(&client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();

        let cont = containers.iter().find(|x| x.name == container_name);
        if let None = cont {
            Container::create(client, container_name, PublicAccess::Blob).unwrap();
        }
    }

    let new_blob = Blob {
        name: blob_name.to_owned(),
        container_name: container_name.to_owned(),
        snapshot_time: None,
        last_modified: UTC::now(),
        etag: "".to_owned(),
        content_length: content_length,
        content_type: "application/octet-stream".parse::<Mime>().unwrap(),
        content_encoding: None,
        content_language: None,
        content_md5: None,
        cache_control: None,
        x_ms_blob_sequence_number: None,
        blob_type: BlobType::BlockBlob,
        lease_status: LeaseStatus::Unlocked,
        lease_state: LeaseState::Available,
        lease_duration: None,
        copy_id: None,
        copy_status: None,
        copy_source: None,
        copy_progress: None,
        copy_completion: None,
        copy_status_description: None,
    };

    new_blob.put_block(&client,
                       "block_name",
                       &PUT_BLOCK_OPTIONS_DEFAULT,
                       (&mut file, 1024 * 1024))
            .unwrap();

    println!("created {:?}", new_blob);
}

#[allow(dead_code)]
fn put_page_blob(client: &Client) {
    use std::fs::metadata;
    use std::fs::File;

    println!("\nrunning put_page_blob");

    let blob_name: &'static str = "MindDB_Log.ldf";
    let file_name: &'static str = "C:\\temp\\MindDB_Log.ldf";
    let container_name: &'static str = "rust";
    let metadata = metadata(file_name).unwrap();
    let mut file = File::open(file_name).unwrap();

    {
        let containers = Container::list(&client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();

        let cont = containers.iter().find(|x| x.name == container_name);
        if let None = cont {
            Container::create(client, container_name, PublicAccess::Blob).unwrap();
        }
    }

    // align to 512 bytes
    let content_length = metadata.len() % 512 + metadata.len();

    let new_blob = Blob {
        name: blob_name.to_owned(),
        container_name: container_name.to_owned(),
        snapshot_time: None,
        last_modified: UTC::now(),
        etag: "".to_owned(),
        content_length: content_length,
        content_type: "application/octet-stream".parse::<Mime>().unwrap(),
        content_encoding: None,
        content_language: None,
        content_md5: None,
        cache_control: None,
        x_ms_blob_sequence_number: None,
        blob_type: BlobType::PageBlob,
        lease_status: LeaseStatus::Unlocked,
        lease_state: LeaseState::Available,
        lease_duration: None,
        copy_id: None,
        copy_status: None,
        copy_source: None,
        copy_progress: None,
        copy_completion: None,
        copy_status_description: None,
    };

    new_blob.put(&client, &PUT_OPTIONS_DEFAULT, None)
            .unwrap();

    let range = BA512Range::new(0, 1024 * 1024 - 1).unwrap();

    new_blob.put_page(client,
                      &range, // 1MB
                      &PUT_PAGE_OPTIONS_DEFAULT,
                      (&mut file, range.size()))
            .unwrap();

    println!("created {:?}", new_blob);
}
<commit_msg>Update main func.<commit_after>// #![feature(plugin)]
// #![plugin(clippy)]

#[macro_use]
extern crate hyper;
extern crate chrono;
extern crate url;
extern crate crypto;
extern crate rustc_serialize as serialize;
extern crate xml;
#[macro_use]
extern crate mime;
extern crate time;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate uuid;

use azure::core::lease::{LeaseState, LeaseStatus, LeaseAction};
use azure::storage::client::Client;
use azure::storage::blob::{Blob, BlobType, LIST_BLOB_OPTIONS_DEFAULT, PUT_OPTIONS_DEFAULT,
                           PUT_BLOCK_OPTIONS_DEFAULT, PUT_PAGE_OPTIONS_DEFAULT,
                           LEASE_BLOB_OPTIONS_DEFAULT};
use azure::storage::container::{Container, PublicAccess, LIST_CONTAINER_OPTIONS_DEFAULT};
use azure::core::ba512_range::BA512Range;

use std::fs;
use time::Duration;

// use azure::storage::container::PublicAccess;

#[macro_use]
pub mod azure;

// use chrono::datetime::DateTime;
use chrono::UTC;

use mime::Mime;

fn get_from_env(varname: &str) -> String {
    match std::env::var(varname) {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set {} env variable first!", varname);
        }
    }
}

fn create_storage_client() -> Client {
    let azure_storage_account = get_from_env("AZURE_STORAGE_ACCOUNT");
    let azure_storage_key = get_from_env("AZURE_STORAGE_KEY");
    Client::new(&azure_storage_account, &azure_storage_key, true)
}

fn main() {
    let client = create_storage_client();
    list_containers(&client);
}

#[allow(dead_code)]
#[allow(unused_variables)]
fn main_old() {
    env_logger::init().unwrap();

    let azure_storage_account = match std::env::var("AZURE_STORAGE_ACCOUNT") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_STORAGE_ACCOUNT env variable first!");
        }
    };

    let azure_storage_key = match std::env::var("AZURE_STORAGE_KEY") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_STORAGE_KEY env variable first!");
        }
    };

    let client = Client::new(&azure_storage_account, &azure_storage_key, true);

    let policy_name = match std::env::var("AZURE_POLICY_NAME") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_POLICY_NAME env variable first!");
        }
    };

    let policy_key = match std::env::var("AZURE_POLICY_KEY") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_POLICY_KEY env variable first!");
        }
    };

    let sb_namespace = match std::env::var("AZURE_SERVICE_BUS_NAMESPACE") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_SERVICE_BUS_NAMESPACE env variable first!");
        }
    };

    let ev_name = match std::env::var("AZURE_EVENT_HUB_NAME") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set AZURE_EVENT_HUB_NAME env variable first!");
        }
    };

    let mut eh_client = azure::service_bus::event_hub::Client::new(&sb_namespace,
                                                                   &ev_name,
                                                                   &policy_name,
                                                                   &policy_key);
    // "todeleh",
    // "write_policy",
    // "9GIzBhQhMKg/patjrI2XS6gSGn6ju2+N40CQEYmowJ8=");

    // client.create_container("balocco3", PublicAccess::Blob).unwrap();
    // // println!("{:?}", new);
    //

    info!("Beginning tests");

    for i in 0..20 {
        info!("Sending message {}", i);
        send_event(&mut eh_client);
    }

    // lease_blob(&client);

    // put_block_blob(&client);
    //
    // put_page_blob(&client);

    // {
    //     let vhds = ret.iter_mut().find(|x| x.name == "canotto").unwrap();
    //
    //     let blobs = vhds.list_blobs(&client, true, true, true, true).unwrap();
    //
    //     println!("len == {:?}", blobs.len());
    //
    //     for blob in &blobs {
    //         println!("{}, {} KB ({:?})",
    //                  blob.name,
    //                  (blob.content_length / 1024),
    //                  blob.lease_state)
    //     }
    //
    //     let (blob, mut stream) = vhds.get_blob(&client, "DataCollector01.csv", None, None, None)
    //                                  .unwrap();
    //     println!("blob == {:?}", blob);
    //
    //     let mut buffer = String::new();
    //     stream.read_to_string(&mut buffer).unwrap();
    //
    //     // println!("buffer == {:?}", buffer);
    // }

    // for i in 0..2 {
    //     use std::fs::metadata;
    //     use std::fs::File;
    //
    //     let file_name: &'static str = "C:\\temp\\prova.txt";
    //     let container_name: &'static str = "rust";
    //
    //     {
    //         let containers = Container::list(&client).unwrap();
    //
    //         let cont = containers.iter().find(|x| x.name == container_name);
    //         if let None = cont {
    //             Container::create(&client, container_name, PublicAccess::Blob).unwrap();
    //         }
    //     }
    //
    //     let metadata = metadata(file_name).unwrap();
    //     let mut file = File::open(file_name).unwrap();
    //
    //     let new_blob = Blob {
    //         name: format!("go_rust{}.txt", i),
    //         snapshot_time: None,
    //         last_modified: UTC::now(),
    //         etag: "".to_owned(),
    //         content_length: metadata.len(),
    //         content_type: "application/octet-stream".parse::<Mime>().unwrap(),
    //         content_encoding: None,
    //         content_language: None,
    //         content_md5: None,
    //         cache_control: None,
    //         x_ms_blob_sequence_number: None,
    //         blob_type: BlobType::BlockBlob,
    //         lease_status: LeaseStatus::Unlocked,
    //         lease_state: LeaseState::Available,
    //         lease_duration: None,
    //         copy_id: None,
    //         copy_status: None,
    //         copy_source: None,
    //         copy_progress: None,
    //         copy_completion: None,
    //         copy_status_description: None,
    //     };
    //
    //     new_blob.put(&client,
    //                  container_name,
    //                  None,
    //                  Some((&mut file, metadata.len())))
    //             .unwrap();
    //
    //     println!("{} created", new_blob.name);
    // }

    // bal2.delete(&client).unwrap();
    // println!("{:?} deleted!", bal2);

    // let ret = client.delete_container("balocco2").unwrap();
    // println!("{:?}", ret);
    // inc_a!("main");
}

#[allow(dead_code)]
fn send_event(cli: &mut azure::service_bus::event_hub::Client) {
    debug!("running send_event");
    let file_name = "C:\\temp\\samplein.json";

    let metadata = fs::metadata(file_name).unwrap();
    let mut file_handle = fs::File::open(file_name).unwrap();

    cli.send_event((&mut file_handle, metadata.len()), Duration::hours(1))
       .unwrap();
}

#[allow(dead_code)]
fn lease_blob(client: &Client) {
    println!("running lease_blob");

    let ret = Container::list(client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();
    let vhds = ret.iter().find(|x| x.name == "rust").unwrap();
    let blobs = Blob::list(&client, &vhds.name, &LIST_BLOB_OPTIONS_DEFAULT).unwrap();
    let blob = blobs.iter().find(|ref x| x.name == "go_rust12.txt").unwrap();

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

    let mut lbo = LEASE_BLOB_OPTIONS_DEFAULT.clone();
    lbo.lease_duration = Some(30);
    let ret = blob.lease(client, LeaseAction::Acquire, &lbo).unwrap();
    println!("ret == {:?}", ret);

}

#[allow(dead_code)]
fn list_blobs(client: &Client) {
    println!("running list_blobs");

    let mut lbo2 = LIST_BLOB_OPTIONS_DEFAULT.clone();
    lbo2.max_results = 15;

    loop {
        let uc = Blob::list(&client, "rust", &lbo2).unwrap();

        println!("uc {:?}\n\n", uc);

        if !uc.is_complete() {
            lbo2.next_marker = Some(uc.next_marker().unwrap().to_owned());
        } else {
            break;
        }
    }
}

#[allow(dead_code)]
fn list_containers(client: &Client) {
    println!("running list_containers");

    let mut lco = LIST_CONTAINER_OPTIONS_DEFAULT.clone();
    lco.max_results = 2;
    loop {
        let ret = Container::list(&client, &lco).unwrap();

        println!("ret {:?}\n\n", ret);

        if !ret.is_complete() {
            lco.next_marker = Some(ret.next_marker().unwrap().to_owned());
        } else {
            break;
        }
    }
}

#[allow(dead_code)]
fn put_block_blob(client: &Client) {
    use std::fs::metadata;
    use std::fs::File;

    println!("\nrunning put_block_blob");

    let blob_name: &'static str = "Win64OpenSSL-1_0_2e.exe";
    let file_name: &'static str = "C:\\temp\\Win64OpenSSL-1_0_2e.exe";
    let container_name: &'static str = "rust";
    let metadata = metadata(file_name).unwrap();
    let mut file = File::open(file_name).unwrap();

    let content_length = metadata.len();

    {
        let containers = Container::list(&client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();

        let cont = containers.iter().find(|x| x.name == container_name);
        if let None = cont {
            Container::create(client, container_name, PublicAccess::Blob).unwrap();
        }
    }

    let new_blob = Blob {
        name: blob_name.to_owned(),
        container_name: container_name.to_owned(),
        snapshot_time: None,
        last_modified: UTC::now(),
        etag: "".to_owned(),
        content_length: content_length,
        content_type: "application/octet-stream".parse::<Mime>().unwrap(),
        content_encoding: None,
        content_language: None,
        content_md5: None,
        cache_control: None,
        x_ms_blob_sequence_number: None,
        blob_type: BlobType::BlockBlob,
        lease_status: LeaseStatus::Unlocked,
        lease_state: LeaseState::Available,
        lease_duration: None,
        copy_id: None,
        copy_status: None,
        copy_source: None,
        copy_progress: None,
        copy_completion: None,
        copy_status_description: None,
    };

    new_blob.put_block(&client,
                       "block_name",
                       &PUT_BLOCK_OPTIONS_DEFAULT,
                       (&mut file, 1024 * 1024))
            .unwrap();

    println!("created {:?}", new_blob);
}

#[allow(dead_code)]
fn put_page_blob(client: &Client) {
    use std::fs::metadata;
    use std::fs::File;

    println!("\nrunning put_page_blob");

    let blob_name: &'static str = "MindDB_Log.ldf";
    let file_name: &'static str = "C:\\temp\\MindDB_Log.ldf";
    let container_name: &'static str = "rust";
    let metadata = metadata(file_name).unwrap();
    let mut file = File::open(file_name).unwrap();

    {
        let containers = Container::list(&client, &LIST_CONTAINER_OPTIONS_DEFAULT).unwrap();

        let cont = containers.iter().find(|x| x.name == container_name);
        if let None = cont {
            Container::create(client, container_name, PublicAccess::Blob).unwrap();
        }
    }

    // align to 512 bytes
    let content_length = metadata.len() % 512 + metadata.len();

    let new_blob = Blob {
        name: blob_name.to_owned(),
        container_name: container_name.to_owned(),
        snapshot_time: None,
        last_modified: UTC::now(),
        etag: "".to_owned(),
        content_length: content_length,
        content_type: "application/octet-stream".parse::<Mime>().unwrap(),
        content_encoding: None,
        content_language: None,
        content_md5: None,
        cache_control: None,
        x_ms_blob_sequence_number: None,
        blob_type: BlobType::PageBlob,
        lease_status: LeaseStatus::Unlocked,
        lease_state: LeaseState::Available,
        lease_duration: None,
        copy_id: None,
        copy_status: None,
        copy_source: None,
        copy_progress: None,
        copy_completion: None,
        copy_status_description: None,
    };

    new_blob.put(&client, &PUT_OPTIONS_DEFAULT, None)
            .unwrap();

    let range = BA512Range::new(0, 1024 * 1024 - 1).unwrap();

    new_blob.put_page(client,
                      &range, // 1MB
                      &PUT_PAGE_OPTIONS_DEFAULT,
                      (&mut file, range.size()))
            .unwrap();

    println!("created {:?}", new_blob);
}
<|endoftext|>


<commit_before><commit_msg>Rename WikipediaWithoutWikipedians to WikipediaMinusWikipediansHandler.<commit_after><|endoftext|>


<commit_before><commit_msg>Extract mock for reusability in other tests<commit_after><|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
extern crate glob;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

extern crate libc;

mod structs;
mod ghclient;
mod statics;
use statics::CLIENT;

macro_rules! syslog {
    ($msg:expr) => (
        unsafe {
            libc::openlog("sectora".as_ptr() as *const i8, libc::LOG_PID, libc::LOG_AUTH);
            libc::syslog(libc::LOG_NOTICE, $msg.as_ptr() as *const i8);
            libc::closelog();
        }
    )
}

fn main() {
    let user_arg = Arg::with_name("USER").required(true)
                                         .index(1)
                                         .help("user name");
    let conf_arg = Arg::with_name("CONF").required(true)
                                         .index(1)
                                         .help("conf path");
    let app = App::new(crate_name!()).version(crate_version!())
                                     .author(crate_authors!())
                                     .about(crate_description!())
                                     .subcommand(SubCommand::with_name("key").about("Gets user public key")
                                                                             .arg(user_arg))
                                     .subcommand(SubCommand::with_name("pam").about("Executes pam check"))
                                     .subcommand(SubCommand::with_name("cleanup").about("Cleans caches up"))
                                     .subcommand(SubCommand::with_name("check").about("Check configuration")
                                                                               .arg(conf_arg))
                                     .get_matches();

    use std::env;
    use std::path::Path;
    use std::process;

    match app.subcommand() {
        ("key", Some(sub)) => match CLIENT.print_user_public_key(sub.value_of("USER").unwrap()) {
            Ok(_) => {
                syslog!("sectora key (success).");
                process::exit(0)
            }
            Err(_) => {
                syslog!("sectora key (fail).");
                process::exit(21)
            }
        },
        ("check", Some(sub)) => match structs::Config::new(Path::new(sub.value_of("CONF").unwrap())) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        ("cleanup", Some(_)) => CLIENT.clear_all_caches().unwrap(),
        ("pam", Some(_)) => match env::var("PAM_USER") {
            Ok(user) => {
                if CLIENT.check_pam(&user).unwrap() {
                    syslog!("sectora pam (success).");
                    process::exit(0);
                } else {
                    syslog!("sectora pam (fail).");
                    process::exit(1)
                }
            }
            Err(e) => println!("PAM_USER: {}", e),
        },
        (&_, _) => println!("{}", app.usage()),
    }
}
<commit_msg>Set the level for each log message<commit_after>#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
extern crate glob;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

extern crate libc;

mod structs;
mod ghclient;
mod statics;
use statics::CLIENT;

macro_rules! syslog {
    ($level:path, $msg:expr) => (
        unsafe {
            libc::openlog("sectora".as_ptr() as *const i8, libc::LOG_PID, libc::LOG_AUTH);
            libc::syslog($level, $msg.as_ptr() as *const i8);
            libc::closelog();
        }
    )
}

fn main() {
    let user_arg = Arg::with_name("USER").required(true)
                                         .index(1)
                                         .help("user name");
    let conf_arg = Arg::with_name("CONF").required(true)
                                         .index(1)
                                         .help("conf path");
    let app = App::new(crate_name!()).version(crate_version!())
                                     .author(crate_authors!())
                                     .about(crate_description!())
                                     .subcommand(SubCommand::with_name("key").about("Gets user public key")
                                                                             .arg(user_arg))
                                     .subcommand(SubCommand::with_name("pam").about("Executes pam check"))
                                     .subcommand(SubCommand::with_name("cleanup").about("Cleans caches up"))
                                     .subcommand(SubCommand::with_name("check").about("Check configuration")
                                                                               .arg(conf_arg))
                                     .get_matches();

    use std::env;
    use std::path::Path;
    use std::process;

    match app.subcommand() {
        ("key", Some(sub)) => match CLIENT.print_user_public_key(sub.value_of("USER").unwrap()) {
            Ok(_) => {
                syslog!(libc::LOG_NOTICE, "sectora key (success).");
                process::exit(0)
            }
            Err(_) => {
                syslog!(libc::LOG_WARNING, "sectora key (fail).");
                process::exit(21)
            }
        },
        ("check", Some(sub)) => match structs::Config::new(Path::new(sub.value_of("CONF").unwrap())) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        ("cleanup", Some(_)) => CLIENT.clear_all_caches().unwrap(),
        ("pam", Some(_)) => match env::var("PAM_USER") {
            Ok(user) => {
                if CLIENT.check_pam(&user).unwrap() {
                    syslog!(libc::LOG_NOTICE, "sectora pam (success).");
                    process::exit(0);
                } else {
                    syslog!(libc::LOG_WARNING, "sectora pam (fail).");
                    process::exit(1)
                }
            }
            Err(e) => println!("PAM_USER: {}", e),
        },
        (&_, _) => println!("{}", app.usage()),
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

// Import the hat library
extern crate hat;

// Rust crates.
extern crate env_logger;
extern crate sodiumoxide;

// We use Clap for argument parsing.
#[macro_use]
extern crate clap;

use std::borrow::ToOwned;
use std::convert::From;
use std::path::PathBuf;
use std::sync::Arc;

use clap::{App, SubCommand};

use hat::backend;

static MAX_BLOB_SIZE: usize = 4 * 1024 * 1024;

fn blob_dir() -> PathBuf {
    PathBuf::from("blobs")
}

fn license() {
    println!(include_str!("../LICENSE"));
    println!("clap (Command Line Argument Parser) License:");
    println!(include_str!("../LICENSE-CLAP"));
}

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

    // Because "snapshot" and "checkout" use the exact same type of arguments, we can make a
    // template. This template defines two positional arguments, both are required
    let arg_template = "<NAME> 'Name of the snapshot'
                        <PATH> 'The path of \
                        the snapshot'";

    // Create valid arguments
    let matches = App::new("hat")
        .version(&format!("v{}", crate_version!())[..])
        .about("Create backup snapshots")
        .arg_from_usage("--license 'Display the license'")
        .subcommand(SubCommand::with_name("snapshot")
            .about("Create a snapshot")
            .args_from_usage(arg_template))
        .subcommand(SubCommand::with_name("checkout")
            .about("Checkout a snapshot")
            .args_from_usage(arg_template))
        .subcommand(SubCommand::with_name("commit")
            .about("Commit a snapshot")
            .arg_from_usage("<NAME> 'Name of the snapshot'"))
        .subcommand(SubCommand::with_name("meta-commit")
            .about("Commit snapshot metadata (required for recover command"))
        .subcommand(SubCommand::with_name("recover").about("Recover list of commit'ed snapshots"))
        .subcommand(SubCommand::with_name("delete")
            .about("Delete a snapshot")
            .args_from_usage("<NAME> 'Name of the snapshot family'
                                                        \
                              <ID> 'The snapshot id to delete'"))
        .subcommand(SubCommand::with_name("gc")
            .about("Garbage collect: identify and remove unused data blocks.")
            .args_from_usage("-p --pretend 'Do not modify any data'"))
        .subcommand(SubCommand::with_name("resume").about("Resume previous failed command."))
        .get_matches();

    // Check for license flag
    if matches.is_present("license") {
        license();
        std::process::exit(0);
    }

    // Initialize sodium (must only be called once)
    sodiumoxide::init();

    match matches.subcommand() {
        ("resume", Some(_cmd)) => {
            // Setting up the repository triggers automatic resume.
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE).unwrap();
        }
        ("snapshot", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let path = cmd.value_of("PATH").unwrap();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            let family = hat.open_family(name.clone())
                .expect(&format!("Could not open family '{}'", name));

            family.snapshot_dir(PathBuf::from(path));
            family.flush().unwrap();

            println!("Waiting for final flush...");
        }
        ("checkout", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let path = cmd.value_of("PATH").unwrap();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.checkout_in_dir(name, PathBuf::from(path)).unwrap();
        }
        ("meta-commit", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.meta_commit().unwrap();
        }
        ("recover", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.recover().unwrap();
        }
        ("commit", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.commit_by_name(name, None).unwrap();
        }
        ("delete", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let id = cmd.value_of("ID").unwrap().to_owned();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.deregister_by_name(name, id.parse::<i64>().unwrap()).unwrap();
        }
        ("gc", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();
            let (deleted_hashes, live_blobs) = hat.gc().unwrap();
            println!("Deleted hashes: {:?}", deleted_hashes);
            println!("Live data blobs after deletion: {:?}", live_blobs);

        }
        _ => {
            println!("No subcommand specified\n{}\nFor more information re-run with --help",
                     matches.usage());
            std::process::exit(1);
        }
    }
}
<commit_msg>Cargo fmt import sorting.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

// Import the hat library
extern crate hat;

// Rust crates.
extern crate env_logger;
extern crate sodiumoxide;

// We use Clap for argument parsing.
#[macro_use]
extern crate clap;

use clap::{App, SubCommand};

use hat::backend;
use std::borrow::ToOwned;
use std::convert::From;
use std::path::PathBuf;
use std::sync::Arc;

static MAX_BLOB_SIZE: usize = 4 * 1024 * 1024;

fn blob_dir() -> PathBuf {
    PathBuf::from("blobs")
}

fn license() {
    println!(include_str!("../LICENSE"));
    println!("clap (Command Line Argument Parser) License:");
    println!(include_str!("../LICENSE-CLAP"));
}

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

    // Because "snapshot" and "checkout" use the exact same type of arguments, we can make a
    // template. This template defines two positional arguments, both are required
    let arg_template = "<NAME> 'Name of the snapshot'
                        <PATH> 'The path of \
                        the snapshot'";

    // Create valid arguments
    let matches = App::new("hat")
        .version(&format!("v{}", crate_version!())[..])
        .about("Create backup snapshots")
        .arg_from_usage("--license 'Display the license'")
        .subcommand(SubCommand::with_name("snapshot")
            .about("Create a snapshot")
            .args_from_usage(arg_template))
        .subcommand(SubCommand::with_name("checkout")
            .about("Checkout a snapshot")
            .args_from_usage(arg_template))
        .subcommand(SubCommand::with_name("commit")
            .about("Commit a snapshot")
            .arg_from_usage("<NAME> 'Name of the snapshot'"))
        .subcommand(SubCommand::with_name("meta-commit")
            .about("Commit snapshot metadata (required for recover command"))
        .subcommand(SubCommand::with_name("recover").about("Recover list of commit'ed snapshots"))
        .subcommand(SubCommand::with_name("delete")
            .about("Delete a snapshot")
            .args_from_usage("<NAME> 'Name of the snapshot family'
                                                        \
                              <ID> 'The snapshot id to delete'"))
        .subcommand(SubCommand::with_name("gc")
            .about("Garbage collect: identify and remove unused data blocks.")
            .args_from_usage("-p --pretend 'Do not modify any data'"))
        .subcommand(SubCommand::with_name("resume").about("Resume previous failed command."))
        .get_matches();

    // Check for license flag
    if matches.is_present("license") {
        license();
        std::process::exit(0);
    }

    // Initialize sodium (must only be called once)
    sodiumoxide::init();

    match matches.subcommand() {
        ("resume", Some(_cmd)) => {
            // Setting up the repository triggers automatic resume.
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE).unwrap();
        }
        ("snapshot", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let path = cmd.value_of("PATH").unwrap();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            let family = hat.open_family(name.clone())
                .expect(&format!("Could not open family '{}'", name));

            family.snapshot_dir(PathBuf::from(path));
            family.flush().unwrap();

            println!("Waiting for final flush...");
        }
        ("checkout", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let path = cmd.value_of("PATH").unwrap();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.checkout_in_dir(name, PathBuf::from(path)).unwrap();
        }
        ("meta-commit", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.meta_commit().unwrap();
        }
        ("recover", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.recover().unwrap();
        }
        ("commit", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.commit_by_name(name, None).unwrap();
        }
        ("delete", Some(cmd)) => {
            let name = cmd.value_of("NAME").unwrap().to_owned();
            let id = cmd.value_of("ID").unwrap().to_owned();

            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();

            hat.deregister_by_name(name, id.parse::<i64>().unwrap()).unwrap();
        }
        ("gc", Some(_cmd)) => {
            let backend = Arc::new(backend::FileBackend::new(blob_dir()));
            let mut hat = hat::Hat::open_repository(PathBuf::from("repo"), backend, MAX_BLOB_SIZE)
                .unwrap();
            let (deleted_hashes, live_blobs) = hat.gc().unwrap();
            println!("Deleted hashes: {:?}", deleted_hashes);
            println!("Live data blobs after deletion: {:?}", live_blobs);

        }
        _ => {
            println!("No subcommand specified\n{}\nFor more information re-run with --help",
                     matches.usage());
            std::process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Copy, Clone)]
struct Card {
    suit: Suit,
    value: char,
}

impl Card {
    fn new(suit: Suit, value: char) -> Card {
        Card { suit: suit, value: value }
    }
}

impl Ord for Card {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

fn print_card(card: Card) {
    println!("My card: {:?}", card);
}

fn main() {
    let card = Card::new(Suit::Hearts, 'Q');
    print_card(card);
}
<commit_msg>add fifth suit<commit_after>#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
    Stars,
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Copy, Clone)]
struct Card {
    suit: Suit,
    value: char,
}

impl Card {
    fn new(suit: Suit, value: char) -> Card {
        Card { suit: suit, value: value }
    }
}

impl Ord for Card {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

fn print_card(card: Card) {
    println!("My card: {:?}", card);
}

fn main() {
    let card = Card::new(Suit::Hearts, 'Q');
    print_card(card);
}
<|endoftext|>