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

use fmt;
use sync::{Mutex, Condvar};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A result returned from wait.
///
/// Currently this opaque structure only has one method, [`.is_leader`]. Only
/// one thread will receive a result that will return `true` from this function.
///
/// [`.is_leader`]: #method.is_leader
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Barrier { .. }")
    }
}

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
    /// all threads at once when the `n`th thread calls [`wait`].
    ///
    /// [`wait`]: #method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(10);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`is_leader`] when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// [`is_leader`].
    ///
    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::{Arc, Barrier};
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = barrier.clone();
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // http://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id &&
                  lock.count < self.num_threads {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id += 1;
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BarrierWaitResult")
            .field("is_leader", &self.is_leader())
            .finish()
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from [`wait`] is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// [`wait`]: struct.Barrier.html#method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool { self.0 }
}

#[cfg(test)]
mod tests {
    use sync::{Arc, Barrier};
    use sync::mpsc::{channel, TryRecvError};
    use thread;

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));
        let (tx, rx) = channel();

        for _ in 0..N - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..N - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }
}
<commit_msg>Rollup merge of #40977 - projektir:BarrierWaitResult_doc, r=steveklabnik<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use fmt;
use sync::{Mutex, Condvar};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
/// have rendezvoused.
///
/// [`wait`]: struct.Barrier.html#method.wait
/// [`Barrier`]: struct.Barrier.html
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Barrier { .. }")
    }
}

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
    /// all threads at once when the `n`th thread calls [`wait`].
    ///
    /// [`wait`]: #method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(10);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`is_leader`] when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// [`is_leader`].
    ///
    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::{Arc, Barrier};
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = barrier.clone();
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // http://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id &&
                  lock.count < self.num_threads {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id += 1;
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BarrierWaitResult")
            .field("is_leader", &self.is_leader())
            .finish()
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from [`wait`] is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// [`wait`]: struct.Barrier.html#method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool { self.0 }
}

#[cfg(test)]
mod tests {
    use sync::{Arc, Barrier};
    use sync::mpsc::{channel, TryRecvError};
    use thread;

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));
        let (tx, rx) = channel();

        for _ in 0..N - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..N - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }
}
<|endoftext|>


<commit_before>#[derive(Clone)]
pub enum CellProperty {
    Floor,
    Wall,
    Entrance,
    Exit,
    Door
}

#[derive(Clone)]
pub enum CellOccupant
{
    Monster,
    Treasure,
    Trap,
    Teleporter
}

#[derive(Clone)]
pub struct Cell {
    x: u32,
    y: u32,
    property: Option<CellProperty>,
    occupants: Vec<CellOccupant>,
}

impl Cell {
    pub fn new(x: u32, y: u32, property: Option<CellProperty>) -> Cell {
        Cell {
            x: x,
            y: y,
            property: property,
            occupants: Vec::new()
        }
    }

    pub fn add(&mut self, occupant: CellOccupant) -> () {
        self.occupants.push(occupant)
    }
}

impl PartialEq for Cell {
    fn eq(&self, other: &Cell) -> bool {
        self.x == other.x && self.y == other.y
    }
}
<commit_msg>Implement Rand for Cell.<commit_after>use std::{rand};

#[derive(Clone, Rand, Debug)]
pub enum CellProperty {
    Floor,
    Wall,
    Entrance,
    Exit,
    Door
}

#[derive(Clone, Rand, Debug)]
pub enum CellOccupant
{
    Monster,
    Treasure,
    Trap,
    Teleporter
}

#[derive(Clone)]
pub struct Cell {
    x: u32,
    y: u32,
    property: Option<CellProperty>,
    occupants: Vec<CellOccupant>,
}

impl Cell {
    pub fn new(x: u32, y: u32, property: Option<CellProperty>) -> Cell {
        Cell {
            x: x,
            y: y,
            property: property,
            occupants: vec![]
        }
    }

    pub fn add(&mut self, occupant: CellOccupant) -> () {
        self.occupants.push(occupant)
    }
}

impl PartialEq for Cell {
    fn eq(&self, other: &Cell) -> bool {
        self.x == other.x && self.y == other.y
    }
}

impl rand::Rand for Cell {
    fn rand<R>(rng: &mut R) -> Cell {
        Cell {
            x: 0,
            y: 0,
            property: Some(rand::random::<CellProperty>()),
            occupants: vec![]
        }
    }
}
<|endoftext|>


<commit_before>use std::net;
use std::str::FromStr;
use std::num;

#[derive(Debug, PartialEq)]
pub struct Cidr {
    pub prefix: net::Ipv4Addr,
    pub length: u8,
}

#[derive(Debug)]
pub enum CidrParseError {
    Prefix(net::AddrParseError),
    Length(num::ParseIntError),
}

impl From<net::AddrParseError> for CidrParseError {
    fn from(err: net::AddrParseError) -> CidrParseError {
        CidrParseError::Prefix(err)
    }
}

impl From<num::ParseIntError> for CidrParseError {
    fn from(err: num::ParseIntError) -> CidrParseError {
        CidrParseError::Length(err)
    }
}

impl FromStr for Cidr {
    type Err = CidrParseError;

    fn from_str(s: &str) -> Result<Cidr, CidrParseError> {
        let parts = s.split("/").collect::<Vec<&str>>();
        let mut length = 32;
        if parts.len() > 1 {
            length = try!(parts[1].parse::<u8>());
        }
        return Ok(Cidr {
            prefix: try!(net::Ipv4Addr::from_str(parts[0])),
            length: length,
        })
    }
}

impl Cidr {
    pub fn from_bits(bits: u32, length: u8) -> Option<Cidr> {
        Some(Cidr {
            prefix: net::Ipv4Addr::new(
                        (bits >> 24) as u8,
                        (bits >> 16) as u8,
                        (bits >>  8) as u8,
                        (bits)       as u8),
            length: length,
        })
    }

    pub fn prefix_bits(&self) -> u32 {
        let octets = self.prefix.octets();
        ((octets[0] as u32) << 24) |
        ((octets[1] as u32) << 16) |
        ((octets[2] as u32) << 8) |
        ((octets[3] as u32))
    }
}

#[test]
fn test_from_str() {
    assert!(Cidr::from_str("1.2.3.4/32").unwrap().prefix ==
            Cidr::from_str("1.2.3.4").unwrap().prefix);

    assert!(Cidr::from_str("1.2.3.4/32").unwrap().length == 32);
    assert!(Cidr::from_str("1.2.3.4/0").unwrap().length == 0);

    let from_bits = Cidr::from_bits(0x80000000, 1).unwrap();
    let from_str = Cidr::from_str("128.0.0.0/1").unwrap();
    assert!(from_bits == from_str);
}
<commit_msg>Created a Prefix abstraction<commit_after>use std::net;
use std::str::FromStr;
use std::num;

#[derive(Debug, PartialEq)]
pub struct Prefix {
    pub bits: net::Ipv4Addr,
}

impl Prefix {
    pub fn octets(&self) -> [u8; 4] {
        self.bits.octets()
    }
}

#[derive(Debug, PartialEq)]
pub struct Cidr {
    pub prefix: Prefix,
    pub length: u8,
}

#[derive(Debug)]
pub enum CidrParseError {
    Prefix(net::AddrParseError),
    Length(num::ParseIntError),
}

impl From<net::AddrParseError> for CidrParseError {
    fn from(err: net::AddrParseError) -> CidrParseError {
        CidrParseError::Prefix(err)
    }
}

impl From<num::ParseIntError> for CidrParseError {
    fn from(err: num::ParseIntError) -> CidrParseError {
        CidrParseError::Length(err)
    }
}

impl FromStr for Cidr {
    type Err = CidrParseError;

    fn from_str(s: &str) -> Result<Cidr, CidrParseError> {
        let parts = s.split("/").collect::<Vec<&str>>();
        let mut length = 32;
        if parts.len() > 1 {
            length = try!(parts[1].parse::<u8>());
        }
        return Ok(Cidr {
            prefix: Prefix { bits: try!(net::Ipv4Addr::from_str(parts[0])) },
            length: length,
        })
    }
}

impl Cidr {
    pub fn from_bits(bits: u32, length: u8) -> Option<Cidr> {
        Some(Cidr {
            prefix: Prefix {
                bits: net::Ipv4Addr::new((bits >> 24) as u8,
                                         (bits >> 16) as u8,
                                         (bits >>  8) as u8,
                                         (bits)       as u8)
            },
            length: length,
        })
    }

    pub fn prefix_bits(&self) -> u32 {
        let octets = self.prefix.octets();
        ((octets[0] as u32) << 24) |
        ((octets[1] as u32) << 16) |
        ((octets[2] as u32) << 8) |
        ((octets[3] as u32))
    }
}

#[test]
fn test_from_str() {
    assert!(Cidr::from_str("1.2.3.4/32").unwrap().prefix ==
            Cidr::from_str("1.2.3.4").unwrap().prefix);

    assert!(Cidr::from_str("1.2.3.4/32").unwrap().length == 32);
    assert!(Cidr::from_str("1.2.3.4/0").unwrap().length == 0);

    let from_bits = Cidr::from_bits(0x80000000, 1).unwrap();
    let from_str = Cidr::from_str("128.0.0.0/1").unwrap();
    assert!(from_bits == from_str);
}
<|endoftext|>


<commit_before>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A [`Conf`](struct.Conf.html) struct is used to create a config file
//! which specifies hardware setup stuff, mostly video display settings.
//!
//! By default a ggez game will search its resource paths for a `/conf.toml`
//! file and load values from it when the [`Context`](../struct.Context.html) is created.  This file
//! must be complete (ie you cannot just fill in some fields and have the
//! rest be default) and provides a nice way to specify settings that
//! can be tweaked such as window resolution, multisampling options, etc.
//! If no file is found, it will create a `Conf` object from the settings
//! passed to the [`ContextBuilder`](../struct.ContextBuilder.html).

use std::convert::TryFrom;
use std::io;

use crate::error::{GameError, GameResult};

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode.
    Windowed,
    /// True fullscreen, which used to be preferred 'cause it can have
    /// small performance benefits over windowed fullscreen.
    ///
    /// Also it allows us to set different resolutions.
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop,
}

/// A builder structure containing window settings
/// that can be set at runtime and changed with [`graphics::set_mode()`](../graphics/fn.set_mode.html).
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowMode {
///     width: 800.0,
///     height: 600.0,
///     maximized: false,
///     fullscreen_type: FullscreenType::Windowed,
///     borderless: false,
///     min_width: 1.0,
///     max_width: 0.0,
///     min_height: 1.0,
///     max_height: 0.0,
///     resizable: false,
///     visible: true,
///     transparent: false,
///     resize_on_scale_factor_change: false,
/// }
/// # , WindowMode::default());}
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowMode {
    /// Window width in physical pixels
    #[default = 800.0]
    pub width: f32,
    /// Window height in physical pixels
    #[default = 600.0]
    pub height: f32,
    /// Window height/width but allows LogicalSize for high DPI systems. If Some will be used instead of width/height.
    pub logical_size: Option<winit::dpi::LogicalSize<f32>>,
    /// Whether or not to maximize the window
    #[default = false]
    pub maximized: bool,
    /// Fullscreen type
    #[default(FullscreenType::Windowed)]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to show window decorations
    #[default = false]
    pub borderless: bool,
    /// Whether or not the window should be transparent
    #[default = false]
    pub transparent: bool,
    /// Minimum width for resizable windows; 1 is the technical minimum,
    /// as wgpu will panic on a width of 0.
    #[default = 1.0]
    pub min_width: f32,
    /// Minimum height for resizable windows; 1 is the technical minimum,
    /// as wgpu will panic on a height of 0.
    #[default = 1.0]
    pub min_height: f32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_width: f32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_height: f32,
    /// Whether or not the window is resizable
    #[default = false]
    pub resizable: bool,
    /// Whether this window should displayed (true) or hidden (false)
    #[default = true]
    pub visible: bool,
    /// Whether this window should change its size in physical pixels
    /// when its hidpi factor changes, i.e. when [`WindowEvent::ScaleFactorChanged`](https://docs.rs/winit/0.25.0/winit/event/enum.WindowEvent.html#variant.ScaleFactorChanged)
    /// is fired.
    ///
    /// You usually want this to be false, since the window suddenly changing size may break your game.
    /// Setting this to true may be desirable if you plan for it and want your window to behave like
    /// windows of other programs when being dragged from one screen to another, for example.
    ///
    /// For more context on this take a look at [this conversation](https://github.com/ggez/ggez/pull/949#issuecomment-854731226).
    #[default = false]
    pub resize_on_scale_factor_change: bool,
}

impl WindowMode {
    /// Set default window size, or screen resolution in true fullscreen mode.
    #[must_use]
    pub fn dimensions(mut self, width: f32, height: f32) -> Self {
        if width >= 1.0 {
            self.width = width;
        }
        if height >= 1.0 {
            self.height = height;
        }
        self
    }

    /// Set whether the window should be maximized.
    #[must_use]
    pub fn maximized(mut self, maximized: bool) -> Self {
        self.maximized = maximized;
        self
    }

    /// Set the fullscreen type.
    #[must_use]
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set whether a window should be borderless in windowed mode.
    #[must_use]
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set whether a window should be transparent.
    pub fn transparent(mut self, transparent: bool) -> Self {
        self.transparent = transparent;
        self
    }

    /// Set minimum window dimensions for windowed mode.
    /// Minimum dimensions will always be >= 1.
    #[must_use]
    pub fn min_dimensions(mut self, width: f32, height: f32) -> Self {
        if width >= 1.0 {
            self.min_width = width;
        }
        if height >= 1.0 {
            self.min_height = height;
        }
        self
    }

    /// Set maximum window dimensions for windowed mode.
    #[must_use]
    pub fn max_dimensions(mut self, width: f32, height: f32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }

    /// Set resizable.
    #[must_use]
    pub fn resizable(mut self, resizable: bool) -> Self {
        self.resizable = resizable;
        self
    }

    /// Set visibility
    #[must_use]
    pub fn visible(mut self, visible: bool) -> Self {
        self.visible = visible;
        self
    }

    /// Set whether to resize when the hidpi factor changes
    #[must_use]
    pub fn resize_on_scale_factor_change(mut self, resize_on_scale_factor_change: bool) -> Self {
        self.resize_on_scale_factor_change = resize_on_scale_factor_change;
        self
    }

    // Use logical_size if set, else convert width/height to PhysicalSize
    pub(crate) fn actual_size(&self) -> GameResult<winit::dpi::Size> {
        if let Some(logical_size) = self.logical_size {
            if logical_size.width >= 1.0 && logical_size.height >= 1.0 {
                Ok(logical_size.into())
            } else {
                Err(GameError::WindowError(format!(
                    "window width and height need to be at least 1; actual values: {}, {}",
                    logical_size.width, logical_size.height
                )))
            }
        } else {
            let physical_size = winit::dpi::PhysicalSize::<f64>::from((self.width, self.height));
            if physical_size.width >= 1.0 && physical_size.height >= 1.0 {
                Ok(physical_size.into())
            } else {
                Err(GameError::WindowError(format!(
                    "window width and height need to be at least 1; actual values: {}, {}",
                    physical_size.width, physical_size.height
                )))
            }
        }
    }
}

/// A builder structure containing window settings
/// that must be set at init time and cannot be changed afterwards.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowSetup {
///     title: "An easy, good game".to_owned(),
///     samples: NumSamples::One,
///     vsync: true,
///     icon: "".to_owned(),
///     srgb: true,
/// }
/// # , WindowSetup::default()); }
/// ```
#[derive(Debug, Clone, SmartDefault, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowSetup {
    /// The window title.
    #[default(String::from("An easy, good game"))]
    pub title: String,
    /// Number of samples to use for multisample anti-aliasing.
    #[default(NumSamples::One)]
    pub samples: NumSamples,
    /// Whether or not to enable vsync.
    #[default = true]
    pub vsync: bool,
    /// A file path to the window's icon.
    /// It takes a path rooted in the `resources` directory (see the [`filesystem`](../filesystem/index.html)
    /// module for details), and an empty string results in a blank/default icon.
    #[default(String::new())]
    pub icon: String,
    /// Whether or not to enable sRGB (gamma corrected color)
    /// handling on the display.
    #[default = true]
    pub srgb: bool,
}

impl WindowSetup {
    /// Set window title.
    #[must_use]
    pub fn title(mut self, title: &str) -> Self {
        self.title = title.to_owned();
        self
    }

    /// Set number of samples to use for multisample anti-aliasing.
    #[must_use]
    pub fn samples(mut self, samples: NumSamples) -> Self {
        self.samples = samples;
        self
    }

    /// Set whether vsync is enabled.
    #[must_use]
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set the window's icon.
    #[must_use]
    pub fn icon(mut self, icon: &str) -> Self {
        self.icon = icon.to_owned();
        self
    }

    /// Set sRGB color mode.
    #[must_use]
    pub fn srgb(mut self, active: bool) -> Self {
        self.srgb = active;
        self
    }
}

/// Possible graphics backends.
/// The default is `Primary`.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, SmartDefault)]
#[serde(tag = "type")]
pub enum Backend {
    /// Includes [`Backend::OnlyPrimary`] and also secondary APIs consisting of OpenGL and DX11.
    ///
    /// These APIs may have issues and may be deprecated by some platforms.
    #[default]
    All,
    /// Primary APIs consisting of Vulkan, Metal and DX12.
    ///
    /// These APIs have first-class support from WGPU and from the platforms that support them.
    OnlyPrimary,
    /// Use the Khronos Vulkan API.
    Vulkan,
    /// Use the Apple Metal API.
    Metal,
    /// Use the Microsoft DirectX 12 API.
    Dx12,
    /// Use the Microsoft DirectX 11 API. This is not a recommended backend.
    Dx11,
    /// Use the Khronos OpenGL API. This is not a recommended backend.
    Gl,
    /// Use the WebGPU API. Targets the web.
    BrowserWebGpu,
}

/// The possible number of samples for multisample anti-aliasing.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NumSamples {
    /// One sample
    One = 1,
    /* uncomment when WGPU supports more sample counts
    /// Two samples
    Two = 2,
    */
    /// Four samples
    Four = 4,
    /* uncomment when WGPU supports more sample counts
    /// Eight samples
    Eight = 8,
    /// Sixteen samples
    Sixteen = 16,
    */
}

impl TryFrom<u8> for NumSamples {
    type Error = GameError;
    fn try_from(i: u8) -> Result<Self, Self::Error> {
        match i {
            1 => Ok(NumSamples::One),
            //2 => Ok(NumSamples::Two),
            4 => Ok(NumSamples::Four),
            //8 => Ok(NumSamples::Eight),
            //16 => Ok(NumSamples::Sixteen),
            _ => Err(GameError::ConfigError(String::from(
                "Invalid number of samples",
            ))),
        }
    }
}

impl From<NumSamples> for u8 {
    fn from(ns: NumSamples) -> u8 {
        ns as u8
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Conf {
///     window_mode: WindowMode::default(),
///     window_setup: WindowSetup::default(),
///     backend: Backend::default(),
/// }
/// # , Conf::default()); }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault, Clone)]
pub struct Conf {
    /// Window setting information that can be set at runtime
    pub window_mode: WindowMode,
    /// Window setting information that must be set at init-time
    pub window_setup: WindowSetup,
    /// Graphics backend configuration
    pub backend: Backend,
}

impl Conf {
    /// Same as `Conf::default()`
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        let _ = file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }

    /// Sets the window mode
    #[must_use]
    pub fn window_mode(mut self, window_mode: WindowMode) -> Self {
        self.window_mode = window_mode;
        self
    }

    /// Sets the backend
    #[must_use]
    pub fn backend(mut self, backend: Backend) -> Self {
        self.backend = backend;
        self
    }
}

#[cfg(test)]
mod tests {
    use crate::conf;

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn headless_encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        c1.to_toml_file(&mut writer).unwrap();
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<commit_msg>Try another way to reduce duplication<commit_after>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A [`Conf`](struct.Conf.html) struct is used to create a config file
//! which specifies hardware setup stuff, mostly video display settings.
//!
//! By default a ggez game will search its resource paths for a `/conf.toml`
//! file and load values from it when the [`Context`](../struct.Context.html) is created.  This file
//! must be complete (ie you cannot just fill in some fields and have the
//! rest be default) and provides a nice way to specify settings that
//! can be tweaked such as window resolution, multisampling options, etc.
//! If no file is found, it will create a `Conf` object from the settings
//! passed to the [`ContextBuilder`](../struct.ContextBuilder.html).

use std::convert::TryFrom;
use std::io;

use winit::dpi::PhysicalSize;

use crate::error::{GameError, GameResult};

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode.
    Windowed,
    /// True fullscreen, which used to be preferred 'cause it can have
    /// small performance benefits over windowed fullscreen.
    ///
    /// Also it allows us to set different resolutions.
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop,
}

/// A builder structure containing window settings
/// that can be set at runtime and changed with [`graphics::set_mode()`](../graphics/fn.set_mode.html).
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowMode {
///     width: 800.0,
///     height: 600.0,
///     maximized: false,
///     fullscreen_type: FullscreenType::Windowed,
///     borderless: false,
///     min_width: 1.0,
///     max_width: 0.0,
///     min_height: 1.0,
///     max_height: 0.0,
///     resizable: false,
///     visible: true,
///     transparent: false,
///     resize_on_scale_factor_change: false,
/// }
/// # , WindowMode::default());}
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq)]
pub struct WindowMode {
    /// Window width in physical pixels
    #[default = 800.0]
    pub width: f32,
    /// Window height in physical pixels
    #[default = 600.0]
    pub height: f32,
    /// Window height/width but allows LogicalSize for high DPI systems. If Some will be used instead of width/height.
    pub logical_size: Option<winit::dpi::LogicalSize<f32>>,
    /// Whether or not to maximize the window
    #[default = false]
    pub maximized: bool,
    /// Fullscreen type
    #[default(FullscreenType::Windowed)]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to show window decorations
    #[default = false]
    pub borderless: bool,
    /// Whether or not the window should be transparent
    #[default = false]
    pub transparent: bool,
    /// Minimum width for resizable windows; 1 is the technical minimum,
    /// as wgpu will panic on a width of 0.
    #[default = 1.0]
    pub min_width: f32,
    /// Minimum height for resizable windows; 1 is the technical minimum,
    /// as wgpu will panic on a height of 0.
    #[default = 1.0]
    pub min_height: f32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_width: f32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = 0.0]
    pub max_height: f32,
    /// Whether or not the window is resizable
    #[default = false]
    pub resizable: bool,
    /// Whether this window should displayed (true) or hidden (false)
    #[default = true]
    pub visible: bool,
    /// Whether this window should change its size in physical pixels
    /// when its hidpi factor changes, i.e. when [`WindowEvent::ScaleFactorChanged`](https://docs.rs/winit/0.25.0/winit/event/enum.WindowEvent.html#variant.ScaleFactorChanged)
    /// is fired.
    ///
    /// You usually want this to be false, since the window suddenly changing size may break your game.
    /// Setting this to true may be desirable if you plan for it and want your window to behave like
    /// windows of other programs when being dragged from one screen to another, for example.
    ///
    /// For more context on this take a look at [this conversation](https://github.com/ggez/ggez/pull/949#issuecomment-854731226).
    #[default = false]
    pub resize_on_scale_factor_change: bool,
}

impl WindowMode {
    /// Set default window size, or screen resolution in true fullscreen mode.
    #[must_use]
    pub fn dimensions(mut self, width: f32, height: f32) -> Self {
        if width >= 1.0 {
            self.width = width;
        }
        if height >= 1.0 {
            self.height = height;
        }
        self
    }

    /// Set whether the window should be maximized.
    #[must_use]
    pub fn maximized(mut self, maximized: bool) -> Self {
        self.maximized = maximized;
        self
    }

    /// Set the fullscreen type.
    #[must_use]
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set whether a window should be borderless in windowed mode.
    #[must_use]
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set whether a window should be transparent.
    pub fn transparent(mut self, transparent: bool) -> Self {
        self.transparent = transparent;
        self
    }

    /// Set minimum window dimensions for windowed mode.
    /// Minimum dimensions will always be >= 1.
    #[must_use]
    pub fn min_dimensions(mut self, width: f32, height: f32) -> Self {
        if width >= 1.0 {
            self.min_width = width;
        }
        if height >= 1.0 {
            self.min_height = height;
        }
        self
    }

    /// Set maximum window dimensions for windowed mode.
    #[must_use]
    pub fn max_dimensions(mut self, width: f32, height: f32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }

    /// Set resizable.
    #[must_use]
    pub fn resizable(mut self, resizable: bool) -> Self {
        self.resizable = resizable;
        self
    }

    /// Set visibility
    #[must_use]
    pub fn visible(mut self, visible: bool) -> Self {
        self.visible = visible;
        self
    }

    /// Set whether to resize when the hidpi factor changes
    #[must_use]
    pub fn resize_on_scale_factor_change(mut self, resize_on_scale_factor_change: bool) -> Self {
        self.resize_on_scale_factor_change = resize_on_scale_factor_change;
        self
    }

    // Use logical_size if set, else convert width/height to PhysicalSize
    pub(crate) fn actual_size(&self) -> GameResult<winit::dpi::Size> {
        let actual_size: winit::dpi::Size = if let Some(logical_size) = self.logical_size {
            logical_size.into()
        } else {
            winit::dpi::PhysicalSize::<f64>::from((self.width, self.height)).into()
        };
        let physical_size: PhysicalSize<f64> = actual_size.to_physical(1.0);
        if physical_size.width >= 1.0 && physical_size.height >= 1.0 {
            Ok(actual_size)
        } else {
            Err(GameError::WindowError(format!(
                "window width and height need to be at least 1; actual values: {}, {}",
                physical_size.width, physical_size.height
            )))
        }
    }
}

/// A builder structure containing window settings
/// that must be set at init time and cannot be changed afterwards.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// WindowSetup {
///     title: "An easy, good game".to_owned(),
///     samples: NumSamples::One,
///     vsync: true,
///     icon: "".to_owned(),
///     srgb: true,
/// }
/// # , WindowSetup::default()); }
/// ```
#[derive(Debug, Clone, SmartDefault, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowSetup {
    /// The window title.
    #[default(String::from("An easy, good game"))]
    pub title: String,
    /// Number of samples to use for multisample anti-aliasing.
    #[default(NumSamples::One)]
    pub samples: NumSamples,
    /// Whether or not to enable vsync.
    #[default = true]
    pub vsync: bool,
    /// A file path to the window's icon.
    /// It takes a path rooted in the `resources` directory (see the [`filesystem`](../filesystem/index.html)
    /// module for details), and an empty string results in a blank/default icon.
    #[default(String::new())]
    pub icon: String,
    /// Whether or not to enable sRGB (gamma corrected color)
    /// handling on the display.
    #[default = true]
    pub srgb: bool,
}

impl WindowSetup {
    /// Set window title.
    #[must_use]
    pub fn title(mut self, title: &str) -> Self {
        self.title = title.to_owned();
        self
    }

    /// Set number of samples to use for multisample anti-aliasing.
    #[must_use]
    pub fn samples(mut self, samples: NumSamples) -> Self {
        self.samples = samples;
        self
    }

    /// Set whether vsync is enabled.
    #[must_use]
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set the window's icon.
    #[must_use]
    pub fn icon(mut self, icon: &str) -> Self {
        self.icon = icon.to_owned();
        self
    }

    /// Set sRGB color mode.
    #[must_use]
    pub fn srgb(mut self, active: bool) -> Self {
        self.srgb = active;
        self
    }
}

/// Possible graphics backends.
/// The default is `Primary`.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, SmartDefault)]
#[serde(tag = "type")]
pub enum Backend {
    /// Includes [`Backend::OnlyPrimary`] and also secondary APIs consisting of OpenGL and DX11.
    ///
    /// These APIs may have issues and may be deprecated by some platforms.
    #[default]
    All,
    /// Primary APIs consisting of Vulkan, Metal and DX12.
    ///
    /// These APIs have first-class support from WGPU and from the platforms that support them.
    OnlyPrimary,
    /// Use the Khronos Vulkan API.
    Vulkan,
    /// Use the Apple Metal API.
    Metal,
    /// Use the Microsoft DirectX 12 API.
    Dx12,
    /// Use the Microsoft DirectX 11 API. This is not a recommended backend.
    Dx11,
    /// Use the Khronos OpenGL API. This is not a recommended backend.
    Gl,
    /// Use the WebGPU API. Targets the web.
    BrowserWebGpu,
}

/// The possible number of samples for multisample anti-aliasing.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NumSamples {
    /// One sample
    One = 1,
    /* uncomment when WGPU supports more sample counts
    /// Two samples
    Two = 2,
    */
    /// Four samples
    Four = 4,
    /* uncomment when WGPU supports more sample counts
    /// Eight samples
    Eight = 8,
    /// Sixteen samples
    Sixteen = 16,
    */
}

impl TryFrom<u8> for NumSamples {
    type Error = GameError;
    fn try_from(i: u8) -> Result<Self, Self::Error> {
        match i {
            1 => Ok(NumSamples::One),
            //2 => Ok(NumSamples::Two),
            4 => Ok(NumSamples::Four),
            //8 => Ok(NumSamples::Eight),
            //16 => Ok(NumSamples::Sixteen),
            _ => Err(GameError::ConfigError(String::from(
                "Invalid number of samples",
            ))),
        }
    }
}

impl From<NumSamples> for u8 {
    fn from(ns: NumSamples) -> u8 {
        ns as u8
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust
/// # use ggez::conf::*;
/// # fn main() { assert_eq!(
/// Conf {
///     window_mode: WindowMode::default(),
///     window_setup: WindowSetup::default(),
///     backend: Backend::default(),
/// }
/// # , Conf::default()); }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault, Clone)]
pub struct Conf {
    /// Window setting information that can be set at runtime
    pub window_mode: WindowMode,
    /// Window setting information that must be set at init-time
    pub window_setup: WindowSetup,
    /// Graphics backend configuration
    pub backend: Backend,
}

impl Conf {
    /// Same as `Conf::default()`
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        let _ = file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }

    /// Sets the window mode
    #[must_use]
    pub fn window_mode(mut self, window_mode: WindowMode) -> Self {
        self.window_mode = window_mode;
        self
    }

    /// Sets the backend
    #[must_use]
    pub fn backend(mut self, backend: Backend) -> Self {
        self.backend = backend;
        self
    }
}

#[cfg(test)]
mod tests {
    use crate::conf;

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn headless_encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        c1.to_toml_file(&mut writer).unwrap();
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<|endoftext|>


<commit_before>//! Thread-safe connections on any IrcWriters and IrcReaders
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use data::kinds::{IrcWriter, IrcReader};
use data::message::Message;

/// A thread-safe connection
#[experimental]
pub struct Connection<T, U> where T: IrcWriter, U: IrcReader {
    writer: Mutex<T>,
    reader: Mutex<U>,
}

impl Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let socket = try!(TcpStream::connect(host, port));
        Ok(Connection::new(BufferedWriter::new(socket.clone()), BufferedReader::new(socket)))
    }
}

impl<T, U> Connection<T, U> where T: IrcWriter, U: IrcReader {
    /// Creates a new connection from any arbitrary IrcWriter and IrcReader
    #[experimental]
    pub fn new(writer: T, reader: U) -> Connection<T, U> {
        Connection {
            writer: Mutex::new(writer),
            reader: Mutex::new(reader),
        }
    }

    /// Sends a Message over this connection
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut send = self.writer.lock();
        try!(send.write_str(message.into_string()[]));
        send.flush()
    }

    /// Receives a single line from this connection
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.reader.lock().read_line()
    }

    /// Acquires the Writer lock
    #[experimental]
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, T> {
        self.writer.lock()
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(MemWriter::new(), NullReader);
        assert!(conn.send(Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))).is_ok());
        let data = String::from_utf8(conn.writer().get_ref().to_vec()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<commit_msg>Updated connect(...) with API changes for TcpStream.<commit_after>//! Thread-safe connections on any IrcWriters and IrcReaders
#![experimental]
use std::sync::{Mutex, MutexGuard};
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use data::kinds::{IrcWriter, IrcReader};
use data::message::Message;

/// A thread-safe connection
#[experimental]
pub struct Connection<T, U> where T: IrcWriter, U: IrcReader {
    writer: Mutex<T>,
    reader: Mutex<U>,
}

impl Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    /// Creates a thread-safe TCP connection to the specified server
    #[experimental]
    pub fn connect(host: &str, port: u16) -> IoResult<Connection<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let socket = try!(TcpStream::connect(format!("{}:{}", host, port)[]));
        Ok(Connection::new(BufferedWriter::new(socket.clone()), BufferedReader::new(socket)))
    }
}

impl<T, U> Connection<T, U> where T: IrcWriter, U: IrcReader {
    /// Creates a new connection from any arbitrary IrcWriter and IrcReader
    #[experimental]
    pub fn new(writer: T, reader: U) -> Connection<T, U> {
        Connection {
            writer: Mutex::new(writer),
            reader: Mutex::new(reader),
        }
    }

    /// Sends a Message over this connection
    #[experimental]
    pub fn send(&self, message: Message) -> IoResult<()> {
        let mut send = self.writer.lock();
        try!(send.write_str(message.into_string()[]));
        send.flush()
    }

    /// Receives a single line from this connection
    #[experimental]
    pub fn recv(&self) -> IoResult<String> {
        self.reader.lock().read_line()
    }

    /// Acquires the Writer lock
    #[experimental]
    pub fn writer<'a>(&'a self) -> MutexGuard<'a, T> {
        self.writer.lock()
    }
}

#[cfg(test)]
mod test {
    use super::Connection;
    use std::io::{MemReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use data::message::Message;

    #[test]
    fn send() {
        let conn = Connection::new(MemWriter::new(), NullReader);
        assert!(conn.send(Message::new(None, "PRIVMSG", Some(vec!["test"]), Some("Testing!"))).is_ok());
        let data = String::from_utf8(conn.writer().get_ref().to_vec()).unwrap();
        assert_eq!(data[], "PRIVMSG test :Testing!\r\n");
    }

    #[test]
    fn recv() {
        let conn = Connection::new(NullWriter, MemReader::new("PRIVMSG test :Testing!\r\n".as_bytes().to_vec()));
        assert_eq!(conn.recv().unwrap()[], "PRIVMSG test :Testing!\r\n");
    }
}
<|endoftext|>


<commit_before>use cppn_ext::cppn::{Cppn, CppnNode};
use cppn_ext::position::Position;
use cppn_ext::activation_function::{GeometricActivationFunction, ActivationFunction};
use weight::Weight;
use substrate::{Substrate, Node};
use behavioral_bitvec::BehavioralBitvec;
use genome::Genome;
use nsga2::driver::Driver;
use nsga2::population::{UnratedPopulation, RatedPopulation};
use fitness::Fitness;
use rand::Rng;

pub type CppnGenome<AF> where AF: ActivationFunction = Genome<CppnNode<AF>>;

pub trait NetworkBuilderVisitor<P, T> where P: Position {
    fn add_node(&mut self, node: &Node<P, T>, param: f64);
    fn add_link(&mut self,
                source_node: &Node<P, T>,
                target_node: &Node<P, T>,
                weight1: f64,
                weight2: f64);
}

const CPPN_OUTPUT_LINK_WEIGHT1: usize = 0;
const CPPN_OUTPUT_LINK_WEIGHT2: usize = 1;
const CPPN_OUTPUT_LINK_EXPRESSION: usize = 2;
const CPPN_OUTPUT_NODE_WEIGHT: usize = 3;

/// Develops a network out of the CPPN
///
/// Returns the BehavioralBitvec and Connection Cost of the developed network

fn develop_cppn<P, AF, T, V>(cppn: &mut Cppn<CppnNode<AF>, Weight, ()>,
                             null_position: &P,
                             nodes: &[Node<P, T>],
                             links: &[(&Node<P, T>, &Node<P, T>)],
                             visitor: &mut V,
                             leo_threshold: f64)
                             -> (BehavioralBitvec, f64)
    where P: Position,
          AF: ActivationFunction,
          V: NetworkBuilderVisitor<P, T>
{

    // our CPPN has four outputs: link weight 1, link weight 2, link expression output, node weight
    assert!(cppn.output_count() == 4);
    assert!(cppn.input_count() == 6);

    let mut bitvec = BehavioralBitvec::new(4 * (nodes.len() + links.len()));
    let mut connection_cost = 0.0;

    // First visit all nodes

    for node in nodes.iter() {
        let inputs = [node.position.coords(), null_position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        visitor.add_node(node, node_weight)
    }

    for &(source_node, target_node) in links.iter() {
        let inputs = [source_node.position.coords(), target_node.position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        if link_expression > leo_threshold {
            let distance_sq = source_node.position.distance_square(&target_node.position);
            debug_assert!(distance_sq >= 0.0);
            connection_cost += distance_sq;
            visitor.add_link(source_node, target_node, link_weight1, link_weight2);
        }
    }

    return (bitvec, connection_cost);
}

pub struct CppnDriver;

impl Driver for CppnDriver {
    type IND = CppnGenome<GeometricActivationFunction>;
    type FIT = Fitness;

    /// Creates a random individual for use by the start generation.
    ///
    /// We start from a minimal topology.

    fn random_individual<R>(&self, rng: &mut R) -> Self::IND where R: Rng {
        let mut genome = Self::IND::new();

        // 6 inputs (x1,y1,z1, x2,y2,z2)
        let inp_x1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_y1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_z1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_x2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_y2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_z2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));

        // 1 bias node (constant input of 1.0)
        let bias = genome.add_node(CppnNode::bias(GeometricActivationFunction::Constant1));

        // 4 outputs (t,w,ex,r)
        let out_t  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));
        let out_w  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));
        let out_ex = genome.add_node(CppnNode::output(GeometricActivationFunction::Linear));
        let out_r  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));

        // make those nodes above immutable for mutation and crossover, as we need them to
        // develop the CPPN.
        genome.protect_nodes();

        // XXX: Add x-distance and y-distance Gaussian seed nodes.
        // XXX: Add initial random connections?

        genome
    }

    fn fitness(&self, ind: &Self::IND) -> Self::FIT {
        Fitness {
            domain_fitness: 0.0,
            behavioral_diversity: 0.0,
            connection_cost: 0.0,
        }
    }

    fn mate<R>(&self, rng: &mut R, parent1: &Self::IND, parent2: &Self::IND) -> Self::IND where R: Rng {
        parent1.clone()
    }

    fn population_metric(&self, population: &mut RatedPopulation<Self::IND, Self::FIT>) {
    }
}
<commit_msg>Implement mate()<commit_after>use cppn_ext::cppn::{Cppn, CppnNode};
use cppn_ext::position::Position;
use cppn_ext::activation_function::{GeometricActivationFunction, ActivationFunction};
use weight::{Weight, WeightRange, WeightPerturbanceMethod};
use substrate::{Substrate, Node};
use behavioral_bitvec::BehavioralBitvec;
use genome::Genome;
use nsga2::driver::Driver;
use nsga2::population::{UnratedPopulation, RatedPopulation};
use fitness::Fitness;
use rand::Rng;
use mating::{MatingMethod, MatingMethodWeights};
use prob::Prob;

pub type CppnGenome<AF> where AF: ActivationFunction = Genome<CppnNode<AF>>;

pub trait NetworkBuilderVisitor<P, T> where P: Position {
    fn add_node(&mut self, node: &Node<P, T>, param: f64);
    fn add_link(&mut self,
                source_node: &Node<P, T>,
                target_node: &Node<P, T>,
                weight1: f64,
                weight2: f64);
}

const CPPN_OUTPUT_LINK_WEIGHT1: usize = 0;
const CPPN_OUTPUT_LINK_WEIGHT2: usize = 1;
const CPPN_OUTPUT_LINK_EXPRESSION: usize = 2;
const CPPN_OUTPUT_NODE_WEIGHT: usize = 3;

/// Develops a network out of the CPPN
///
/// Returns the BehavioralBitvec and Connection Cost of the developed network

fn develop_cppn<P, AF, T, V>(cppn: &mut Cppn<CppnNode<AF>, Weight, ()>,
                             null_position: &P,
                             nodes: &[Node<P, T>],
                             links: &[(&Node<P, T>, &Node<P, T>)],
                             visitor: &mut V,
                             leo_threshold: f64)
                             -> (BehavioralBitvec, f64)
    where P: Position,
          AF: ActivationFunction,
          V: NetworkBuilderVisitor<P, T>
{

    // our CPPN has four outputs: link weight 1, link weight 2, link expression output, node weight
    assert!(cppn.output_count() == 4);
    assert!(cppn.input_count() == 6);

    let mut bitvec = BehavioralBitvec::new(4 * (nodes.len() + links.len()));
    let mut connection_cost = 0.0;

    // First visit all nodes

    for node in nodes.iter() {
        let inputs = [node.position.coords(), null_position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        visitor.add_node(node, node_weight)
    }

    for &(source_node, target_node) in links.iter() {
        let inputs = [source_node.position.coords(), target_node.position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        if link_expression > leo_threshold {
            let distance_sq = source_node.position.distance_square(&target_node.position);
            debug_assert!(distance_sq >= 0.0);
            connection_cost += distance_sq;
            visitor.add_link(source_node, target_node, link_weight1, link_weight2);
        }
    }

    return (bitvec, connection_cost);
}

pub struct CppnDriver {
    mating_method_weights: MatingMethodWeights,
    activation_functions: Vec<GeometricActivationFunction>,
    mutate_element_prob: Prob,
    weight_perturbance: WeightPerturbanceMethod,
    link_weight_range: WeightRange,

    mutate_add_node_random_link_weight: bool,
    mutate_drop_node_tournament_k: usize,
    mutate_modify_node_tournament_k: usize,
}

impl CppnDriver {
    fn random_hidden_node<R>(&self, rng: &mut R) -> CppnNode<GeometricActivationFunction> where R: Rng {
        let af = *rng.choose(&self.activation_functions).unwrap();
        CppnNode::hidden(af)
    }
}

impl Driver for CppnDriver {
    type IND = CppnGenome<GeometricActivationFunction>;
    type FIT = Fitness;

    /// Creates a random individual for use by the start generation.
    ///
    /// We start from a minimal topology.

    fn random_individual<R>(&self, rng: &mut R) -> Self::IND where R: Rng {
        let mut genome = Self::IND::new();

        // 6 inputs (x1,y1,z1, x2,y2,z2)
        let inp_x1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_y1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_z1 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_x2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_y2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));
        let inp_z2 = genome.add_node(CppnNode::input(GeometricActivationFunction::Linear));

        // 1 bias node (constant input of 1.0)
        let bias = genome.add_node(CppnNode::bias(GeometricActivationFunction::Constant1));

        // 4 outputs (t,w,ex,r)
        let out_t  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));
        let out_w  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));
        let out_ex = genome.add_node(CppnNode::output(GeometricActivationFunction::Linear));
        let out_r  = genome.add_node(CppnNode::output(GeometricActivationFunction::BipolarGaussian));

        // make those nodes above immutable for mutation and crossover, as we need them to
        // develop the CPPN.
        genome.protect_nodes();

        // XXX: Add x-distance and y-distance Gaussian seed nodes.
        // XXX: Add initial random connections?

        genome
    }

    fn fitness(&self, ind: &Self::IND) -> Self::FIT {
        Fitness {
            domain_fitness: 0.0,
            behavioral_diversity: 0.0,
            connection_cost: 0.0,
        }
    }

    fn mate<R>(&self, rng: &mut R, parent1: &Self::IND, parent2: &Self::IND) -> Self::IND where R: Rng {
        let mut offspring = parent1.clone();

        match MatingMethod::random_with(&self.mating_method_weights, rng) {
            MatingMethod::MutateAddNode => {
                let link_weight =  if self.mutate_add_node_random_link_weight {
                    Some(self.link_weight_range.random_weight(rng))
                } else {
                    // duplicate existing node weight
                    None
                };
                let hidden_node = self.random_hidden_node(rng);
                let _modified = offspring.mutate_add_node(hidden_node, link_weight, rng);
            }
            MatingMethod::MutateDropNode => {
                let _modified = offspring.mutate_drop_node(self.mutate_drop_node_tournament_k, rng);
            }
            MatingMethod::MutateModifyNode => {
                let hidden_node = self.random_hidden_node(rng);
                let _modified = offspring.mutate_modify_node(hidden_node, self.mutate_modify_node_tournament_k, rng);
            }
            MatingMethod::MutateConnect => {
                let link_weight = self.link_weight_range.random_weight(rng);
                let _modified = offspring.mutate_connect(link_weight, rng);
            }
            MatingMethod::MutateDisconnect => {
                let _modified = offspring.mutate_disconnect(rng);
            }
            MatingMethod::MutateWeights => {
                let _modifications = offspring.mutate_weights(self.mutate_element_prob,
                                                         &self.weight_perturbance,
                                                         &self.link_weight_range,
                                                         rng);
            }
            MatingMethod::CrossoverWeights => {
                let _modifications = offspring.crossover_weights(parent2, rng);
            }
        }

        return offspring;
    }

    fn population_metric(&self, population: &mut RatedPopulation<Self::IND, Self::FIT>) {
    }
}
<|endoftext|>


<commit_before>extern crate hyper;

use hyper::{HttpError, HttpResult, Url};
use hyper::client::Request;

fn get_content(url: &str) -> HttpResult<String> {
    let url = match Url::parse(url) {
        Ok(url) => url,
        Err(_) => return Err(HttpError::HttpUriError),
    };
    let fresh_request = try!(Request::get(url));
    let streaming_request = try!(fresh_request.start());
    let mut response = try!(streaming_request.send());
    Ok(try!(response.read_to_string()))
}

fn main() {
    println!("24 days of Rust - hyper (day 5)");
    println!("{}", get_content("http://httpbin.org/status/200"));
}
<commit_msg>String-based post_query.<commit_after>extern crate hyper;

use hyper::{HttpError, HttpResult, Url};
use hyper::client::Request;
use hyper::header::ContentLength;

fn get_content(url: &str) -> HttpResult<String> {
    let url = match Url::parse(url) {
        Ok(url) => url,
        Err(_) => return Err(HttpError::HttpUriError),
    };
    let fresh_request = try!(Request::get(url));
    let streaming_request = try!(fresh_request.start());
    let mut response = try!(streaming_request.send());
    Ok(try!(response.read_to_string()))
}

fn post_query(url: &str, body: &str) -> HttpResult<String> {
    let url = match Url::parse(url) {
        Ok(url) => url,
        Err(_) => return Err(HttpError::HttpUriError),
    };
    let mut fresh_request = try!(Request::post(url));
    fresh_request.headers_mut().set(ContentLength(body.len()));
    let mut streaming_request = try!(fresh_request.start());
    try!(streaming_request.write_str(body));
    let mut response = try!(streaming_request.send());
    Ok(try!(response.read_to_string()))
}

fn main() {
    println!("24 days of Rust - hyper (day 5)");
    println!("{}", get_content("http://httpbin.org/status/200"));
    println!("{}", post_query("http://httpbin.org/post", "key=value"));
}
<|endoftext|>


<commit_before>extern crate sdl2;

use std::path::Path;

use sdl2::event::{Event};
use sdl2::surface::{Surface};

fn main() {
    let mut ctx = sdl2::init().everything().unwrap();

    let window  = match ctx.window("eg05", 640, 480).position_centered().opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    let mut renderer = match window.renderer().build() {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    // Load a surface.
    // Surfaces live in system RAM, so they aren't ideal for performance.
    let surface = match Surface::load_bmp(&Path::new("res/ice-troll.bmp")) {
        Ok(surface) => surface,
        Err(err)    => panic!("failed to load surface: {}", err)
    };

    // Convert a surface to a texture.
    // Textures can be used more efficiently by the GPU. (If one is available.)
    let texture = match renderer.create_texture_from_surface(&surface) {
        Ok(texture) => texture,
        Err(err)    => panic!("failed to convert surface: {}", err)
    };

    let mut drawer = renderer.drawer();

    let _ = drawer.clear();
    // Display the texture.
    // Omitting the src & dst Rect arguments will cause our image to stretch across the entire buffer.
    // Try passing Some(surface.get_rect()) for src & dst instead of None & see how things change.
    let _ = drawer.copy(&texture, None, None);
    let _ = drawer.present();

    let mut events = ctx.event_pump();

    // loop until we receive a QuitEvent
    'event : loop {
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                _               => continue
            }
        }
    }
}

<commit_msg>Fix eg05<commit_after>extern crate sdl2;

use std::path::Path;

use sdl2::event::{Event};
use sdl2::surface::{Surface};

fn main() {
    let ctx = sdl2::init().unwrap();
    let video_ctx = ctx.video().unwrap();

    let window  = match video_ctx.window("eg05", 640, 480).position_centered().opengl().build() {
        Ok(window) => window,
        Err(err)   => panic!("failed to create window: {}", err)
    };

    let mut renderer = match window.renderer().build() {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    // Load a surface.
    // Surfaces live in system RAM, so they aren't ideal for performance.
    let surface = match Surface::load_bmp(&Path::new("res/ice-troll.bmp")) {
        Ok(surface) => surface,
        Err(err)    => panic!("failed to load surface: {}", err)
    };

    // Convert a surface to a texture.
    // Textures can be used more efficiently by the GPU. (If one is available.)
    let texture = match renderer.create_texture_from_surface(&surface) {
        Ok(texture) => texture,
        Err(err)    => panic!("failed to convert surface: {}", err)
    };

    let _ = renderer.clear();
    // Display the texture.
    // Omitting the src & dst Rect arguments will cause our image to stretch across the entire buffer.
    // Try passing Some(surface.get_rect()) for src & dst instead of None & see how things change.
    let _ = renderer.copy(&texture, None, None);
    let _ = renderer.present();

    let mut events = ctx.event_pump().unwrap();

    // loop until we receive a QuitEvent
    'event : loop {
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                _               => continue
            }
        }
    }
}

<|endoftext|>


<commit_before>extern crate ilc;

use std::io;
use std::collections::hash_map::*;

use ilc::log::Event::*;
use ilc::format::{ self, Decode };

struct Person {
    lines: u32,
    words: u32
}

fn words(s: &str) -> u32 {
    s.split_whitespace().filter(|s| !s.is_empty()).count() as u32
}

fn main() {
    let stdin = io::stdin();

    let mut stats: HashMap<String, Person> = HashMap::new();

    let mut parser = format::weechat3::Weechat3;
    for e in parser.decode(stdin.lock()) {
        let m = match e {
            Ok(m) => m,
            Err(err) => panic!(err)
        };

        match m {
            Msg { ref from, ref content, .. } => {
                if stats.contains_key(from) {
                    let p: &mut Person = stats.get_mut(from).unwrap();
                    p.lines += 1;
                    p.words += words(content);
                } else {
                    stats.insert(from.clone(), Person {
                        lines: 1,
                        words: words(content)
                    });
                }
            },
            _ => ()
        }
    }

    let mut stats: Vec<(String, Person)> = stats.into_iter().collect();
    stats.sort_by(|&(_, ref a), &(_, ref b)| b.words.cmp(&a.words));

    for &(ref name, ref stat) in stats.iter().take(10) {
        println!("{}:\n\tLines: {}\n\tWords: {}", name, stat.lines, stat.words)
    }
}
<commit_msg>Fix name prefix stripping<commit_after>extern crate ilc;

use std::io;
use std::collections::hash_map::*;

use ilc::log::Event::*;
use ilc::format::{ self, Decode };

struct Person {
    lines: u32,
    words: u32
}

fn words(s: &str) -> u32 {
    s.split_whitespace().filter(|s| !s.is_empty()).count() as u32
}

fn strip_nick(s: &str) -> &str {
    if s.is_empty() { return s }
    match s.as_bytes()[0] {
        b'~' | b'&' | b'@' | b'%' | b'+' => &s[1..],
        _ => s
    }
}

fn main() {
    let stdin = io::stdin();

    let mut stats: HashMap<String, Person> = HashMap::new();

    let mut parser = format::weechat3::Weechat3;
    for e in parser.decode(stdin.lock()) {
        let m = match e {
            Ok(m) => m,
            Err(err) => panic!(err)
        };

        match m {
            Msg { ref from, ref content, .. } => {
                let nick = strip_nick(from);
                if stats.contains_key(nick) {
                    let p: &mut Person = stats.get_mut(nick).unwrap();
                    p.lines += 1;
                    p.words += words(content);
                } else {
                    stats.insert(nick.to_owned(), Person {
                        lines: 1,
                        words: words(content)
                    });
                }
            },
            _ => ()
        }
    }

    let mut stats: Vec<(String, Person)> = stats.into_iter().collect();
    stats.sort_by(|&(_, ref a), &(_, ref b)| b.words.cmp(&a.words));

    for &(ref name, ref stat) in stats.iter().take(10) {
        println!("{}:\n\tLines: {}\n\tWords: {}", name, stat.lines, stat.words)
    }
}
<|endoftext|>