<commit_before>use command::Command;
use tmux;

pub fn main(commands: &Vec<Command>) -> () {
    for c in commands {
        match c {
            &Command::Session(ref c)    => tmux::new_session(&c.name, &c.tmp_window_name),
            &Command::Window(ref c)     => tmux::new_window(&c.session_name, &c.name, &c.root),
            &Command::Split(ref c)      => tmux::split_window(&c.target, &c.root),
            &Command::Layout(ref c)     => tmux::layout(&c.target, &c.layout),
            &Command::SendKeys(ref c)   => tmux::send_keys(&c.target, &c.exec),
            &Command::Attach(ref c)     => tmux::attach(&c.name),
            &Command::KillWindow(ref c) => tmux::kill_window(&c.name)
        }
    };
}
<commit_msg>Add mod and function docs to the processor<commit_after>//! Processes the stack of Commands and matches them to the appropriate tmux
/// call.

use command::Command;
use tmux;

/// Processing of the commands. A simple match occurs to handle the tmux calls
/// needed based off the command provided. The commands are processed first in,
/// first out. So simply looping the Vec is enough to execute all needed
/// instructions.
///
/// # Example
///
/// ```
/// let commands: Vec<Command> = vec!(
///   Command::Session(Session{...}),
///   Command::Attach(Attach{...})
/// );
///
/// main(&commands);
/// ```
///
/// commands: The stack of commands to process.
pub fn main(commands: &Vec<Command>) -> () {
    for c in commands {
        match c {
            &Command::Session(ref c)    => tmux::new_session(&c.name, &c.tmp_window_name),
            &Command::Window(ref c)     => tmux::new_window(&c.session_name, &c.name, &c.root),
            &Command::Split(ref c)      => tmux::split_window(&c.target, &c.root),
            &Command::Layout(ref c)     => tmux::layout(&c.target, &c.layout),
            &Command::SendKeys(ref c)   => tmux::send_keys(&c.target, &c.exec),
            &Command::Attach(ref c)     => tmux::attach(&c.name),
            &Command::KillWindow(ref c) => tmux::kill_window(&c.name)
        }
    };
}
<|endoftext|>


<commit_before>extern crate pgn_reader;
extern crate memmap;
extern crate madvise;
extern crate btoi;
extern crate rand;
extern crate reqwest;

use std::env;
use std::mem;
use std::str;
use std::cmp::min;
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use memmap::Mmap;
use madvise::{AccessPattern, AdviseMemory};
use pgn_reader::{Visitor, Skip, Reader, San};
use btoi::ParseIntegerError;
use rand::{thread_rng, Rng};
use rand::distributions::OpenClosed01;

const BATCH_SIZE: usize = 50;

const MAX_PLIES: usize = 50;

#[derive(Debug)]
enum TimeControl {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

#[derive(Debug)]
struct TimeControlError;

impl From<ParseIntegerError> for TimeControlError {
    fn from(_: ParseIntegerError) -> TimeControlError {
        TimeControlError { }
    }
}

impl TimeControl {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> TimeControl {
        let total = seconds + 40 * increment;

        if total < 30 {
            TimeControl::UltraBullet
        } else if total < 180 {
            TimeControl::Bullet
        } else if total < 480 {
            TimeControl::Blitz
        } else if total < 1500 {
            TimeControl::Rapid
        } else if total < 21_600 {
            TimeControl::Classical
        } else {
            TimeControl::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<TimeControl, TimeControlError> {
        if bytes == b"-" {
            return Ok(TimeControl::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        let increment = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        Ok(TimeControl::from_seconds_and_increment(seconds, increment))
    }
}

struct Indexer<'pgn> {
    client: reqwest::blocking::Client,

    filename: String,
    date: &'pgn [u8],

    white_elo: i16,
    black_elo: i16,
    time_control: TimeControl,
    skip: bool,

    current_game: Vec<u8>,
    plies: usize,
    standard: bool,

    batch: Vec<u8>,
    batch_size: usize,
}

impl<'pgn> Indexer<'pgn> {
    fn new(filename: &str) -> Indexer {
        Indexer {
            client: reqwest::blocking::Client::builder().timeout(Duration::from_secs(60)).build().expect("client"),

            filename: filename.into(),
            date: b"0000.00.00",

            white_elo: 0,
            black_elo: 0,
            time_control: TimeControl::Correspondence,
            skip: true,

            current_game: Vec::new(),
            plies: 0,
            standard: true,

            batch: Vec::new(),
            batch_size: 0,
        }
    }

    fn send(&mut self) {
        if self.batch_size > 0 {
            self.batch_size = 0;

            let mut res = self.client
                .put("http://127.0.0.1:9000/import/lichess")
                .header("Content-Type", "application/vnd.chess-pgn;charset=utf-8")
                .body(mem::replace(&mut self.batch, Vec::new()))
                .send().expect("send batch");

            let mut answer = String::new();
            res.read_to_string(&mut answer).expect("decode response");
            println!("{} d: {} t: {}", self.filename, str::from_utf8(self.date).expect("date is valid utf8"), answer);
            assert!(res.status().is_success());
        }
    }
}

impl<'pgn> Visitor<'pgn> for Indexer<'pgn> {
    type Result = ();

    fn begin_game(&mut self) {
        self.current_game.clear();
        self.plies = 0;
    }

    fn begin_headers(&mut self) {
        self.white_elo = 0;
        self.black_elo = 0;
        self.time_control = TimeControl::Correspondence;
        self.standard = true;
    }

    fn header(&mut self, key: &'pgn [u8], value: &'pgn [u8]) {
        if key == b"WhiteElo" {
            self.white_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("WhiteElo") };
        } else if key == b"BlackElo" {
            self.black_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("BlackElo") };
        } else if key == b"TimeControl" {
            self.time_control = TimeControl::from_bytes(value).expect("TimeControl");
        } else if key == b"Variant" {
            self.standard = value == b"Standard";
            if self.standard {
                return; // we add this unconditionally later
            }
        } else if key == b"Date" || key == b"UTCDate" {
            self.date = value;
        }

        let (key, value) = if key == b"Site" {
            (&b"LichessID"[..], value.rsplitn(2, |ch| *ch == b'/').next().expect("Site"))
        } else {
            (key, value)
        };

        self.current_game.push(b'[');
        self.current_game.extend(key);
        self.current_game.extend(b" \"");
        self.current_game.extend(value);
        self.current_game.extend(b"\"]\n");
    }

    fn end_headers(&mut self) -> Skip {
        let rating = (self.white_elo + self.black_elo) / 2;

        let probability = if self.standard {
            self.current_game.extend(b"[Variant \"Standard\"]\n");

            match self.time_control {
                TimeControl::Correspondence | TimeControl::Classical => 1.0,
                TimeControl::Rapid if rating >= 2000 => 1.0,
                TimeControl::Rapid if rating >= 1800 => 2.0 / 5.0,
                TimeControl::Rapid => 1.0 / 8.0,
                TimeControl::Blitz if rating >= 2000 => 1.0,
                TimeControl::Blitz if rating >= 1800 => 1.0 / 4.0,
                TimeControl::Blitz => 1.0 / 15.0,
                TimeControl::Bullet if rating >= 2300 => 1.0,
                TimeControl::Bullet if rating >= 2200 => 4.0 / 5.0,
                TimeControl::Bullet if rating >= 2000 => 1.0 / 4.0,
                TimeControl::Bullet if rating >= 1800 => 1.0 / 7.0,
                _ => 1.0 / 20.0,
            }
        } else {
            if rating >= 1600 { 1.0 } else { 0.5 } // variant games
        };

        self.current_game.push(b'\n');

        let rnd = thread_rng().sample(OpenClosed01);
        let accept = min(self.white_elo, self.black_elo) >= 1500 && probability >= rnd;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: San) {
        if self.plies < MAX_PLIES {
            if self.plies > 0 {
                self.current_game.push(b' ');
            }

            self.current_game.extend(san.to_string().as_bytes());
            self.plies += 1;
        }
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self, _game: &'pgn [u8]) {
        if !self.skip && self.plies > 8 {
            if self.batch_size >= BATCH_SIZE {
                self.send();
            }

            if self.batch_size > 0 {
                self.batch.extend(b"\n\n\n");
            }

            self.batch.extend(&self.current_game);
            self.batch_size += 1;
        }
    }
}

fn main() {
    for arg in env::args().skip(1) {
        eprintln!("% indexing lichess games from {} ...", arg);
        let file = File::open(&arg).expect("fopen");
        if file.metadata().expect("meta").len() != 0 {
            let pgn = unsafe { Mmap::map(&file).expect("mmap") };
            pgn.advise_memory_access(AccessPattern::Sequential).expect("madvise");

            let mut indexer = Indexer::new(&arg);
            Reader::new(&mut indexer, &pgn[..]).read_all();
            indexer.send(); // send last
        }
    }
}
<commit_msg>let index-pgn skip bot games (fixes ornicar/lila#8392)<commit_after>extern crate pgn_reader;
extern crate memmap;
extern crate madvise;
extern crate btoi;
extern crate rand;
extern crate reqwest;

use std::env;
use std::mem;
use std::str;
use std::cmp::min;
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use memmap::Mmap;
use madvise::{AccessPattern, AdviseMemory};
use pgn_reader::{Visitor, Skip, Reader, San};
use btoi::ParseIntegerError;
use rand::{thread_rng, Rng};
use rand::distributions::OpenClosed01;

const BATCH_SIZE: usize = 50;

const MAX_PLIES: usize = 50;

#[derive(Debug)]
enum TimeControl {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

#[derive(Debug)]
struct TimeControlError;

impl From<ParseIntegerError> for TimeControlError {
    fn from(_: ParseIntegerError) -> TimeControlError {
        TimeControlError { }
    }
}

impl TimeControl {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> TimeControl {
        let total = seconds + 40 * increment;

        if total < 30 {
            TimeControl::UltraBullet
        } else if total < 180 {
            TimeControl::Bullet
        } else if total < 480 {
            TimeControl::Blitz
        } else if total < 1500 {
            TimeControl::Rapid
        } else if total < 21_600 {
            TimeControl::Classical
        } else {
            TimeControl::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<TimeControl, TimeControlError> {
        if bytes == b"-" {
            return Ok(TimeControl::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        let increment = btoi::btou(parts.next().ok_or(TimeControlError)?)?;
        Ok(TimeControl::from_seconds_and_increment(seconds, increment))
    }
}

struct Indexer<'pgn> {
    client: reqwest::blocking::Client,

    filename: String,
    date: &'pgn [u8],

    white_elo: i16,
    black_elo: i16,
    time_control: TimeControl,
    bot: bool,
    skip: bool,

    current_game: Vec<u8>,
    plies: usize,
    standard: bool,

    batch: Vec<u8>,
    batch_size: usize,
}

impl<'pgn> Indexer<'pgn> {
    fn new(filename: &str) -> Indexer {
        Indexer {
            client: reqwest::blocking::Client::builder().timeout(Duration::from_secs(60)).build().expect("client"),

            filename: filename.into(),
            date: b"0000.00.00",

            white_elo: 0,
            black_elo: 0,
            time_control: TimeControl::Correspondence,
            bot: false,
            skip: true,

            current_game: Vec::new(),
            plies: 0,
            standard: true,

            batch: Vec::new(),
            batch_size: 0,
        }
    }

    fn send(&mut self) {
        if self.batch_size > 0 {
            self.batch_size = 0;

            let mut res = self.client
                .put("http://127.0.0.1:9000/import/lichess")
                .header("Content-Type", "application/vnd.chess-pgn;charset=utf-8")
                .body(mem::replace(&mut self.batch, Vec::new()))
                .send().expect("send batch");

            let mut answer = String::new();
            res.read_to_string(&mut answer).expect("decode response");
            println!("{} d: {} t: {}", self.filename, str::from_utf8(self.date).expect("date is valid utf8"), answer);
            assert!(res.status().is_success());
        }
    }
}

impl<'pgn> Visitor<'pgn> for Indexer<'pgn> {
    type Result = ();

    fn begin_game(&mut self) {
        self.current_game.clear();
        self.plies = 0;
    }

    fn begin_headers(&mut self) {
        self.white_elo = 0;
        self.black_elo = 0;
        self.time_control = TimeControl::Correspondence;
        self.standard = true;
        self.bot = false;
    }

    fn header(&mut self, key: &'pgn [u8], value: &'pgn [u8]) {
        if key == b"WhiteElo" {
            self.white_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("WhiteElo") };
        } else if key == b"BlackElo" {
            self.black_elo = if value == b"?" { 0 } else { btoi::btoi(value).expect("BlackElo") };
        } else if key == b"TimeControl" {
            self.time_control = TimeControl::from_bytes(value).expect("TimeControl");
        } else if key == b"Variant" {
            self.standard = value == b"Standard";
            if self.standard {
                return; // we add this unconditionally later
            }
        } else if key == b"Date" || key == b"UTCDate" {
            self.date = value;
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value == b"BOT" {
                self.bot = true;
            }
        }

        let (key, value) = if key == b"Site" {
            (&b"LichessID"[..], value.rsplitn(2, |ch| *ch == b'/').next().expect("Site"))
        } else {
            (key, value)
        };

        self.current_game.push(b'[');
        self.current_game.extend(key);
        self.current_game.extend(b" \"");
        self.current_game.extend(value);
        self.current_game.extend(b"\"]\n");
    }

    fn end_headers(&mut self) -> Skip {
        let rating = (self.white_elo + self.black_elo) / 2;

        let probability = if self.standard {
            self.current_game.extend(b"[Variant \"Standard\"]\n");

            match self.time_control {
                TimeControl::Correspondence | TimeControl::Classical => 1.0,
                TimeControl::Rapid if rating >= 2000 => 1.0,
                TimeControl::Rapid if rating >= 1800 => 2.0 / 5.0,
                TimeControl::Rapid => 1.0 / 8.0,
                TimeControl::Blitz if rating >= 2000 => 1.0,
                TimeControl::Blitz if rating >= 1800 => 1.0 / 4.0,
                TimeControl::Blitz => 1.0 / 15.0,
                TimeControl::Bullet if rating >= 2300 => 1.0,
                TimeControl::Bullet if rating >= 2200 => 4.0 / 5.0,
                TimeControl::Bullet if rating >= 2000 => 1.0 / 4.0,
                TimeControl::Bullet if rating >= 1800 => 1.0 / 7.0,
                _ => 1.0 / 20.0,
            }
        } else {
            if rating >= 1600 { 1.0 } else { 0.5 } // variant games
        };

        self.current_game.push(b'\n');

        let rnd = thread_rng().sample(OpenClosed01);
        let accept = min(self.white_elo, self.black_elo) >= 1500 && probability >= rnd && !self.bot;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: San) {
        if self.plies < MAX_PLIES {
            if self.plies > 0 {
                self.current_game.push(b' ');
            }

            self.current_game.extend(san.to_string().as_bytes());
            self.plies += 1;
        }
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self, _game: &'pgn [u8]) {
        if !self.skip && self.plies > 8 {
            if self.batch_size >= BATCH_SIZE {
                self.send();
            }

            if self.batch_size > 0 {
                self.batch.extend(b"\n\n\n");
            }

            self.batch.extend(&self.current_game);
            self.batch_size += 1;
        }
    }
}

fn main() {
    for arg in env::args().skip(1) {
        eprintln!("% indexing lichess games from {} ...", arg);
        let file = File::open(&arg).expect("fopen");
        if file.metadata().expect("meta").len() != 0 {
            let pgn = unsafe { Mmap::map(&file).expect("mmap") };
            pgn.advise_memory_access(AccessPattern::Sequential).expect("madvise");

            let mut indexer = Indexer::new(&arg);
            Reader::new(&mut indexer, &pgn[..]).read_all();
            indexer.send(); // send last
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//!
//! extern crate syn;
//! extern crate proc_macro;
//! extern crate proc_macro2;
//!
//! use syn::Type;
//! use syn::spanned::Spanned;
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, Tokens};

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.2/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span,
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span(),
            None => Span::call_site(),
        }
    }
}
<commit_msg>Update Spanned implementation when built with semver_exempt<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//!
//! extern crate syn;
//! extern crate proc_macro;
//! extern crate proc_macro2;
//!
//! use syn::Type;
//! use syn::spanned::Spanned;
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.

use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, Tokens};

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.2/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span(),
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span()) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = Tokens::new();
        self.to_tokens(&mut tokens);
        let token_stream = TokenStream::from(tokens);
        let mut iter = token_stream.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span(),
            None => Span::call_site(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//!
//! extern crate syn;
//! extern crate proc_macro;
//! extern crate proc_macro2;
//!
//! use syn::Type;
//! use syn::spanned::Spanned;
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.

use proc_macro2::{Span, TokenStream};
use quote::ToTokens;

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.2/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = TokenStream::new();
        self.to_tokens(&mut tokens);
        let mut iter = tokens.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span(),
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span()) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = TokenStream::new();
        self.to_tokens(&mut tokens);
        let mut iter = tokens.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span(),
            None => Span::call_site(),
        }
    }
}
<commit_msg>Seal the Spanned trait<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```
//! #[macro_use]
//! extern crate quote;
//!
//! extern crate syn;
//! extern crate proc_macro;
//! extern crate proc_macro2;
//!
//! use syn::Type;
//! use syn::spanned::Spanned;
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.

use proc_macro2::{Span, TokenStream};
use quote::ToTokens;

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate. It is sealed and cannot be implemented
/// outside of the Syn crate other than by implementing `ToTokens`.
///
/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
///
/// See the [module documentation] for an example.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned: private::Sealed {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.2/proc_macro2/struct.Span.html#method.call_site
    fn span(&self) -> Span;
}

mod private {
    use quote::ToTokens;
    pub trait Sealed {}
    impl<T: ToTokens> Sealed for T {}
}

impl<T> Spanned for T
where
    T: ToTokens,
{
    #[cfg(procmacro2_semver_exempt)]
    fn span(&self) -> Span {
        let mut tokens = TokenStream::new();
        self.to_tokens(&mut tokens);
        let mut iter = tokens.into_iter();
        let mut span = match iter.next() {
            Some(tt) => tt.span(),
            None => {
                return Span::call_site();
            }
        };
        for tt in iter {
            if let Some(joined) = span.join(tt.span()) {
                span = joined;
            }
        }
        span
    }

    #[cfg(not(procmacro2_semver_exempt))]
    fn span(&self) -> Span {
        let mut tokens = TokenStream::new();
        self.to_tokens(&mut tokens);
        let mut iter = tokens.into_iter();

        // We can't join spans without procmacro2_semver_exempt so just grab the
        // first one.
        match iter.next() {
            Some(tt) => tt.span(),
            None => Span::call_site(),
        }
    }
}
<|endoftext|>


<commit_before>use nalgebra::DMatrix;
use std::ops::{Index, IndexMut};

/// The game's grid, internally represented by matrices provided by the nalgebra crate.
pub struct Grid {
    matrix: DMatrix<bool>,
}

impl Grid {
    /// Create a new grid with the specified dimensions. All cells default to `false`.
    pub fn new(rows: usize, columns: usize) -> Grid {
        Grid { matrix: DMatrix::from_element(rows, columns, false) }
    }

    /// The number of columns in the grid.
    pub fn cols(&self) -> usize {
        self.matrix.ncols()
    }

    /// The number of rows in the grid.
    pub fn rows(&self) -> usize {
        self.matrix.nrows()
    }
}

impl Index<(usize, usize)> for Grid {
    type Output = bool;

    fn index(&self, index: (usize, usize)) -> &bool {
        &self.matrix[index]
    }
}

impl IndexMut<(usize, usize)> for Grid {
    fn index_mut(&mut self, index: (usize, usize)) -> &mut bool {
        &mut self.matrix[index]
    }
}
<commit_msg>Voeg tests toe<commit_after>use nalgebra::DMatrix;
use std::ops::{Index, IndexMut};

/// The game's grid, internally represented by matrices provided by the nalgebra crate.
pub struct Grid {
    matrix: DMatrix<bool>,
}

impl Grid {
    /// Create a new grid with the specified dimensions. All cells default to `false`.
    pub fn new(rows: usize, columns: usize) -> Grid {
        Grid { matrix: DMatrix::from_element(rows, columns, false) }
    }

    /// The number of columns in the grid.
    pub fn cols(&self) -> usize {
        self.matrix.ncols()
    }

    /// The number of rows in the grid.
    pub fn rows(&self) -> usize {
        self.matrix.nrows()
    }
}

impl Index<(usize, usize)> for Grid {
    type Output = bool;

    fn index(&self, index: (usize, usize)) -> &bool {
        &self.matrix[index]
    }
}

impl IndexMut<(usize, usize)> for Grid {
    fn index_mut(&mut self, index: (usize, usize)) -> &mut bool {
        &mut self.matrix[index]
    }
}

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

    #[test]
    fn bounds_are_reported_correctly() {
        let grid = Grid::new(10, 10);

        assert_eq!(10, grid.rows());
        assert_eq!(10, grid.cols());

        assert_eq!(false, grid[(9, 9)]);
    }

    #[test]
    #[should_panic]
    fn horizontal_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(10, 9)];
    }

    #[test]
    #[should_panic]
    fn vertical_bound_should_overflow() {
        let grid = Grid::new(10, 10);

        grid[(9, 10)];
    }

    #[test]
    fn indexing_works() {
        let mut grid = Grid::new(10, 10);

        for i in 0..10 {
            grid[(i, 0)] = true;
        }

        for x in 0..10 {
            for y in 0..10 {
                if y == 0 {
                    assert_eq!(true, grid[(x, y)])
                } else {
                    assert_eq!(false, grid[(x, y)])
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*!
Rust bindings to the [sodium library](https://github.com/jedisct1/libsodium).

Sodium is a portable implementation of Dan Bernsteins [NaCl: Networking and
Cryptography library](http://nacl.cr.yp.to)

For most users, if you want public-key (asymmetric) cryptography you should use
the functions in `crypto::asymmetricbox` for encryption/decryption.

If you want secret-key (symmetric) cryptography you should be using the
functions in `crypto::secretbox` for encryption/decryption.

For public-key signatures you should use the functions in `crypto::sign` for
signature creation and verification.

Unless you know what you're doing you most certainly don't want to use the
functions in `crypto::scalarmult`, `crypto::stream`, `crypto::auth` and
`crypto::onetimeauth`.

## Thread Safety
All functions in this library are thread-safe provided that the `init()`
function has been called during program execution.

If `init()` hasn't been called then all functions except the random-number
generation functions and the key-generation functions are thread-safe.

# Public-key cryptography
 `crypto::asymmetricbox`

 `crypto::sign`

# Secret-key cryptography
 `crypto::secretbox`

 `crypto::stream`

 `crypto::auth`

 `crypto::onetimeauth`

# Low-level functions
 `crypto::hash`

 `crypto::verify`

 `crypto::shorthash`
 */
#![crate_id = "sodiumoxide#0.1"]
#![comment = "Fast cryptographic library"]
#![license = "MIT"]
#![crate_type = "lib"]
#![warn(missing_doc)]
#![warn(non_uppercase_statics)]
#![warn(non_camel_case_types)]
#![warn(managed_heap_memory)]
#![warn(unnecessary_qualification)]
#![feature(globs)]
#![feature(macro_rules)]
extern crate libc;
use libc::c_int;

#[link(name = "sodium")]
extern {
    fn sodium_init() -> c_int;
}

/**
 * `init()` initializes the sodium library and chooses faster versions of
 * the primitives if possible. `init()` also makes the random number generation
 * functions (`gen_key`, `gen_keypair`, `gen_nonce`, `randombytes`, `randombytes_into`)
 * thread-safe
 */
pub fn init() -> bool {
    unsafe {
        sodium_init() == 0
    }
}

/**
 * Cryptographic functions
 */
pub mod crypto {
    pub mod asymmetricbox;
    pub mod sign;
    pub mod scalarmult;
    pub mod auth;
    pub mod hash;
    pub mod secretbox;
    pub mod onetimeauth;
    pub mod stream;
    pub mod shorthash;

    pub mod verify;
}

pub mod randombytes;
mod utils;
<commit_msg>crate_id -> crate_name<commit_after>/*!
Rust bindings to the [sodium library](https://github.com/jedisct1/libsodium).

Sodium is a portable implementation of Dan Bernsteins [NaCl: Networking and
Cryptography library](http://nacl.cr.yp.to)

For most users, if you want public-key (asymmetric) cryptography you should use
the functions in `crypto::asymmetricbox` for encryption/decryption.

If you want secret-key (symmetric) cryptography you should be using the
functions in `crypto::secretbox` for encryption/decryption.

For public-key signatures you should use the functions in `crypto::sign` for
signature creation and verification.

Unless you know what you're doing you most certainly don't want to use the
functions in `crypto::scalarmult`, `crypto::stream`, `crypto::auth` and
`crypto::onetimeauth`.

## Thread Safety
All functions in this library are thread-safe provided that the `init()`
function has been called during program execution.

If `init()` hasn't been called then all functions except the random-number
generation functions and the key-generation functions are thread-safe.

# Public-key cryptography
 `crypto::asymmetricbox`

 `crypto::sign`

# Secret-key cryptography
 `crypto::secretbox`

 `crypto::stream`

 `crypto::auth`

 `crypto::onetimeauth`

# Low-level functions
 `crypto::hash`

 `crypto::verify`

 `crypto::shorthash`
 */
#![crate_name = "sodiumoxide"]
#![comment = "Fast cryptographic library"]
#![license = "MIT"]
#![crate_type = "lib"]
#![warn(missing_doc)]
#![warn(non_uppercase_statics)]
#![warn(non_camel_case_types)]
#![warn(managed_heap_memory)]
#![warn(unnecessary_qualification)]
#![feature(globs)]
#![feature(macro_rules)]
extern crate libc;
use libc::c_int;

#[link(name = "sodium")]
extern {
    fn sodium_init() -> c_int;
}

/**
 * `init()` initializes the sodium library and chooses faster versions of
 * the primitives if possible. `init()` also makes the random number generation
 * functions (`gen_key`, `gen_keypair`, `gen_nonce`, `randombytes`, `randombytes_into`)
 * thread-safe
 */
pub fn init() -> bool {
    unsafe {
        sodium_init() == 0
    }
}

/**
 * Cryptographic functions
 */
pub mod crypto {
    pub mod asymmetricbox;
    pub mod sign;
    pub mod scalarmult;
    pub mod auth;
    pub mod hash;
    pub mod secretbox;
    pub mod onetimeauth;
    pub mod stream;
    pub mod shorthash;

    pub mod verify;
}

pub mod randombytes;
mod utils;
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device> ops::Deref for Graphics<D> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device> ops::DerefMut for Graphics<D> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device> Graphics<D> {
    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ::ClearData, mask: ::Mask, frame: &::Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &::Frame<D::Resources>)
                -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
                     params: &'a T, frame: &::Frame<D::Resources>)
                     -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<R: device::Resources, C: device::draw::CommandBuffer<R>>:
    device::Device<Resources = R, CommandBuffer = C>
{
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<Self>;
}

impl<
    R: device::Resources,
    C: device::draw::CommandBuffer<R>,
    D: RenderFactory<R, C> + device::Device<Resources = R, CommandBuffer = C>,
> DeviceExt<R, C> for D {
    fn into_graphics(mut self) -> Graphics<D> {
        let rend = self.create_renderer();
        Graphics {
            device: self,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<commit_msg>Added factory to Graphics<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device, F> {
    /// Graphics device.
    pub device: D,
    /// Resource factory.
    pub factory: F,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device, F> ops::Deref for Graphics<D, F> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device, F> ops::DerefMut for Graphics<D, F> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device, F: device::Factory<D::Resources>> Graphics<D, F> {
    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ::ClearData, mask: ::Mask, frame: &::Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &::Frame<D::Resources>)
                -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
                     params: &'a T, frame: &::Frame<D::Resources>)
                     -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
        // self.factory.after_frame();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<D: device::Device, F> {
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<D, F>;
}

impl<
    D: device::Device,
    F: device::Factory<D::Resources>,
> DeviceExt<D, F> for (D, F) {
    fn into_graphics(mut self) -> Graphics<D, F> {
        let rend = self.1.create_renderer();
        Graphics {
            device: self.0,
            factory: self.1,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<|endoftext|>


<commit_before>use cairo;

use crate::reference_utils::{Compare, Evaluate, Reference};
use crate::utils::{load_svg, render_document, SurfaceSize};

#[test]
fn simple_opacity_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(150, 150),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 150, 150).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_transform");
}

#[test]
fn simple_opacity_with_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(150, 150),
        |_cr| (),
        cairo::Rectangle {
            x: 50.0,
            y: 50.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 150, 150).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_offset_viewport");
}

#[test]
// https://gitlab.gnome.org/GNOME/librsvg/issues/471
fn simple_opacity_with_scale() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(500, 500),
        |cr| {
            cr.translate(50.0, 50.0);
            cr.scale(8.0, 8.0);
        },
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 500).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.scale(8.0, 8.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_scale");
}

#[test]
// https://gitlab.gnome.org/GNOME/librsvg/issues/471
fn markers_with_scale() {
    let svg = load_svg(
        br#"<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <marker id="marker1" refX="10" refY="10" markerWidth="20" markerHeight="20" orient="auto">
        <path id="marker-path" d="M 20 10 L 0 16 V 4 Z" fill="blue" opacity="0.5"/>
    </marker>
    <path d="M 30 100 L 170 100"
          fill="none" stroke="green"
          marker-start="url(#marker1)" marker-end="url(#marker1)"/>
</svg>

"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(800, 800),
        |cr| {
            cr.scale(4.0, 4.0);
        },
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 200.0,
            height: 200.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 800, 800).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.scale(4.0, 4.0);

        cr.move_to(30.0, 100.0);
        cr.line_to(170.0, 100.0);
        cr.set_source_rgb(0.0, 0.5, 0.0);
        cr.set_line_width(1.0);
        cr.stroke().unwrap();

        for (x, y) in &[(30.0, 100.0), (170.0, 100.0)] {
            cr.move_to(x + 20.0 - 10.0, y + 10.0 - 10.0);
            cr.line_to(x + 0.0 - 10.0, y + 16.0 - 10.0);
            cr.line_to(x + 0.0 - 10.0, y + 4.0 - 10.0);
            cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
            cr.fill().unwrap();
        }
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "markers_with_scale");
}

#[test]
fn opacity_inside_transformed_group() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <g transform="translate(20, 20)">
    <rect x="0" y="0" width="60" height="60" style="fill:blue; opacity:0.5;"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(140, 140),
        |cr| cr.translate(20.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 140, 140).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(20.0, 20.0);
        cr.rectangle(20.0, 20.0, 60.0, 60.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "opacity_inside_transformed_group");
}

#[test]
fn compound_opacity() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" baseProfile="basic" id="svg-root"
  width="100%" height="100%" viewBox="0 0 480 360"
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g>
    <g opacity="0.5">
      <rect x="60" y="230" width="80" height="40" fill="#0000ff" opacity=".5"/>
      <rect x="70" y="240" width="80" height="40" fill="#00ff00" opacity=".5"/>
    </g>
  </g>
</svg>
"##,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(500, 380),
        |cr| cr.translate(10.0, 10.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 480.0,
            height: 360.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 380).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(10.0, 10.0);

        cr.push_group();

        cr.rectangle(60.0, 230.0, 80.0, 40.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();

        cr.rectangle(70.0, 240.0, 80.0, 40.0);
        cr.set_source_rgba(0.0, 1.0, 0.0, 0.5);
        cr.fill().unwrap();

        cr.pop_group_to_source().unwrap();
        cr.paint_with_alpha(0.5).unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "compound_opacity");
}

#[test]
fn nested_masks() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="321.00" height="27.00" viewBox="0 0 6420 540">
  <defs>
    <mask id="Mask_big_ex_small" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540">
      <g>
	<use xlink:href="#big" fill="white"/>
	<use xlink:href="#small" fill="black"/>
      </g>
    </mask>
    <g id="big_ex_small">
      <use xlink:href="#big" mask="url(#Mask_big_ex_small)"/>
    </g>
    <mask id="Region0" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
      <use xlink:href="#big_ex_small" fill="white"/>
    </mask>
    <rect id="big" x="0" y="0" width="6420" height="540"/>
    <rect id="small" x="2760" y="20" width="900" height="480"/>
  </defs>
  <g mask="url(#Region0)">
    <g transform="matrix(1.66667 0 0 1.66667 0 0)">
      <rect x="0" y="0" width="6420" height="540" fill="black"/>
    </g>
  </g>
</svg>

"##,
    ).unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(321 + 20, 27 + 20),
        |cr| cr.translate(10.0, 10.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 321.0,
            height: 27.0,
        },
    )
    .unwrap();

    let reference_surf =
        cairo::ImageSurface::create(cairo::Format::ARgb32, 321 + 20, 27 + 20).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(10.0, 10.0);
        cr.scale(321.0 / 6420.0, 27.0 / 540.0);

        cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
        cr.rectangle(0.0, 0.0, 6420.0, 540.0);
        cr.fill().unwrap();

        cr.set_operator(cairo::Operator::Clear);
        cr.rectangle(2760.0, 20.0, 900.0, 480.0);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "nested_masks");
}
<commit_msg>Test when an image element has no href attribute<commit_after>use cairo;

use crate::reference_utils::{Compare, Evaluate, Reference};
use crate::test_compare_render_output;
use crate::utils::{load_svg, render_document, SurfaceSize};

#[test]
fn simple_opacity_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(150, 150),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 150, 150).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_transform");
}

#[test]
fn simple_opacity_with_offset_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(150, 150),
        |_cr| (),
        cairo::Rectangle {
            x: 50.0,
            y: 50.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 150, 150).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_offset_viewport");
}

#[test]
// https://gitlab.gnome.org/GNOME/librsvg/issues/471
fn simple_opacity_with_scale() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
  <g opacity="0.5">
    <rect x="10" y="10" width="30" height="30" fill="blue"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(500, 500),
        |cr| {
            cr.translate(50.0, 50.0);
            cr.scale(8.0, 8.0);
        },
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 50.0,
            height: 50.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 500).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(50.0, 50.0);
        cr.scale(8.0, 8.0);
        cr.rectangle(10.0, 10.0, 30.0, 30.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "simple_opacity_with_scale");
}

#[test]
// https://gitlab.gnome.org/GNOME/librsvg/issues/471
fn markers_with_scale() {
    let svg = load_svg(
        br#"<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <marker id="marker1" refX="10" refY="10" markerWidth="20" markerHeight="20" orient="auto">
        <path id="marker-path" d="M 20 10 L 0 16 V 4 Z" fill="blue" opacity="0.5"/>
    </marker>
    <path d="M 30 100 L 170 100"
          fill="none" stroke="green"
          marker-start="url(#marker1)" marker-end="url(#marker1)"/>
</svg>

"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(800, 800),
        |cr| {
            cr.scale(4.0, 4.0);
        },
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 200.0,
            height: 200.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 800, 800).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.scale(4.0, 4.0);

        cr.move_to(30.0, 100.0);
        cr.line_to(170.0, 100.0);
        cr.set_source_rgb(0.0, 0.5, 0.0);
        cr.set_line_width(1.0);
        cr.stroke().unwrap();

        for (x, y) in &[(30.0, 100.0), (170.0, 100.0)] {
            cr.move_to(x + 20.0 - 10.0, y + 10.0 - 10.0);
            cr.line_to(x + 0.0 - 10.0, y + 16.0 - 10.0);
            cr.line_to(x + 0.0 - 10.0, y + 4.0 - 10.0);
            cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
            cr.fill().unwrap();
        }
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "markers_with_scale");
}

#[test]
fn opacity_inside_transformed_group() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <g transform="translate(20, 20)">
    <rect x="0" y="0" width="60" height="60" style="fill:blue; opacity:0.5;"/>
  </g>
</svg>
"#,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(140, 140),
        |cr| cr.translate(20.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 140, 140).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(20.0, 20.0);
        cr.rectangle(20.0, 20.0, 60.0, 60.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "opacity_inside_transformed_group");
}

#[test]
fn compound_opacity() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" baseProfile="basic" id="svg-root"
  width="100%" height="100%" viewBox="0 0 480 360"
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g>
    <g opacity="0.5">
      <rect x="60" y="230" width="80" height="40" fill="#0000ff" opacity=".5"/>
      <rect x="70" y="240" width="80" height="40" fill="#00ff00" opacity=".5"/>
    </g>
  </g>
</svg>
"##,
    )
    .unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(500, 380),
        |cr| cr.translate(10.0, 10.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 480.0,
            height: 360.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 380).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(10.0, 10.0);

        cr.push_group();

        cr.rectangle(60.0, 230.0, 80.0, 40.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 0.5);
        cr.fill().unwrap();

        cr.rectangle(70.0, 240.0, 80.0, 40.0);
        cr.set_source_rgba(0.0, 1.0, 0.0, 0.5);
        cr.fill().unwrap();

        cr.pop_group_to_source().unwrap();
        cr.paint_with_alpha(0.5).unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "compound_opacity");
}

#[test]
fn nested_masks() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="321.00" height="27.00" viewBox="0 0 6420 540">
  <defs>
    <mask id="Mask_big_ex_small" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540">
      <g>
	<use xlink:href="#big" fill="white"/>
	<use xlink:href="#small" fill="black"/>
      </g>
    </mask>
    <g id="big_ex_small">
      <use xlink:href="#big" mask="url(#Mask_big_ex_small)"/>
    </g>
    <mask id="Region0" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
      <use xlink:href="#big_ex_small" fill="white"/>
    </mask>
    <rect id="big" x="0" y="0" width="6420" height="540"/>
    <rect id="small" x="2760" y="20" width="900" height="480"/>
  </defs>
  <g mask="url(#Region0)">
    <g transform="matrix(1.66667 0 0 1.66667 0 0)">
      <rect x="0" y="0" width="6420" height="540" fill="black"/>
    </g>
  </g>
</svg>

"##,
    ).unwrap();

    let output_surf = render_document(
        &svg,
        SurfaceSize(321 + 20, 27 + 20),
        |cr| cr.translate(10.0, 10.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 321.0,
            height: 27.0,
        },
    )
    .unwrap();

    let reference_surf =
        cairo::ImageSurface::create(cairo::Format::ARgb32, 321 + 20, 27 + 20).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");

        cr.translate(10.0, 10.0);
        cr.scale(321.0 / 6420.0, 27.0 / 540.0);

        cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
        cr.rectangle(0.0, 0.0, 6420.0, 540.0);
        cr.fill().unwrap();

        cr.set_operator(cairo::Operator::Clear);
        cr.rectangle(2760.0, 20.0, 900.0, 480.0);
        cr.fill().unwrap();
    }

    Reference::from_surface(reference_surf)
        .compare(&output_surf)
        .evaluate(&output_surf, "nested_masks");
}

test_compare_render_output!(
    image_element_with_no_href,
    30,
    30,
    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
      <image x="10" y="10"/>
    </svg>"##,
    br##"<?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
    </svg>"##,
);
<|endoftext|>


<commit_before>use event::ChatEvent;

use std::collections::VecDeque;
use std::cell::{Cell, RefCell};

use termion::{self, cursor, clear};

pub struct DisplayArea {
    messages: Messages,
    to_be_displayed: Cell<usize>,
}

impl DisplayArea {
    pub fn new() -> DisplayArea {
        DisplayArea {
            messages: Messages::with_max(100),
            to_be_displayed: Cell::new(0),
        }
    }

    pub fn show_event(&self, event: &ChatEvent) {
        use irc_lib::client::data::Command::*;
        let from = event.source_nickname().unwrap_or("");
        let message = match event.message.command {
            PRIVMSG(ref target, ref msg) => format!("{} <{}> {}", target, from, msg),
            NOTICE(ref target, ref msg) => format!("!{} <{}> {}", target, from, msg),
            JOIN(ref channel, _, _) => format!("{} has joined {}", from, channel),
            NICK(ref new_nick) => format!("{} is now known as {}", from, new_nick),
            _ => format!("{}", event.message),
        };
        self.add_message(message);
    }

    pub fn add_message<S: Into<String>>(&self, message: S) {
        let message = message.into();
        self.messages.add_message(message.into());

        let to_be_displayed = self.to_be_displayed.get();
        self.to_be_displayed.set(to_be_displayed + 1);
    }

    pub fn self_message(&self, message: &str) {
        self.add_message(format!("<> {}", message));
    }

    pub fn update_display(&self) {
        let messages = self.messages.storage.borrow();
        let to_be_displayed = self.to_be_displayed.get();
        for i in messages.len().saturating_sub(to_be_displayed) .. messages.len() {
            let message = &messages[i];
            let (_, max_y) = termion::terminal_size().unwrap();
            print!("{}{}", cursor::Goto(1, max_y - 1), clear::AfterCursor);
            print!("{}\n\n", message);
        }
        self.to_be_displayed.set(0);
    }

    pub fn redraw(&self) {
        let (_, max_y) = termion::terminal_size().unwrap();
        print!("{}{}", clear::All, cursor::Goto(1, max_y));
        self.messages.for_all(|message| print!("{}\r\n", message));
        print!("\n");
        self.to_be_displayed.set(0);
    }
}

struct Messages {
    max_len: usize,
    storage: RefCell<VecDeque<String>>,
}

impl Messages {
    fn with_max(max_len: usize) -> Messages {
        Messages {
            max_len: max_len,
            storage: RefCell::new(VecDeque::with_capacity(100)),
        }
    }

    fn add_message(&self, message: String) {
        let mut storage = self.storage.borrow_mut();
        while storage.len() >= self.max_len {
            storage.pop_front();
        }
        storage.push_back(message);
    }

    fn for_all<F: FnMut(&str)>(&self, mut closure: F) {
        let storage = self.storage.borrow();
        for message in storage.iter() {
            closure(message);
        }
    }
}
<commit_msg>Trim excess `\r\n` from the ends of messages.<commit_after>use event::ChatEvent;

use std::collections::VecDeque;
use std::cell::{Cell, RefCell};

use termion::{self, cursor, clear};

pub struct DisplayArea {
    messages: Messages,
    to_be_displayed: Cell<usize>,
}

impl DisplayArea {
    pub fn new() -> DisplayArea {
        DisplayArea {
            messages: Messages::with_max(100),
            to_be_displayed: Cell::new(0),
        }
    }

    pub fn show_event(&self, event: &ChatEvent) {
        use irc_lib::client::data::Command::*;
        let from = event.source_nickname().unwrap_or("");
        let mut message = match event.message.command {
            PRIVMSG(ref target, ref msg) => format!("{} <{}> {}", target, from, msg),
            NOTICE(ref target, ref msg) => format!("!{} <{}> {}", target, from, msg),
            JOIN(ref channel, _, _) => format!("{} has joined {}", from, channel),
            NICK(ref new_nick) => format!("{} is now known as {}", from, new_nick),
            _ => format!("{}", event.message),
        };
        while message.ends_with(&['\r', '\n'][..]) {
            message.pop();
        }
        self.add_message(message);
    }

    pub fn add_message<S: Into<String>>(&self, message: S) {
        let message = message.into();
        self.messages.add_message(message.into());

        let to_be_displayed = self.to_be_displayed.get();
        self.to_be_displayed.set(to_be_displayed + 1);
    }

    pub fn self_message(&self, message: &str) {
        self.add_message(format!("<> {}", message));
    }

    pub fn update_display(&self) {
        let messages = self.messages.storage.borrow();
        let to_be_displayed = self.to_be_displayed.get();
        for i in messages.len().saturating_sub(to_be_displayed) .. messages.len() {
            let message = &messages[i];
            let (_, max_y) = termion::terminal_size().unwrap();
            print!("{}{}", cursor::Goto(1, max_y - 1), clear::AfterCursor);
            print!("{}\n\n", message);
        }
        self.to_be_displayed.set(0);
    }

    pub fn redraw(&self) {
        let (_, max_y) = termion::terminal_size().unwrap();
        print!("{}{}", clear::All, cursor::Goto(1, max_y));
        self.messages.for_all(|message| print!("{}\r\n", message));
        print!("\n");
        self.to_be_displayed.set(0);
    }
}

struct Messages {
    max_len: usize,
    storage: RefCell<VecDeque<String>>,
}

impl Messages {
    fn with_max(max_len: usize) -> Messages {
        Messages {
            max_len: max_len,
            storage: RefCell::new(VecDeque::with_capacity(100)),
        }
    }

    fn add_message(&self, message: String) {
        let mut storage = self.storage.borrow_mut();
        while storage.len() >= self.max_len {
            storage.pop_front();
        }
        storage.push_back(message);
    }

    fn for_all<F: FnMut(&str)>(&self, mut closure: F) {
        let storage = self.storage.borrow();
        for message in storage.iter() {
            closure(message);
        }
    }
}
<|endoftext|>