<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match match_result { Accept(count, val) => count == 6 && val == &true, _ => false });
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
/// It's worth noting that this is not just limited to strings and characters. For example, vectors will work too:
///
/// ```
/// # use ndfa::*;
/// matches(&vec![1,2,3,1,2,3], vec![1,2,3].repeat_forever(1)); // == Some(6)
/// # assert!(matches(&vec![1,2,3,1,2,3], vec![1,2,3].repeat_forever(1)) == Some(6));
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
/// ```
/// # use ndfa::*;
/// let prepared = "abc".repeat_forever(1).prepare_to_match();
///
/// matches_prepared("abcabc", &prepared);      // == Some(6))
/// matches_prepared("abc", &prepared);         // == Some(3))
/// matches_prepared("abcabcabc", &prepared);   // == Some(9))
/// ```
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<commit_msg>Fix some comments<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match match_result { Accept(count, val) => count == 6 && val == &true, _ => false });
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
/// It's worth noting that this is not just limited to strings and characters. For example, vectors will work too:
///
/// ```
/// # use ndfa::*;
/// matches(&vec![1,2,3,1,2,3], vec![1,2,3].repeat_forever(1)); // == Some(6)
/// # assert!(matches(&vec![1,2,3,1,2,3], vec![1,2,3].repeat_forever(1)) == Some(6));
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
/// ```
/// # use ndfa::*;
/// let prepared = "abc".repeat_forever(1).prepare_to_match();
///
/// matches_prepared("abcabc", &prepared);      // == Some(6)
/// matches_prepared("abc", &prepared);         // == Some(3)
/// matches_prepared("abcabcabc", &prepared);   // == Some(9)
/// ```
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

macro_rules! min {
    ($x:expr) => ( $x );
    ($x:expr, $($xs:expr),+) => {
        {
            use std::cmp::min;
            min($x, min!( $($xs),+ ))
        }
    };
}

fn input() -> Vec<String> {
    let path = Path::new("data/input.txt");
    let display = path.display();
    let file = match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
        Ok(file) => file,
    };
    BufReader::new(file)
        .lines()
        .map(|x| match x {
            Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
            Ok(s) => s,
        })
        .collect()
}

fn to_dims(s: &str) -> (u64, u64, u64) {
    let v: Vec<u64> = s.split('x').filter_map(|x| x.parse::<u64>().ok()).collect();
    match v.len() {
        3 => (v[0], v[1], v[2]),
        _ => panic!("Invalid input: {}", s),
    }
}

fn sf(lwh: &(u64, u64, u64)) -> u64 {
    let s0 = lwh.0 * lwh.1;
    let s1 = lwh.0 * lwh.2;
    let s2 = lwh.1 * lwh.2;
    2 * (s0 + s1 + s2) + min!(s0, s1, s2)
}

#[test]
fn _t0() {
    assert_eq!(58, sf(&to_dims("2x3x4")));
}

#[test]
fn _t1() {
    assert_eq!(43, sf(&to_dims("1x1x10")));
}

fn r(lwh: &(u64, u64, u64)) -> u64 {
    let p0 = 2 * (lwh.0 + lwh.1);
    let p1 = 2 * (lwh.0 + lwh.2);
    let p2 = 2 * (lwh.1 + lwh.2);
    min!(p0, p1, p2) + lwh.0 * lwh.1 * lwh.2
}

#[test]
fn _t2() {
    assert_eq!(34, r(&to_dims("2x3x4")));
}

#[test]
fn _t3() {
    assert_eq!(14, r(&to_dims("1x1x10")));
}

fn main() {
    let d: Vec<(u64, u64, u64)> = input().iter().map(|l| to_dims(l)).collect();
    let (a1, a2) = d.iter().map(|x| (sf(x), r(x))).fold((0, 0), |(a, b), (x, y)| (a + x, b + y));
    println!("{}", a1);
    println!("{}", a2);
}
<commit_msg>polishing<commit_after>use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::Lines;
use std::io::prelude::*;
use std::path::Path;

macro_rules! min {
    ($x:expr) => ($x);
    ($x:expr, $($xs:expr),+) => (std::cmp::min($x, min!($($xs),+)));
}

fn input() -> Lines<BufReader<File>> {
    let p = Path::new("data/input.txt");
    match File::open(&p) {
        Err(e) => panic!("Couldn't open {}: {}", p.display(), e.description()),
        Ok(f) => BufReader::new(f).lines(),
    }
}

fn to_dims(s: &str) -> (u64, u64, u64) {
    let v: Vec<_> = s.split('x').filter_map(|x| x.parse().ok()).collect();
    match v.len() {
        3 => (v[0], v[1], v[2]),
        _ => panic!("Invalid input: {}", s),
    }
}

fn sf(lwh: &(u64, u64, u64)) -> u64 {
    let s0 = lwh.0 * lwh.1;
    let s1 = lwh.0 * lwh.2;
    let s2 = lwh.1 * lwh.2;
    2 * (s0 + s1 + s2) + min!(s0, s1, s2)
}

#[test]
fn _t0() {
    assert_eq!(58, sf(&to_dims("2x3x4")));
}

#[test]
fn _t1() {
    assert_eq!(43, sf(&to_dims("1x1x10")));
}

fn r(lwh: &(u64, u64, u64)) -> u64 {
    let p0 = lwh.0 + lwh.1;
    let p1 = lwh.0 + lwh.2;
    let p2 = lwh.1 + lwh.2;
    2 * min!(p0, p1, p2) + lwh.0 * lwh.1 * lwh.2
}

#[test]
fn _t2() {
    assert_eq!(34, r(&to_dims("2x3x4")));
}

#[test]
fn _t3() {
    assert_eq!(14, r(&to_dims("1x1x10")));
}

fn main() {
    let (a1, a2) = input()
        .filter_map(|l| l.ok())
        .map(|x| to_dims(x.as_str()))
        .map(|x| (sf(&x), r(&x)))
        .fold((0, 0), |(a, b), (x, y)| (a + x, b + y));
    println!("{}", a1);
    println!("{}", a2);
}
<|endoftext|>


<commit_before>use crate::utils::{differing_macro_contexts, in_macro_or_desugar, snippet_opt, span_note_and_lint};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

declare_lint_pass!(Formatting => [
    SUSPICIOUS_ASSIGNMENT_FORMATTING,
    SUSPICIOUS_ELSE_FORMATTING,
    POSSIBLE_MISSING_COMMA
]);

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if_chain! {
        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
        if is_block(else_) || unsugar_if(else_).is_some();
        if !differing_macro_contexts(then.span, else_.span);
        if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span);

        // workaround for rust-lang/rust#43081
        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;

        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
        // the “if” of the “else if” block (excluding)
        let else_span = then.span.between(else_.span);

        // the snippet should look like " else \n    " with maybe comments anywhere
        // it’s bad when there is a ‘\n’ after the “else”
        if let Some(else_snippet) = snippet_opt(cx, else_span);
        if let Some(else_pos) = else_snippet.find("else");
        if else_snippet[else_pos..].contains('\n');
        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

        then {
            span_note_and_lint(
                cx,
                SUSPICIOUS_ELSE_FORMATTING,
                else_span,
                &format!("this is an `else {}` but the formatting might hide it", else_desc),
                else_span,
                &format!(
                    "to remove this lint, remove the `else` or remove the new line between \
                     `else` and `{}`",
                    else_desc,
                ),
            );
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro_or_desugar(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) => Some((then, else_)),
        _ => None,
    }
}
<commit_msg>Remove ast:: prefix from types<commit_after>use crate::utils::{differing_macro_contexts, in_macro_or_desugar, snippet_opt, span_note_and_lint};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast::*;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

declare_lint_pass!(Formatting => [
    SUSPICIOUS_ASSIGNMENT_FORMATTING,
    SUSPICIOUS_ELSE_FORMATTING,
    POSSIBLE_MISSING_COMMA
]);

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&StmtKind::Expr(ref first), &StmtKind::Expr(ref second))
                | (&StmtKind::Expr(ref first), &StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
    if let ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
    if_chain! {
        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
        if is_block(else_) || unsugar_if(else_).is_some();
        if !differing_macro_contexts(then.span, else_.span);
        if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span);

        // workaround for rust-lang/rust#43081
        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;

        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
        // the “if” of the “else if” block (excluding)
        let else_span = then.span.between(else_.span);

        // the snippet should look like " else \n    " with maybe comments anywhere
        // it’s bad when there is a ‘\n’ after the “else”
        if let Some(else_snippet) = snippet_opt(cx, else_span);
        if let Some(else_pos) = else_snippet.find("else");
        if else_snippet[else_pos..].contains('\n');
        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

        then {
            span_note_and_lint(
                cx,
                SUSPICIOUS_ELSE_FORMATTING,
                else_span,
                &format!("this is an `else {}` but the formatting might hide it", else_desc),
                else_span,
                &format!(
                    "to remove this lint, remove the `else` or remove the new line between \
                     `else` and `{}`",
                    else_desc,
                ),
            );
        }
    }
}

fn has_unary_equivalent(bin_op: BinOpKind) -> bool {
    // &, *, -
    bin_op == BinOpKind::And || bin_op == BinOpKind::Mul || bin_op == BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
    if let ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro_or_desugar(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &Expr) -> bool {
    if let ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &Expr) -> Option<(&P<Block>, &Option<P<Expr>>)> {
    match expr.node {
        ExprKind::If(_, ref then, ref else_) => Some((then, else_)),
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! SHM (Shared Memory) is the most basic way wayland clients can send content to
//! the compositor: by sending a file descriptor to some (likely RAM-backed) storage
//! containing the actual data. This helper handles for you most of the logic for
//! handling these file descriptor and accessing their contents as simple `&[u8]` slices.
//!
//! This module is heavily inspired from
//! [the similar helpers](https://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-shm.c)
//! of the wayland C libraries.
//!
//! To use it, first add a `ShmGlobal` to your event loop, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol) and obtain its `ShmToken`.
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::wayland::shm::init_shm_global;
//! use wayland_server::protocol::wl_shm::Format;
//!
//! # fn main() {
//! # let (_, mut event_loop) = wayland_server::create_display();
//! // Insert the ShmGlobal into your event loop
//! // Here, we specify that Yuyv and C8 format are supported
//! // additionnaly to the standart Argb8888 and Xrgb8888.
//! let shm_global = init_shm_global(
//!     &mut event_loop,
//!     vec![Format::Yuyv, Format::C8],
//!     None // we don't provide a logger here
//! );
//! # }
//! ```
//!
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
//! do it:
//!
//! ```
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
//! # fn wrap(buffer: &WlBuffer) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData};
//!
//! with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: BufferData| {
//!         // do something to draw it on the screen
//!     }
//! );
//! # }
//! # fn main() {}
//! ```
//!
//! **Note**
//!
//! This handler makes itself safe regading the client providing a wrong size for the memory pool
//! by using a SIGBUS handler.
//!
//! If you are already using an handler for this signal, you probably don't want to use this handler.

use self::pool::{Pool, ResizeError};
use std::rc::Rc;
use std::sync::Arc;
use wayland_server::{resource_is_registered, Client, EventLoop, EventLoopHandle, Global, Resource};
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};

mod pool;

#[derive(Clone)]
/// Internal data storage of ShmGlobal
///
/// This type is only visible as type parameter of
/// the `Global` handle you are provided.
pub struct ShmGlobalData {
    formats: Rc<Vec<wl_shm::Format>>,
    log: ::slog::Logger,
}

/// Create a new SHM global advertizing given supported formats.
///
/// This global will always advertize `ARGB8888` and `XRGB8888` format
/// as they are required by the protocol. Formats given as argument
/// as additionnaly advertized.
///
/// The global is directly registered into the eventloop, and this function
/// returns the global handle, in case you whish to remove this global in
/// the future.
pub fn init_shm_global<L>(evl: &mut EventLoop, mut formats: Vec<wl_shm::Format>, logger: L)
                          -> Global<wl_shm::WlShm, ShmGlobalData>
where
    L: Into<Option<::slog::Logger>>,
{
    let log = ::slog_or_stdlog(logger);

    // always add the mandatory formats
    formats.push(wl_shm::Format::Argb8888);
    formats.push(wl_shm::Format::Xrgb8888);
    let data = ShmGlobalData {
        formats: Rc::new(formats),
        log: log.new(o!("smithay_module" => "shm_handler")),
    };

    let global = evl.register_global::<wl_shm::WlShm, _>(1, shm_global_bind, data);

    global
}

/// Error that can occur when accessing an SHM buffer
#[derive(Debug)]
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    NotManaged,
    /// An error occured while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    BadMap,
}

/// Call given closure with the contents of the given buffer
///
/// If the buffer is managed by the provided ShmGlobal, its contents are
/// extracted and the closure is extracted with them:
///
/// - The first argument is a data slice of the contents of the pool
/// - The second argument is the specification of this buffer is this pool
///
/// If the buffer is not managed by the provided ShmGlobal, the closure is not called
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
pub fn with_buffer_contents<F>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
where
    F: FnOnce(&[u8], BufferData),
{
    if !resource_is_registered(buffer, &buffer_implementation()) {
        return Err(BufferAccessError::NotManaged);
    }
    let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };

    if data.pool
        .with_data_slice(|slice| f(slice, data.data))
        .is_err()
    {
        // SIGBUS error occured
        buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
        return Err(BufferAccessError::BadMap);
    }
    Ok(())
}

fn shm_global_bind(evlh: &mut EventLoopHandle, data: &mut ShmGlobalData, _: &Client, global: wl_shm::WlShm) {
    // register an handler for this shm
    evlh.register(&global, shm_implementation(), data.clone(), None);
    // and then the custom formats
    for f in &data.formats[..] {
        global.format(*f);
    }
}

fn shm_implementation() -> wl_shm::Implementation<ShmGlobalData> {
    wl_shm::Implementation {
        create_pool: |evlh, data, _, shm, pool, fd, size| {
            if size <= 0 {
                shm.post_error(
                    wl_shm::Error::InvalidFd as u32,
                    "Invalid size for a new wl_shm_pool.".into(),
                );
                return;
            }
            let mmap_pool = match Pool::new(fd, size as usize, data.log.clone()) {
                Ok(p) => p,
                Err(()) => {
                    shm.post_error(
                        wl_shm::Error::InvalidFd as u32,
                        format!("Failed mmap of fd {}.", fd),
                    );
                    return;
                }
            };
            let arc_pool = Box::new(Arc::new(mmap_pool));
            evlh.register(
                &pool,
                shm_pool_implementation(),
                data.clone(),
                Some(destroy_shm_pool),
            );
            pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
        },
    }
}

fn destroy_shm_pool(pool: &wl_shm_pool::WlShmPool) {
    let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
    drop(arc_pool)
}

/// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Wwidth of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format,
}

struct InternalBufferData {
    pool: Arc<Pool>,
    data: BufferData,
}

fn shm_pool_implementation() -> wl_shm_pool::Implementation<ShmGlobalData> {
    wl_shm_pool::Implementation {
        create_buffer: |evlh, data, _, pool, buffer, offset, width, height, stride, format| {
            if !data.formats.contains(&format) {
                buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
                return;
            }
            let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
            let data = Box::into_raw(Box::new(InternalBufferData {
                pool: arc_pool.clone(),
                data: BufferData {
                    offset: offset,
                    width: width,
                    height: height,
                    stride: stride,
                    format: format,
                },
            }));
            evlh.register(&buffer, buffer_implementation(), (), Some(destroy_buffer));
            buffer.set_user_data(data as *mut ());
        },
        resize: |_, _, _, pool, size| {
            let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
            match arc_pool.resize(size) {
                Ok(()) => {}
                Err(ResizeError::InvalidSize) => {
                    pool.post_error(
                        wl_shm::Error::InvalidFd as u32,
                        "Invalid new size for a wl_shm_pool.".into(),
                    );
                }
                Err(ResizeError::MremapFailed) => {
                    pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
                }
            }
        },
        destroy: |_, _, _, _| {},
    }
}

fn destroy_buffer(buffer: &wl_buffer::WlBuffer) {
    let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
    drop(buffer_data)
}

fn buffer_implementation() -> wl_buffer::Implementation<()> {
    wl_buffer::Implementation {
        destroy: |_, _, _, _| {},
    }
}
<commit_msg>Fix invalid drop in SHM doc test<commit_after>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! SHM (Shared Memory) is the most basic way wayland clients can send content to
//! the compositor: by sending a file descriptor to some (likely RAM-backed) storage
//! containing the actual data. This helper handles for you most of the logic for
//! handling these file descriptor and accessing their contents as simple `&[u8]` slices.
//!
//! This module is heavily inspired from
//! [the similar helpers](https://cgit.freedesktop.org/wayland/wayland/tree/src/wayland-shm.c)
//! of the wayland C libraries.
//!
//! To use it, first add a `ShmGlobal` to your event loop, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol) and obtain its `ShmToken`.
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::wayland::shm::init_shm_global;
//! use wayland_server::protocol::wl_shm::Format;
//!
//! # fn main() {
//! # let (display, mut event_loop) = wayland_server::create_display();
//! // Insert the ShmGlobal into your event loop
//! // Here, we specify that Yuyv and C8 format are supported
//! // additionnaly to the standart Argb8888 and Xrgb8888.
//! let shm_global = init_shm_global(
//!     &mut event_loop,
//!     vec![Format::Yuyv, Format::C8],
//!     None // we don't provide a logger here
//! );
//! # }
//! ```
//!
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
//! do it:
//!
//! ```
//! # extern crate wayland_server;
//! # extern crate smithay;
//! # use wayland_server::protocol::wl_buffer::WlBuffer;
//! # fn wrap(buffer: &WlBuffer) {
//! use smithay::wayland::shm::{with_buffer_contents, BufferData};
//!
//! with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: BufferData| {
//!         // do something to draw it on the screen
//!     }
//! );
//! # }
//! # fn main() {}
//! ```
//!
//! **Note**
//!
//! This handler makes itself safe regading the client providing a wrong size for the memory pool
//! by using a SIGBUS handler.
//!
//! If you are already using an handler for this signal, you probably don't want to use this handler.

use self::pool::{Pool, ResizeError};
use std::rc::Rc;
use std::sync::Arc;
use wayland_server::{resource_is_registered, Client, EventLoop, EventLoopHandle, Global, Resource};
use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool};

mod pool;

#[derive(Clone)]
/// Internal data storage of ShmGlobal
///
/// This type is only visible as type parameter of
/// the `Global` handle you are provided.
pub struct ShmGlobalData {
    formats: Rc<Vec<wl_shm::Format>>,
    log: ::slog::Logger,
}

/// Create a new SHM global advertizing given supported formats.
///
/// This global will always advertize `ARGB8888` and `XRGB8888` format
/// as they are required by the protocol. Formats given as argument
/// as additionnaly advertized.
///
/// The global is directly registered into the eventloop, and this function
/// returns the global handle, in case you whish to remove this global in
/// the future.
pub fn init_shm_global<L>(evl: &mut EventLoop, mut formats: Vec<wl_shm::Format>, logger: L)
                          -> Global<wl_shm::WlShm, ShmGlobalData>
where
    L: Into<Option<::slog::Logger>>,
{
    let log = ::slog_or_stdlog(logger);

    // always add the mandatory formats
    formats.push(wl_shm::Format::Argb8888);
    formats.push(wl_shm::Format::Xrgb8888);
    let data = ShmGlobalData {
        formats: Rc::new(formats),
        log: log.new(o!("smithay_module" => "shm_handler")),
    };

    let global = evl.register_global::<wl_shm::WlShm, _>(1, shm_global_bind, data);

    global
}

/// Error that can occur when accessing an SHM buffer
#[derive(Debug)]
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    NotManaged,
    /// An error occured while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    BadMap,
}

/// Call given closure with the contents of the given buffer
///
/// If the buffer is managed by the provided ShmGlobal, its contents are
/// extracted and the closure is extracted with them:
///
/// - The first argument is a data slice of the contents of the pool
/// - The second argument is the specification of this buffer is this pool
///
/// If the buffer is not managed by the provided ShmGlobal, the closure is not called
/// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
pub fn with_buffer_contents<F>(buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
where
    F: FnOnce(&[u8], BufferData),
{
    if !resource_is_registered(buffer, &buffer_implementation()) {
        return Err(BufferAccessError::NotManaged);
    }
    let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) };

    if data.pool
        .with_data_slice(|slice| f(slice, data.data))
        .is_err()
    {
        // SIGBUS error occured
        buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
        return Err(BufferAccessError::BadMap);
    }
    Ok(())
}

fn shm_global_bind(evlh: &mut EventLoopHandle, data: &mut ShmGlobalData, _: &Client, global: wl_shm::WlShm) {
    // register an handler for this shm
    evlh.register(&global, shm_implementation(), data.clone(), None);
    // and then the custom formats
    for f in &data.formats[..] {
        global.format(*f);
    }
}

fn shm_implementation() -> wl_shm::Implementation<ShmGlobalData> {
    wl_shm::Implementation {
        create_pool: |evlh, data, _, shm, pool, fd, size| {
            if size <= 0 {
                shm.post_error(
                    wl_shm::Error::InvalidFd as u32,
                    "Invalid size for a new wl_shm_pool.".into(),
                );
                return;
            }
            let mmap_pool = match Pool::new(fd, size as usize, data.log.clone()) {
                Ok(p) => p,
                Err(()) => {
                    shm.post_error(
                        wl_shm::Error::InvalidFd as u32,
                        format!("Failed mmap of fd {}.", fd),
                    );
                    return;
                }
            };
            let arc_pool = Box::new(Arc::new(mmap_pool));
            evlh.register(
                &pool,
                shm_pool_implementation(),
                data.clone(),
                Some(destroy_shm_pool),
            );
            pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
        },
    }
}

fn destroy_shm_pool(pool: &wl_shm_pool::WlShmPool) {
    let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
    drop(arc_pool)
}

/// Details of the contents of a buffer relative to its pool
#[derive(Copy, Clone, Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Wwidth of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format,
}

struct InternalBufferData {
    pool: Arc<Pool>,
    data: BufferData,
}

fn shm_pool_implementation() -> wl_shm_pool::Implementation<ShmGlobalData> {
    wl_shm_pool::Implementation {
        create_buffer: |evlh, data, _, pool, buffer, offset, width, height, stride, format| {
            if !data.formats.contains(&format) {
                buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
                return;
            }
            let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
            let data = Box::into_raw(Box::new(InternalBufferData {
                pool: arc_pool.clone(),
                data: BufferData {
                    offset: offset,
                    width: width,
                    height: height,
                    stride: stride,
                    format: format,
                },
            }));
            evlh.register(&buffer, buffer_implementation(), (), Some(destroy_buffer));
            buffer.set_user_data(data as *mut ());
        },
        resize: |_, _, _, pool, size| {
            let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
            match arc_pool.resize(size) {
                Ok(()) => {}
                Err(ResizeError::InvalidSize) => {
                    pool.post_error(
                        wl_shm::Error::InvalidFd as u32,
                        "Invalid new size for a wl_shm_pool.".into(),
                    );
                }
                Err(ResizeError::MremapFailed) => {
                    pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
                }
            }
        },
        destroy: |_, _, _, _| {},
    }
}

fn destroy_buffer(buffer: &wl_buffer::WlBuffer) {
    let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
    drop(buffer_data)
}

fn buffer_implementation() -> wl_buffer::Implementation<()> {
    wl_buffer::Implementation {
        destroy: |_, _, _, _| {},
    }
}
<|endoftext|>


<commit_before>use webcore::value::Reference;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node};
use webapi::element::Element;
use webapi::text_node::TextNode;
use webapi::location::Location;
use webapi::parent_node::IParentNode;
use webapi::non_element_parent_node::INonElementParentNode;
use private::TODO;

/// The `Document` interface represents any web page loaded in the browser and
/// serves as an entry point into the web page's content, which is the DOM tree.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
// https://dom.spec.whatwg.org/#document
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Document")]
#[reference(subclass_of(EventTarget, Node))]
pub struct Document( Reference );

impl IEventTarget for Document {}
impl IParentNode for Document {}
impl INode for Document {}

impl INonElementParentNode for Document {}

/// A global instance of [Document](struct.Document.html).
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
pub fn document() -> Document {
    unsafe { js!( return document; ).into_reference_unchecked() }.unwrap()
}

impl Document {
    /// In an HTML document, the Document.createElement() method creates the HTML
    /// element specified by `tag`, or an HTMLUnknownElement if `tag` isn't
    /// recognized. In other documents, it creates an element with a null namespace URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelement
    pub fn create_element( &self, tag: &str ) -> Result< Element, TODO > {
        unsafe {
            Ok( js!( return @{self}.createElement( @{tag} ); ).into_reference_unchecked().unwrap() )
        }
    }

    /// Creates a new text node.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createtextnode
    pub fn create_text_node( &self, text: &str ) -> TextNode {
        unsafe {
            js!( return @{self}.createTextNode( @{text} ); ).into_reference_unchecked().unwrap()
        }
    }

    /// Returns a [Location](struct.Location.html) object which contains
    /// information about the URL of the document and provides methods
    /// for changing that URL and loading another URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/location)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-location
    pub fn location( &self ) -> Option< Location > {
        unsafe {
            js!(
                return @{self}.location;
            ).into_reference_unchecked()
        }
    }
}
<commit_msg>Add `Document::{body, head, title, set_title}` (#170)<commit_after>use webcore::value::Reference;
use webcore::try_from::TryInto;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node};
use webapi::element::Element;
use webapi::html_element::HtmlElement;
use webapi::text_node::TextNode;
use webapi::location::Location;
use webapi::parent_node::IParentNode;
use webapi::non_element_parent_node::INonElementParentNode;
use private::TODO;

/// The `Document` interface represents any web page loaded in the browser and
/// serves as an entry point into the web page's content, which is the DOM tree.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
// https://dom.spec.whatwg.org/#document
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Document")]
#[reference(subclass_of(EventTarget, Node))]
pub struct Document( Reference );

impl IEventTarget for Document {}
impl IParentNode for Document {}
impl INode for Document {}

impl INonElementParentNode for Document {}

/// A global instance of [Document](struct.Document.html).
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document)
pub fn document() -> Document {
    unsafe { js!( return document; ).into_reference_unchecked() }.unwrap()
}

impl Document {
    /// In an HTML document, the Document.createElement() method creates the HTML
    /// element specified by `tag`, or an HTMLUnknownElement if `tag` isn't
    /// recognized. In other documents, it creates an element with a null namespace URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createelement
    pub fn create_element( &self, tag: &str ) -> Result< Element, TODO > {
        unsafe {
            Ok( js!( return @{self}.createElement( @{tag} ); ).into_reference_unchecked().unwrap() )
        }
    }

    /// Creates a new text node.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
    // https://dom.spec.whatwg.org/#ref-for-dom-document-createtextnode
    pub fn create_text_node( &self, text: &str ) -> TextNode {
        unsafe {
            js!( return @{self}.createTextNode( @{text} ); ).into_reference_unchecked().unwrap()
        }
    }

    /// Returns a [Location](struct.Location.html) object which contains
    /// information about the URL of the document and provides methods
    /// for changing that URL and loading another URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/location)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-location
    pub fn location( &self ) -> Option< Location > {
        unsafe {
            js!(
                return @{self}.location;
            ).into_reference_unchecked()
        }
    }

    /// Returns the <body> or <frameset> node of the current document, or null if no such element exists.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/body)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-body
    pub fn body( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.body;
            ).into_reference_unchecked()
        }
    }

    /// Returns the <head> element of the current document. If there are more than one <head>
    /// elements, the first one is returned.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/head)
    // https://html.spec.whatwg.org/#the-document-object:dom-document-head
    pub fn head( &self ) -> Option< HtmlElement > {
        unsafe {
            js!(
                return @{self}.head;
            ).into_reference_unchecked()
        }
    }

    /// Gets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn title( &self ) -> String {
        unsafe {
            js!(
                return @{self}.title;
            ).try_into().unwrap()
        }
    }

    /// Sets the title of the document.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)
    // https://html.spec.whatwg.org/#the-document-object:document.title
    pub fn set_title( &self, title: &str ) {
        unsafe {
            js!( @(no_return) @{self}.title = @{title}; );
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::iter::FromIterator;

use registry::Registry;
use render::{RenderError, RenderContext, Directive, Evaluable, Renderable};

pub fn expand_partial(d: &Directive,
                      r: &Registry,
                      rc: &mut RenderContext)
                      -> Result<(), RenderError> {

    // try eval inline partials first
    if let Some(t) = d.template() {
        try!(t.eval(r, rc));
    }

    if rc.is_current_template(d.name()) {
        return Err(RenderError::new("Cannot include self in >"));
    }

    let tname = d.name();
    let partial = rc.get_partial(tname);
    let render_template = partial.as_ref().or(r.get_template(tname)).or(d.template());
    match render_template {
        Some(t) => {
            let context_param = d.params().get(0).and_then(|p| p.path());
            let old_path = context_param.map(|p| {
                let old_path = rc.get_path().clone();
                rc.promote_local_vars();
                let new_path = format!("{}/{}", old_path, p);
                rc.set_path(new_path);
                old_path
            });

            // @partial-block
            if let Some(t) = d.template() {
                rc.set_partial("@partial-block".to_string(), t.clone());
            }

            let hash = d.hash();
            let r = if hash.is_empty() {
                t.render(r, rc)
            } else {
                let hash_ctx = BTreeMap::from_iter(hash.iter()
                                                       .map(|(k, v)| {
                                                           (k.clone(), v.value().clone())
                                                       }));
                let mut local_rc = rc.derive();
                {
                    let mut ctx_ref = local_rc.context_mut();
                    *ctx_ref = ctx_ref.extend(&hash_ctx);
                }
                t.render(r, &mut local_rc)
            };

            if let Some(path) = old_path {
                rc.set_path(path);
                rc.demote_local_vars();
            }

            r
        }
        None => Ok(()),
    }

}

#[cfg(test)]
mod test {
    use registry::Registry;

    #[test]
    fn test() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{> t1}}").is_ok());
        assert!(handlebars.register_template_string("t1", "{{this}}").is_ok());
        assert!(handlebars.register_template_string("t2", "{{#> t99}}not there{{/t99}}").is_ok());
        assert!(handlebars.register_template_string("t3", "{{#*inline \"t31\"}}{{this}}{{/inline}}{{> t31}}").is_ok());
        assert!(handlebars.register_template_string("t4", "{{#> t5}}{{#*inline \"nav\"}}navbar{{/inline}}{{/t5}}").is_ok());
        assert!(handlebars.register_template_string("t5", "include {{> nav}}").is_ok());
        assert!(handlebars.register_template_string("t6", "{{> t1 a}}").is_ok());
        assert!(handlebars.register_template_string("t7", "{{#*inline \"t71\"}}{{a}}{{/inline}}{{> t71 a=\"world\"}}").is_ok());
        assert!(handlebars.register_template_string("t8", "{{a}}").is_ok());
        assert!(handlebars.register_template_string("t9", "{{> t8 a=2}}").is_ok());

        assert_eq!(handlebars.render("t0", &1).ok().unwrap(), "1".to_string());
        assert_eq!(handlebars.render("t2", &1).ok().unwrap(),
                   "not there".to_string());
        assert_eq!(handlebars.render("t3", &1).ok().unwrap(), "1".to_string());
        assert_eq!(handlebars.render("t4", &1).ok().unwrap(),
                   "include navbar".to_string());
        assert_eq!(handlebars.render("t6", &btreemap!{"a".to_string() => "2".to_string()})
                             .ok()
                             .unwrap(),
                   "2".to_string());
        assert_eq!(handlebars.render("t7", &1).ok().unwrap(),
                   "world".to_string());
        assert_eq!(handlebars.render("t9", &1).ok().unwrap(), "2".to_string());
    }

    #[test]
    fn test_include_partial_block() {
        let t0 = "hello {{> @partial-block}}";
        let t1 = "{{#> t0}}inner {{this}}{{/t0}}";

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t1", &true);
        assert_eq!(r0.ok().unwrap(), "hello inner true".to_string());
    }
}
<commit_msg>(fix) template name tracing [#143]<commit_after>use std::collections::BTreeMap;
use std::iter::FromIterator;

use registry::Registry;
use render::{RenderError, RenderContext, Directive, Evaluable, Renderable};

pub fn expand_partial(d: &Directive,
                      r: &Registry,
                      rc: &mut RenderContext)
                      -> Result<(), RenderError> {

    // try eval inline partials first
    if let Some(t) = d.template() {
        try!(t.eval(r, rc));
    }

    if rc.is_current_template(d.name()) {
        return Err(RenderError::new("Cannot include self in >"));
    }

    let tname = d.name();
    let partial = rc.get_partial(tname);
    let render_template = partial.as_ref().or(r.get_template(tname)).or(d.template());
    match render_template {
        Some(t) => {
            let mut local_rc = rc.derive();
            let context_param = d.params().get(0).and_then(|p| p.path());
            if let Some(p) = context_param {
                let old_path = local_rc.get_path().clone();
                local_rc.promote_local_vars();
                let new_path = format!("{}/{}", old_path, p);
                local_rc.set_path(new_path);
            };

            // @partial-block
            if let Some(t) = d.template() {
                local_rc.set_partial("@partial-block".to_string(), t.clone());
            }

            let hash = d.hash();
            let r = if hash.is_empty() {
                t.render(r, &mut local_rc)
            } else {
                let hash_ctx = BTreeMap::from_iter(hash.iter()
                                                       .map(|(k, v)| {
                                                           (k.clone(), v.value().clone())
                                                       }));
                {
                    let mut ctx_ref = local_rc.context_mut();
                    *ctx_ref = ctx_ref.extend(&hash_ctx);
                }
                t.render(r, &mut local_rc)
            };

            r
        }
        None => Ok(()),
    }

}

#[cfg(test)]
mod test {
    use registry::Registry;

    #[test]
    fn test() {
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", "{{> t1}}").is_ok());
        assert!(handlebars.register_template_string("t1", "{{this}}").is_ok());
        assert!(handlebars.register_template_string("t2", "{{#> t99}}not there{{/t99}}").is_ok());
        assert!(handlebars.register_template_string("t3", "{{#*inline \"t31\"}}{{this}}{{/inline}}{{> t31}}").is_ok());
        assert!(handlebars.register_template_string("t4", "{{#> t5}}{{#*inline \"nav\"}}navbar{{/inline}}{{/t5}}").is_ok());
        assert!(handlebars.register_template_string("t5", "include {{> nav}}").is_ok());
        assert!(handlebars.register_template_string("t6", "{{> t1 a}}").is_ok());
        assert!(handlebars.register_template_string("t7", "{{#*inline \"t71\"}}{{a}}{{/inline}}{{> t71 a=\"world\"}}").is_ok());
        assert!(handlebars.register_template_string("t8", "{{a}}").is_ok());
        assert!(handlebars.register_template_string("t9", "{{> t8 a=2}}").is_ok());

        assert_eq!(handlebars.render("t0", &1).ok().unwrap(), "1".to_string());
        assert_eq!(handlebars.render("t2", &1).ok().unwrap(),
                   "not there".to_string());
        assert_eq!(handlebars.render("t3", &1).ok().unwrap(), "1".to_string());
        assert_eq!(handlebars.render("t4", &1).ok().unwrap(),
                   "include navbar".to_string());
        assert_eq!(handlebars.render("t6", &btreemap!{"a".to_string() => "2".to_string()})
                             .ok()
                             .unwrap(),
                   "2".to_string());
        assert_eq!(handlebars.render("t7", &1).ok().unwrap(),
                   "world".to_string());
        assert_eq!(handlebars.render("t9", &1).ok().unwrap(), "2".to_string());
    }

    #[test]
    fn test_include_partial_block() {
        let t0 = "hello {{> @partial-block}}";
        let t1 = "{{#> t0}}inner {{this}}{{/t0}}";

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t1", &true);
        assert_eq!(r0.ok().unwrap(), "hello inner true".to_string());
    }

    #[test]
    fn test_self_inclusion() {
        let t0 = "hello {{> t1}} {{> t0}}";
        let t1 = "some template";
        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("t0", t0).is_ok());
        assert!(handlebars.register_template_string("t1", t1).is_ok());

        let r0 = handlebars.render("t0", &true);
        assert!(r0.is_err());
    }

    #[test]
    fn test_issue_143() {
        let main_template = "one{{> two }}three{{> two }}";
        let two_partial = "--- two ---";

        let mut handlebars = Registry::new();
        assert!(handlebars.register_template_string("template", main_template).is_ok());
        assert!(handlebars.register_template_string("two", two_partial).is_ok());

        let r0 = handlebars.render("template", &true);
        assert_eq!(r0.ok().unwrap(), "one--- two ---three--- two ---");
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use std::collections::{HashMap, HashSet};

use windows::ffi::{self, MIB_IF_ROW2, PMIB_IF_TABLE2};
use NetworkExt;
use NetworksExt;
use NetworksIter;

use winapi::shared::ifdef::NET_LUID;
use winapi::shared::winerror::NO_ERROR;

macro_rules! old_and_new {
    ($ty_:expr, $name:ident, $old:ident, $new_val:expr) => {{
        $ty_.$old = $ty_.$name;
        $ty_.$name = $new_val;
    }};
}

/// Network interfaces.
///
/// ```no_run
/// use sysinfo::{NetworksExt, System, SystemExt};
///
/// let s = System::new_all();
/// let networks = s.get_networks();
/// ```
pub struct Networks {
    interfaces: HashMap<String, NetworkData>,
}

impl Networks {
    pub(crate) fn new() -> Networks {
        Networks {
            interfaces: HashMap::new(),
        }
    }
}

impl NetworksExt for Networks {
    fn iter<'a>(&'a self) -> NetworksIter<'a> {
        NetworksIter::new(self.interfaces.iter())
    }

    fn refresh_networks_list(&mut self) {
        let mut table: PMIB_IF_TABLE2 = ::std::ptr::null_mut();
        if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR {
            return;
        }
        let mut to_be_removed = HashSet::with_capacity(self.interfaces.len());

        for key in self.interfaces.keys() {
            to_be_removed.insert(key.clone());
        }
        // In here, this is tricky: we have to filter out the software interfaces to only keep
        // the hardware ones. To do so, we first check the connection potential speed (if 0, not
        // interesting), then we check its state: if not open, not interesting either. And finally,
        // we count the members of a same group: if there is more than 1, then it's software level.
        let mut groups = HashMap::new();
        let mut indexes = Vec::new();
        let ptr = unsafe { (*table).Table.as_ptr() };
        for i in 0..unsafe { *table }.NumEntries {
            let ptr = unsafe { &*ptr.offset(i as _) };
            if ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0 {
                continue;
            } else if ptr.MediaConnectState == ffi::MediaConnectStateDisconnected
                || ptr.PhysicalAddressLength == 0
            {
                continue;
            }
            let id = vec![
                ptr.InterfaceGuid.Data2,
                ptr.InterfaceGuid.Data3,
                ptr.InterfaceGuid.Data4[0] as _,
                ptr.InterfaceGuid.Data4[1] as _,
                ptr.InterfaceGuid.Data4[2] as _,
                ptr.InterfaceGuid.Data4[3] as _,
                ptr.InterfaceGuid.Data4[4] as _,
                ptr.InterfaceGuid.Data4[5] as _,
                ptr.InterfaceGuid.Data4[6] as _,
                ptr.InterfaceGuid.Data4[7] as _,
            ];
            let entry = groups.entry(id.clone()).or_insert(0);
            *entry += 1;
            if *entry > 1 {
                continue;
            }
            indexes.push((i, id));
        }
        for (i, id) in indexes {
            let ptr = unsafe { &*ptr.offset(i as _) };
            if *groups.get(&id).unwrap_or(&0) > 1 {
                continue;
            }
            let mut pos = 0;
            for x in ptr.Alias.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let interface_name = match String::from_utf16(&ptr.Alias[..pos]) {
                Ok(s) => s,
                _ => continue,
            };
            to_be_removed.remove(&interface_name);
            let mut interface =
                self.interfaces
                    .entry(interface_name)
                    .or_insert_with(|| NetworkData {
                        id: ptr.InterfaceLuid,
                        current_out: ptr.OutOctets,
                        old_out: ptr.OutOctets,
                        current_in: ptr.InOctets,
                        old_in: ptr.InOctets,
                    });
            old_and_new!(interface, current_out, old_out, ptr.OutOctets);
            old_and_new!(interface, current_in, old_in, ptr.InOctets);
        }
        unsafe {
            ffi::FreeMibTable(table as _);
        }
        for key in to_be_removed {
            self.interfaces.remove(&key);
        }
    }

    fn refresh(&mut self) {
        let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() };
        for (_, interface) in self.interfaces.iter_mut() {
            entry.InterfaceLuid = interface.id;
            entry.InterfaceIndex = 0; // to prevent the function to pick this one as index
            if unsafe { ffi::GetIfEntry2(&mut entry) } != NO_ERROR {
                continue;
            }
            old_and_new!(interface, current_out, old_out, entry.OutOctets);
            old_and_new!(interface, current_in, old_in, entry.InOctets);
        }
    }
}

/// Contains network information.
pub struct NetworkData {
    id: NET_LUID,
    current_out: u64,
    old_out: u64,
    current_in: u64,
    old_in: u64,
}

impl NetworkExt for NetworkData {
    fn get_income(&self) -> u64 {
        self.current_in - self.old_in
    }

    fn get_outcome(&self) -> u64 {
        self.current_out - self.old_out
    }

    fn get_total_income(&self) -> u64 {
        self.current_in
    }

    fn get_total_outcome(&self) -> u64 {
        self.current_out
    }
}
<commit_msg>Extend windows network interface<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use std::collections::{HashMap, HashSet};

use windows::ffi::{self, MIB_IF_ROW2, PMIB_IF_TABLE2};
use NetworkExt;
use NetworksExt;
use NetworksIter;

use winapi::shared::ifdef::NET_LUID;
use winapi::shared::winerror::NO_ERROR;

macro_rules! old_and_new {
    ($ty_:expr, $name:ident, $old:ident, $new_val:expr) => {{
        $ty_.$old = $ty_.$name;
        $ty_.$name = $new_val;
    }};
}

/// Network interfaces.
///
/// ```no_run
/// use sysinfo::{NetworksExt, System, SystemExt};
///
/// let s = System::new_all();
/// let networks = s.get_networks();
/// ```
pub struct Networks {
    interfaces: HashMap<String, NetworkData>,
}

impl Networks {
    pub(crate) fn new() -> Networks {
        Networks {
            interfaces: HashMap::new(),
        }
    }
}

impl NetworksExt for Networks {
    fn iter<'a>(&'a self) -> NetworksIter<'a> {
        NetworksIter::new(self.interfaces.iter())
    }

    fn refresh_networks_list(&mut self) {
        let mut table: PMIB_IF_TABLE2 = ::std::ptr::null_mut();
        if unsafe { ffi::GetIfTable2(&mut table) } != NO_ERROR {
            return;
        }
        let mut to_be_removed = HashSet::with_capacity(self.interfaces.len());

        for key in self.interfaces.keys() {
            to_be_removed.insert(key.clone());
        }
        // In here, this is tricky: we have to filter out the software interfaces to only keep
        // the hardware ones. To do so, we first check the connection potential speed (if 0, not
        // interesting), then we check its state: if not open, not interesting either. And finally,
        // we count the members of a same group: if there is more than 1, then it's software level.
        let mut groups = HashMap::new();
        let mut indexes = Vec::new();
        let ptr = unsafe { (*table).Table.as_ptr() };
        for i in 0..unsafe { *table }.NumEntries {
            let ptr = unsafe { &*ptr.offset(i as _) };
            if ptr.TransmitLinkSpeed == 0 && ptr.ReceiveLinkSpeed == 0 {
                continue;
            } else if ptr.MediaConnectState == ffi::MediaConnectStateDisconnected
                || ptr.PhysicalAddressLength == 0
            {
                continue;
            }
            let id = vec![
                ptr.InterfaceGuid.Data2,
                ptr.InterfaceGuid.Data3,
                ptr.InterfaceGuid.Data4[0] as _,
                ptr.InterfaceGuid.Data4[1] as _,
                ptr.InterfaceGuid.Data4[2] as _,
                ptr.InterfaceGuid.Data4[3] as _,
                ptr.InterfaceGuid.Data4[4] as _,
                ptr.InterfaceGuid.Data4[5] as _,
                ptr.InterfaceGuid.Data4[6] as _,
                ptr.InterfaceGuid.Data4[7] as _,
            ];
            let entry = groups.entry(id.clone()).or_insert(0);
            *entry += 1;
            if *entry > 1 {
                continue;
            }
            indexes.push((i, id));
        }
        for (i, id) in indexes {
            let ptr = unsafe { &*ptr.offset(i as _) };
            if *groups.get(&id).unwrap_or(&0) > 1 {
                continue;
            }
            let mut pos = 0;
            for x in ptr.Alias.iter() {
                if *x == 0 {
                    break;
                }
                pos += 1;
            }
            let interface_name = match String::from_utf16(&ptr.Alias[..pos]) {
                Ok(s) => s,
                _ => continue,
            };
            to_be_removed.remove(&interface_name);
            let mut interface =
                self.interfaces
                    .entry(interface_name)
                    .or_insert_with(|| NetworkData {
                        id: ptr.InterfaceLuid,
                        current_out: ptr.OutOctets,
                        old_out: 0,
                        current_in: ptr.InOctets,
                        old_in: 0,
                        packets_in: ptr.InUcastPkts + ptr.InNUcastPkts,
                        old_packets_in: 0,
                        packets_out: ptr.OutUcastPkts + ptr.OutNUcastPkts,
                        old_packets_out: 0,
                        errors_in: ptr.InErrors,
                        old_errors_in: 0,
                        errors_out: ptr.OutErrors,
                        old_errors_out: 0,
                    });
            old_and_new!(interface, current_out, old_out, ptr.OutOctets);
            old_and_new!(interface, current_in, old_in, ptr.InOctets);
            old_and_new!(interface, packets_in, old_packets_in, ptr.InUcastPkts + ptr.InNUcastPkts);
            old_and_new!(interface, packets_out, old_packets_out, ptr.OutUcastPkts + ptr.OutNUcastPkts);
            old_and_new!(interface, errors_in, old_errors_in, ptr.InErrors);
            old_and_new!(interface, errors_out, old_errors_out, ptr.OutErrors);
        }
        unsafe {
            ffi::FreeMibTable(table as _);
        }
        for key in to_be_removed {
            self.interfaces.remove(&key);
        }
    }

    fn refresh(&mut self) {
        let mut entry: MIB_IF_ROW2 = unsafe { ::std::mem::MaybeUninit::uninit().assume_init() };
        for (_, interface) in self.interfaces.iter_mut() {
            entry.InterfaceLuid = interface.id;
            entry.InterfaceIndex = 0; // to prevent the function to pick this one as index
            if unsafe { ffi::GetIfEntry2(&mut entry) } != NO_ERROR {
                continue;
            }
            old_and_new!(interface, current_out, old_out, entry.OutOctets);
            old_and_new!(interface, current_in, old_in, entry.InOctets);
            old_and_new!(interface, packets_in, old_packets_in, entry.InUcastPkts + entry.InNUcastPkts);
            old_and_new!(interface, packets_out, old_packets_out, entry.OutUcastPkts + entry.OutNUcastPkts);
            old_and_new!(interface, errors_in, old_errors_in, entry.InErrors);
            old_and_new!(interface, errors_out, old_errors_out, entry.OutErrors);
        }
    }
}

/// Contains network information.
pub struct NetworkData {
    id: NET_LUID,
    current_out: u64,
    old_out: u64,
    current_in: u64,
    old_in: u64,
    packets_in: u64,
    old_packets_in: u64,
    packets_out: u64,
    old_packets_out: u64,
    errors_in: u64,
    old_errors_in: u64,
    errors_out: u64,
    old_errors_out: u64,
}

impl NetworkExt for NetworkData {
    fn get_income(&self) -> u64 {
        self.current_in - self.old_in
    }

    fn get_total_income(&self) -> u64 {
        self.current_in
    }

    fn get_outcome(&self) -> u64 {
        self.current_out - self.old_out
    }

    fn get_total_outcome(&self) -> u64 {
        self.current_out
    }

    fn get_packets_income(&self) -> u64 {
        self.packets_in - self.old_packets_in
    }

    fn get_total_packets_income(&self) -> u64 {
        self.packets_in
    }

    fn get_packets_outcome(&self) -> u64 {
        self.packets_out - self.old_packets_out
    }

    fn get_total_packets_outcome(&self) -> u64 {
        self.packets_out
    }

    fn get_errors_income(&self) -> u64 {
        self.errors_in - self.old_errors_in
    }

    fn get_total_errors_income(&self) -> u64 {
        self.errors_in
    }

    fn get_errors_outcome(&self) -> u64 {
        self.errors_out - self.old_errors_out
    }

    fn get_total_errors_outcome(&self) -> u64 {
        self.errors_out
    }
}
<|endoftext|>


<commit_before>//! # Parse `.proto` files
//!
//! Parse `.proto` file definitions, **not** the protobuf text format serialization.
//!
//! Files can be parsed using pure Rust parser (mod `pure`)
//! or using the `protoc` command (mod `protoc`).
//!
//! This crate is not meant to be used directly, but rather through the `protobuf-codegen` crate.
//! If you think this crate might be useful to you,
//! please [consider creating an issue](https://github.com/stepancheg/rust-protobuf/issues/new),
//! until that this crate is considered to have **no stable API**.

mod case_convert;
mod parse_and_typecheck;
mod parser;
mod path;
mod proto;
mod proto_path;
mod protobuf_abs_path;
mod protobuf_ident;
mod protobuf_path;
mod protobuf_rel_path;
pub mod protoc;
pub mod pure;
mod rel_path;
mod test_against_protobuf_protos;
mod which_parser;

// Public API
// Non-public API used by codegen crate.
pub use case_convert::*;
pub use parse_and_typecheck::*;
pub use parser::Parser;
pub use proto_path::*;
use protobuf::reflect::FileDescriptor;
pub use protobuf_abs_path::*;
pub use protobuf_ident::*;
pub use protobuf_rel_path::*;

use crate::pure::model;

#[derive(Clone)]
pub(crate) struct FileDescriptorPair {
    pub(crate) parsed: model::FileDescriptor,
    pub(crate) descriptor_proto: protobuf::descriptor::FileDescriptorProto,
    pub(crate) descriptor: FileDescriptor,
}
<commit_msg>Hide empty `protoc` mod from protobuf-parse crate<commit_after>//! # Parse `.proto` files
//!
//! Parse `.proto` file definitions, **not** the protobuf text format serialization.
//!
//! Files can be parsed using pure Rust parser (mod `pure`)
//! or using the `protoc` command (mod `protoc`).
//!
//! This crate is not meant to be used directly, but rather through the `protobuf-codegen` crate.
//! If you think this crate might be useful to you,
//! please [consider creating an issue](https://github.com/stepancheg/rust-protobuf/issues/new),
//! until that this crate is considered to have **no stable API**.

mod case_convert;
mod parse_and_typecheck;
mod parser;
mod path;
mod proto;
mod proto_path;
mod protobuf_abs_path;
mod protobuf_ident;
mod protobuf_path;
mod protobuf_rel_path;
pub(crate) mod protoc;
pub mod pure;
mod rel_path;
mod test_against_protobuf_protos;
mod which_parser;

// Public API
// Non-public API used by codegen crate.
pub use case_convert::*;
pub use parse_and_typecheck::*;
pub use parser::Parser;
pub use proto_path::*;
use protobuf::reflect::FileDescriptor;
pub use protobuf_abs_path::*;
pub use protobuf_ident::*;
pub use protobuf_rel_path::*;

use crate::pure::model;

#[derive(Clone)]
pub(crate) struct FileDescriptorPair {
    pub(crate) parsed: model::FileDescriptor,
    pub(crate) descriptor_proto: protobuf::descriptor::FileDescriptorProto,
    pub(crate) descriptor: FileDescriptor,
}
<|endoftext|>


<commit_before>use core::libc::c_int;
use core::libc;

pub struct Fd(c_int);

impl Drop for Fd {
    fn finalize(&self) {
        unsafe {
            libc::close(**self);
        }
    }
}

fn main() {
}

<commit_msg>another pub fn for check-fast<commit_after>use core::libc::c_int;
use core::libc;

pub struct Fd(c_int);

impl Drop for Fd {
    fn finalize(&self) {
        unsafe {
            libc::close(**self);
        }
    }
}

pub fn main() {
}

<|endoftext|>


<commit_before>use mqtt3::{MqttRead, MqttWrite};
use std::io::{self, Read, Write};
use std::net::Shutdown;
use {NetworkStream, NetworkReader, NetworkWriter};

pub struct Connection {
    stream: NetworkStream,
    reader: NetworkReader,
    writer: NetworkWriter
}

impl Connection {
    pub fn new(stream: &NetworkStream) -> io::Result<Connection> {
        Ok(Connection {
            stream: try!(stream.try_clone()),
            reader: NetworkReader::new(try!(stream.try_clone())),
            writer: NetworkWriter::new(try!(stream.try_clone()))
        })
    }

    pub fn terminate(&self) -> io::Result<()> {
        self.stream.shutdown(Shutdown::Both)
    }

    pub fn split(self) -> (NetworkReader, NetworkWriter) {
        (self.reader, self.writer)
    }
}

impl Write for Connection {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.writer.write(msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

impl Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.reader.read(buf)
    }
}

impl MqttRead for Connection {}
impl MqttWrite for Connection {}
<commit_msg>netopt: Add set_read_timeout to Connection<commit_after>use mqtt3::{MqttRead, MqttWrite};
use std::io::{self, Read, Write};
use std::net::Shutdown;
use std::time::Duration;
use {NetworkStream, NetworkReader, NetworkWriter};

pub struct Connection {
    stream: NetworkStream,
    reader: NetworkReader,
    writer: NetworkWriter
}

impl Connection {
    pub fn new(stream: &NetworkStream) -> io::Result<Connection> {
        Ok(Connection {
            stream: try!(stream.try_clone()),
            reader: NetworkReader::new(try!(stream.try_clone())),
            writer: NetworkWriter::new(try!(stream.try_clone()))
        })
    }

    pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.stream.set_read_timeout(dur)
    }

    pub fn terminate(&self) -> io::Result<()> {
        self.stream.shutdown(Shutdown::Both)
    }

    pub fn split(self) -> (NetworkReader, NetworkWriter) {
        (self.reader, self.writer)
    }
}

impl Write for Connection {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.writer.write(msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

impl Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.reader.read(buf)
    }
}

impl MqttRead for Connection {}
impl MqttWrite for Connection {}
<|endoftext|>