<commit_before>use std::default::Default;
use ::internal::prelude::*;

macro_rules! colour {
    ($(#[$attr:meta] $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub fn $name() -> Colour {
                    Colour::new($val)
                }
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivilant to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`get_g`]:
///
/// ```rust,ignore
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let colour = Colour::new(role.colour);
/// let green = colour.get_g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`dark_teal`] presets:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::dark_teal();
///
/// assert_eq!(colour.get_tuple(), (17, 128, 106));
/// ```
///
/// [`Role`]: ../model/struct.Role.html
/// [`dark_teal`]: #method.dark_teal
/// [`get_g`]: #method.get_g
#[derive(Clone, Copy, Debug)]
pub struct Colour {
    /// The raw inner 32-bit unsigned integer value of this Colour. This is
    /// worked with to generate values such as the red component value.
    pub value: u32,
}

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivilant
    /// to a specific RGB value, retrieved via [`get_tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_tuple`]: #method.get_tuple
    pub fn new(value: u32) -> Colour {
        Colour {
            value: value,
        }
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).value == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).value == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.get_r(), 217);
    /// assert_eq!(colour.get_g(), 45);
    /// assert_eq!(colour.get_b(), 215);
    /// assert_eq!(colour.get_tuple(), (217, 45, 215));
    /// ```
    pub fn from_rgb(r: u8, g: u8, b: u8) -> Colour {
        let mut uint = r as u32;
        uint = (uint << 8) | (g as u32);
        uint = (uint << 8) | (b as u32);

        Colour::new(uint)
    }

    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Colour> {
        match value {
            Value::U64(v) => Ok(Colour::new(v as u32)),
            Value::I64(v) => Ok(Colour::new(v as u32)),
            other => Err(Error::Decode("Expected valid colour", other)),
        }
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_r(), 100);
    /// ```
    pub fn get_r(&self) -> u8 {
        ((self.value >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_g(), 76);
    /// ```
    pub fn get_g(&self) -> u8 {
        ((self.value >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_b(), 67);
    pub fn get_b(&self) -> u8 {
        (self.value & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivilant to creating a tuple with the return values of
    /// [`get_r`], [`get_g`], and [`get_b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_r`]: #method.get_r
    /// [`get_g`]: #method.get_g
    /// [`get_b`]: #method.get_b
    pub fn get_tuple(&self) -> (u8, u8, u8) {
        (self.get_r(), self.get_g(), self.get_b())
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).get_tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour::new(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).get_r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour::new(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).get_r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour::new(value as u32)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(250, 177, 237)`.
    fabled_pink, 0xFAB1ED;
    /// Creates a new `Colour`, setting its RGB value to `(17, 202, 128)`.
    fooyoo, 0x11CA80;
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    /// This is equivilant to setting the RGB value to `(0, 0, 0)`.
    fn default() -> Colour {
        Colour {
            value: 0,
        }
    }
}
<commit_msg>Add rose water colour<commit_after>use std::default::Default;
use ::internal::prelude::*;

macro_rules! colour {
    ($(#[$attr:meta] $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub fn $name() -> Colour {
                    Colour::new($val)
                }
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivilant to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`get_g`]:
///
/// ```rust,ignore
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let colour = Colour::new(role.colour);
/// let green = colour.get_g();
///
/// println!("The green component is: {}", green);
/// ```
///
/// Creating an instance with the [`dark_teal`] presets:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::dark_teal();
///
/// assert_eq!(colour.get_tuple(), (17, 128, 106));
/// ```
///
/// [`Role`]: ../model/struct.Role.html
/// [`dark_teal`]: #method.dark_teal
/// [`get_g`]: #method.get_g
#[derive(Clone, Copy, Debug)]
pub struct Colour {
    /// The raw inner 32-bit unsigned integer value of this Colour. This is
    /// worked with to generate values such as the red component value.
    pub value: u32,
}

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivilant
    /// to a specific RGB value, retrieved via [`get_tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_tuple`]: #method.get_tuple
    pub fn new(value: u32) -> Colour {
        Colour {
            value: value,
        }
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a `Colour` via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).value == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).value == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.get_r(), 217);
    /// assert_eq!(colour.get_g(), 45);
    /// assert_eq!(colour.get_b(), 215);
    /// assert_eq!(colour.get_tuple(), (217, 45, 215));
    /// ```
    pub fn from_rgb(r: u8, g: u8, b: u8) -> Colour {
        let mut uint = r as u32;
        uint = (uint << 8) | (g as u32);
        uint = (uint << 8) | (b as u32);

        Colour::new(uint)
    }

    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Colour> {
        match value {
            Value::U64(v) => Ok(Colour::new(v as u32)),
            Value::I64(v) => Ok(Colour::new(v as u32)),
            other => Err(Error::Decode("Expected valid colour", other)),
        }
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_r(), 100);
    /// ```
    pub fn get_r(&self) -> u8 {
        ((self.value >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_g(), 76);
    /// ```
    pub fn get_g(&self) -> u8 {
        ((self.value >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_b(), 67);
    pub fn get_b(&self) -> u8 {
        (self.value & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivilant to creating a tuple with the return values of
    /// [`get_r`], [`get_g`], and [`get_b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).get_tuple(), (100, 76, 67));
    /// ```
    ///
    /// [`get_r`]: #method.get_r
    /// [`get_g`]: #method.get_g
    /// [`get_b`]: #method.get_b
    pub fn get_tuple(&self) -> (u8, u8, u8) {
        (self.get_r(), self.get_g(), self.get_b())
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).get_tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour::new(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).get_r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour::new(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).get_r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour::new(value as u32)
    }
}

colour! {
    /// Creates a new `Colour`, setting its RGB value to `(111, 198, 226)`.
    blitz_blue, 0x6FC6E2;
    /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
    blue, 0x3498DB;
    /// Creates a new `Colour`, setting its RGB value to `(114, 137, 218)`.
    blurple, 0x7289DA;
    /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
    dark_blue, 0x206694;
    /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
    dark_gold, 0xC27C0E;
    /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
    dark_green, 0x1F8B4C;
    /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
    dark_grey, 0x607D8B;
    /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
    dark_magenta, 0xAD1457;
    /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
    dark_orange, 0xA84300;
    /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
    dark_purple, 0x71368A;
    /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
    dark_red, 0x992D22;
    /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
    dark_teal, 0x11806A;
    /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
    darker_grey, 0x546E7A;
    /// Creates a new `Colour`, setting its RGB value to `(250, 177, 237)`.
    fabled_pink, 0xFAB1ED;
    /// Creates a new `Colour`, setting its RGB value to `(17, 202, 128)`.
    fooyoo, 0x11CA80;
    /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
    gold, 0xF1C40F;
    /// Creates a new `Colour`, setting its RGB value to `(186, 218, 85)`.
    kerbal, 0xBADA55;
    /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
    light_grey, 0x979C9F;
    /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
    lighter_grey, 0x95A5A6;
    /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
    magenta, 0xE91E63;
    /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
    orange, 0xE67E22;
    /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
    purple, 0x9B59B6;
    /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
    red, 0xE74C3C;
    /// Creates a new `Colour`, setting its RGB value to `(246, 219, 216)`.
    rose_water, 0xF6DBD8;
    /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
    teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a `Colour`, setting the inner value to `0`.
    /// This is equivilant to setting the RGB value to `(0, 0, 0)`.
    fn default() -> Colour {
        Colour {
            value: 0,
        }
    }
}
<|endoftext|>


<commit_before>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.is_in_progress() {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<commit_msg>don't ping hubs if we just refreshed our caches<commit_after>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_sources, update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon() {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect("Environment variable not found");
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    // fork the process
    let pid = unsafe { fork() };
    if pid > 0 {
        let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
            .expect("Failed to create pid file");
        writeln!(&mut file, "{}", pid).expect("Failed to write pid");

        info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
        exit(0);
    }

    // check new crates every minute
    thread::spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            debug!("Checking new crates");
            match doc_builder.get_new_crates() {
                Ok(n) => debug!("{} crates added to queue", n),
                Err(e) => error!("Failed to get new crates: {}", e),
            }

            thread::sleep(Duration::from_secs(60));
        }
    });

    // build new crates every minute
    thread::spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.count() > 0 {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }

                if let Err(e) = update_sources() {
                    error!("Failed to update sources: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package() {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    });

    // update release activity everyday at 23:55
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    });

    // update search index every 3 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    });

    // update github stats every 6 hours
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    });

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::start_web_server(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Tobias Bohumir Schottdorf <tobias.schottdorf@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//  *

// spell-checker:ignore (ToDO) corasick memchr

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::iter::repeat;
use std::path::Path;
use uucore::InvalidEncodingHandling;

mod helper;

static NAME: &str = "nl";
static USAGE: &str = "nl [OPTION]... [FILE]...";
// A regular expression matching everything.

// Settings store options used by nl to produce its output.
pub struct Settings {
    // The variables corresponding to the options -h, -b, and -f.
    header_numbering: NumberingStyle,
    body_numbering: NumberingStyle,
    footer_numbering: NumberingStyle,
    // The variable corresponding to -d
    section_delimiter: [char; 2],
    // The variables corresponding to the options -v, -i, -l, -w.
    starting_line_number: u64,
    line_increment: u64,
    join_blank_lines: u64,
    number_width: usize, // Used with String::from_char, hence usize.
    // The format of the number and the (default value for)
    // renumbering each page.
    number_format: NumberFormat,
    renumber: bool,
    // The string appended to each line number output.
    number_separator: String,
}

// NumberingStyle stores which lines are to be numbered.
// The possible options are:
// 1. Number all lines
// 2. Number only nonempty lines
// 3. Don't number any lines at all
// 4. Number all lines that match a basic regular expression.
#[allow(clippy::enum_variant_names)]
enum NumberingStyle {
    NumberForAll,
    NumberForNonEmpty,
    NumberForNone,
    NumberForRegularExpression(Box<regex::Regex>),
}

// NumberFormat specifies how line numbers are output within their allocated
// space. They are justified to the left or right, in the latter case with
// the option of having all unused space to its left turned into leading zeroes.
enum NumberFormat {
    Left,
    Right,
    RightZero,
}

pub mod options {
    pub const FILE: &str = "file";
    pub const BODY_NUMBERING: &str = "body-numbering";
    pub const SECTION_DELIMITER: &str = "section-delimiter";
    pub const FOOTER_NUMBERING: &str = "footer-numbering";
    pub const HEADER_NUMBERING: &str = "header-numbering";
    pub const LINE_INCREMENT: &str = "line-increment";
    pub const JOIN_BLANK_LINES: &str = "join-blank-lines";
    pub const NUMBER_FORMAT: &str = "number-format";
    pub const NO_RENUMBER: &str = "no-renumber";
    pub const NUMBER_SEPARATOR: &str = "number-separator";
    pub const STARTING_LINE_NUMBER: &str = "starting-line-number";
    pub const NUMBER_WIDTH: &str = "number-width";
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let matches = App::new(executable!())
        .name(NAME)
        .version(crate_version!())
        .usage(USAGE)
        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
        .arg(
            Arg::with_name(options::BODY_NUMBERING)
                .short("b")
                .long(options::BODY_NUMBERING)
                .help("use STYLE for numbering body lines")
                .value_name("SYNTAX"),
        )
        .arg(
            Arg::with_name(options::SECTION_DELIMITER)
                .short("d")
                .long(options::SECTION_DELIMITER)
                .help("use CC for separating logical pages")
                .value_name("CC"),
        )
        .arg(
            Arg::with_name(options::FOOTER_NUMBERING)
                .short("f")
                .long(options::FOOTER_NUMBERING)
                .help("use STYLE for numbering footer lines")
                .value_name("STYLE"),
        )
        .arg(
            Arg::with_name(options::HEADER_NUMBERING)
                .short("h")
                .long(options::HEADER_NUMBERING)
                .help("use STYLE for numbering header lines")
                .value_name("STYLE"),
        )
        .arg(
            Arg::with_name(options::LINE_INCREMENT)
                .short("i")
                .long(options::LINE_INCREMENT)
                .help("line number increment at each line")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::JOIN_BLANK_LINES)
                .short("l")
                .long(options::JOIN_BLANK_LINES)
                .help("group of NUMBER empty lines counted as one")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::NUMBER_FORMAT)
                .short("n")
                .long(options::NUMBER_FORMAT)
                .help("insert line numbers according to FORMAT")
                .value_name("FORMAT"),
        )
        .arg(
            Arg::with_name(options::NO_RENUMBER)
                .short("p")
                .long(options::NO_RENUMBER)
                .help("do not reset line numbers at logical pages"),
        )
        .arg(
            Arg::with_name(options::NUMBER_SEPARATOR)
                .short("s")
                .long(options::NUMBER_SEPARATOR)
                .help("add STRING after (possible) line number")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::STARTING_LINE_NUMBER)
                .short("v")
                .long(options::STARTING_LINE_NUMBER)
                .help("first line number on each logical page")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::NUMBER_WIDTH)
                .short("w")
                .long(options::NUMBER_WIDTH)
                .help("use NUMBER columns for line numbers")
                .value_name("NUMBER"),
        )
        .get_matches_from(args);

    // A mutable settings object, initialized with the defaults.
    let mut settings = Settings {
        header_numbering: NumberingStyle::NumberForNone,
        body_numbering: NumberingStyle::NumberForAll,
        footer_numbering: NumberingStyle::NumberForNone,
        section_delimiter: ['\\', ':'],
        starting_line_number: 1,
        line_increment: 1,
        join_blank_lines: 1,
        number_width: 6,
        number_format: NumberFormat::Right,
        renumber: true,
        number_separator: String::from("\t"),
    };

    // Update the settings from the command line options, and terminate the
    // program if some options could not successfully be parsed.
    let parse_errors = helper::parse_options(&mut settings, &matches);
    if !parse_errors.is_empty() {
        show_error!("Invalid arguments supplied.");
        for message in &parse_errors {
            println!("{}", message);
        }
        return 1;
    }

    let mut read_stdin = false;
    let files: Vec<String> = match matches.values_of(options::FILE) {
        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
        None => vec!["-".to_owned()],
    };

    for file in &files {
        if file == "-" {
            // If both file names and '-' are specified, we choose to treat first all
            // regular files, and then read from stdin last.
            read_stdin = true;
            continue;
        }
        let path = Path::new(file);
        let reader = File::open(path).unwrap();
        let mut buffer = BufReader::new(reader);
        nl(&mut buffer, &settings);
    }

    if read_stdin {
        let mut buffer = BufReader::new(stdin());
        nl(&mut buffer, &settings);
    }
    0
}

// nl implements the main functionality for an individual buffer.
fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) {
    let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
    let mut line_no = settings.starting_line_number;
    // The current line number's width as a string. Using to_string is inefficient
    // but since we only do it once, it should not hurt.
    let mut line_no_width = line_no.to_string().len();
    let line_no_width_initial = line_no_width;
    // Stores the smallest integer with one more digit than line_no, so that
    // when line_no >= line_no_threshold, we need to use one more digit.
    let mut line_no_threshold = 10u64.pow(line_no_width as u32);
    let mut empty_line_count: u64 = 0;
    let fill_char = match settings.number_format {
        NumberFormat::RightZero => '0',
        _ => ' ',
    };
    // Initially, we use the body's line counting settings
    let mut regex_filter = match settings.body_numbering {
        NumberingStyle::NumberForRegularExpression(ref re) => re,
        _ => &regexp,
    };
    let mut line_filter: fn(&str, &regex::Regex) -> bool = pass_regex;
    for mut l in reader.lines().map(|r| r.unwrap()) {
        // Sanitize the string. We want to print the newline ourselves.
        if l.chars().last() == Some('\n') {
            l.pop();
        }
        // Next we iterate through the individual chars to see if this
        // is one of the special lines starting a new "section" in the
        // document.
        let line = l;
        let mut odd = false;
        // matched_group counts how many copies of section_delimiter
        // this string consists of (0 if there's anything else)
        let mut matched_groups = 0u8;
        for c in line.chars() {
            // If this is a newline character, the loop should end.
            if c == '\n' {
                break;
            }
            // If we have already seen three groups (corresponding to
            // a header) or the current char does not form part of
            // a new group, then this line is not a segment indicator.
            if matched_groups >= 3 || settings.section_delimiter[if odd { 1 } else { 0 }] != c {
                matched_groups = 0;
                break;
            }
            if odd {
                // We have seen a new group and count it.
                matched_groups += 1;
            }
            odd = !odd;
        }

        // See how many groups we matched. That will tell us if this is
        // a line starting a new segment, and the number of groups
        // indicates what type of segment.
        if matched_groups > 0 {
            // The current line is a section delimiter, so we output
            // a blank line.
            println!();
            // However the line does not count as a blank line, so we
            // reset the counter used for --join-blank-lines.
            empty_line_count = 0;
            match *match matched_groups {
                3 => {
                    // This is a header, so we may need to reset the
                    // line number and the line width
                    if settings.renumber {
                        line_no = settings.starting_line_number;
                        line_no_width = line_no_width_initial;
                        line_no_threshold = 10u64.pow(line_no_width as u32);
                    }
                    &settings.header_numbering
                }
                1 => &settings.footer_numbering,
                // The only option left is 2, but rust wants
                // a catch-all here.
                _ => &settings.body_numbering,
            } {
                NumberingStyle::NumberForAll => {
                    line_filter = pass_all;
                }
                NumberingStyle::NumberForNonEmpty => {
                    line_filter = pass_nonempty;
                }
                NumberingStyle::NumberForNone => {
                    line_filter = pass_none;
                }
                NumberingStyle::NumberForRegularExpression(ref re) => {
                    line_filter = pass_regex;
                    regex_filter = re;
                }
            }
            continue;
        }
        // From this point on we format and print a "regular" line.
        if line.is_empty() {
            // The line is empty, which means that we have to care
            // about the --join-blank-lines parameter.
            empty_line_count += 1;
        } else {
            // This saves us from having to check for an empty string
            // in the next selector.
            empty_line_count = 0;
        }
        if !line_filter(&line, regex_filter)
            || (empty_line_count > 0 && empty_line_count < settings.join_blank_lines)
        {
            // No number is printed for this line. Either we did not
            // want to print one in the first place, or it is a blank
            // line but we are still collecting more blank lines via
            // the option --join-blank-lines.
            println!("{}", line);
            continue;
        }
        // If we make it here, then either we are printing a non-empty
        // line or assigning a line number to an empty line. Either
        // way, start counting empties from zero once more.
        empty_line_count = 0;
        // A line number is to be printed.
        let w = if settings.number_width > line_no_width {
            settings.number_width - line_no_width
        } else {
            0
        };
        let fill: String = repeat(fill_char).take(w).collect();
        match settings.number_format {
            NumberFormat::Left => println!(
                "{1}{0}{2}{3}",
                fill, line_no, settings.number_separator, line
            ),
            _ => println!(
                "{0}{1}{2}{3}",
                fill, line_no, settings.number_separator, line
            ),
        }
        // Now update the variables for the (potential) next
        // line.
        line_no += settings.line_increment;
        while line_no >= line_no_threshold {
            // The line number just got longer.
            line_no_threshold *= 10;
            line_no_width += 1;
        }
    }
}

fn pass_regex(line: &str, re: &regex::Regex) -> bool {
    re.is_match(line)
}

fn pass_nonempty(line: &str, _: &regex::Regex) -> bool {
    !line.is_empty()
}

fn pass_none(_: &str, _: &regex::Regex) -> bool {
    false
}

fn pass_all(_: &str, _: &regex::Regex) -> bool {
    true
}
<commit_msg>nl: fix clippy error<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Tobias Bohumir Schottdorf <tobias.schottdorf@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
//  *

// spell-checker:ignore (ToDO) corasick memchr

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::iter::repeat;
use std::path::Path;
use uucore::InvalidEncodingHandling;

mod helper;

static NAME: &str = "nl";
static USAGE: &str = "nl [OPTION]... [FILE]...";
// A regular expression matching everything.

// Settings store options used by nl to produce its output.
pub struct Settings {
    // The variables corresponding to the options -h, -b, and -f.
    header_numbering: NumberingStyle,
    body_numbering: NumberingStyle,
    footer_numbering: NumberingStyle,
    // The variable corresponding to -d
    section_delimiter: [char; 2],
    // The variables corresponding to the options -v, -i, -l, -w.
    starting_line_number: u64,
    line_increment: u64,
    join_blank_lines: u64,
    number_width: usize, // Used with String::from_char, hence usize.
    // The format of the number and the (default value for)
    // renumbering each page.
    number_format: NumberFormat,
    renumber: bool,
    // The string appended to each line number output.
    number_separator: String,
}

// NumberingStyle stores which lines are to be numbered.
// The possible options are:
// 1. Number all lines
// 2. Number only nonempty lines
// 3. Don't number any lines at all
// 4. Number all lines that match a basic regular expression.
#[allow(clippy::enum_variant_names)]
enum NumberingStyle {
    NumberForAll,
    NumberForNonEmpty,
    NumberForNone,
    NumberForRegularExpression(Box<regex::Regex>),
}

// NumberFormat specifies how line numbers are output within their allocated
// space. They are justified to the left or right, in the latter case with
// the option of having all unused space to its left turned into leading zeroes.
enum NumberFormat {
    Left,
    Right,
    RightZero,
}

pub mod options {
    pub const FILE: &str = "file";
    pub const BODY_NUMBERING: &str = "body-numbering";
    pub const SECTION_DELIMITER: &str = "section-delimiter";
    pub const FOOTER_NUMBERING: &str = "footer-numbering";
    pub const HEADER_NUMBERING: &str = "header-numbering";
    pub const LINE_INCREMENT: &str = "line-increment";
    pub const JOIN_BLANK_LINES: &str = "join-blank-lines";
    pub const NUMBER_FORMAT: &str = "number-format";
    pub const NO_RENUMBER: &str = "no-renumber";
    pub const NUMBER_SEPARATOR: &str = "number-separator";
    pub const STARTING_LINE_NUMBER: &str = "starting-line-number";
    pub const NUMBER_WIDTH: &str = "number-width";
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let matches = App::new(executable!())
        .name(NAME)
        .version(crate_version!())
        .usage(USAGE)
        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
        .arg(
            Arg::with_name(options::BODY_NUMBERING)
                .short("b")
                .long(options::BODY_NUMBERING)
                .help("use STYLE for numbering body lines")
                .value_name("SYNTAX"),
        )
        .arg(
            Arg::with_name(options::SECTION_DELIMITER)
                .short("d")
                .long(options::SECTION_DELIMITER)
                .help("use CC for separating logical pages")
                .value_name("CC"),
        )
        .arg(
            Arg::with_name(options::FOOTER_NUMBERING)
                .short("f")
                .long(options::FOOTER_NUMBERING)
                .help("use STYLE for numbering footer lines")
                .value_name("STYLE"),
        )
        .arg(
            Arg::with_name(options::HEADER_NUMBERING)
                .short("h")
                .long(options::HEADER_NUMBERING)
                .help("use STYLE for numbering header lines")
                .value_name("STYLE"),
        )
        .arg(
            Arg::with_name(options::LINE_INCREMENT)
                .short("i")
                .long(options::LINE_INCREMENT)
                .help("line number increment at each line")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::JOIN_BLANK_LINES)
                .short("l")
                .long(options::JOIN_BLANK_LINES)
                .help("group of NUMBER empty lines counted as one")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::NUMBER_FORMAT)
                .short("n")
                .long(options::NUMBER_FORMAT)
                .help("insert line numbers according to FORMAT")
                .value_name("FORMAT"),
        )
        .arg(
            Arg::with_name(options::NO_RENUMBER)
                .short("p")
                .long(options::NO_RENUMBER)
                .help("do not reset line numbers at logical pages"),
        )
        .arg(
            Arg::with_name(options::NUMBER_SEPARATOR)
                .short("s")
                .long(options::NUMBER_SEPARATOR)
                .help("add STRING after (possible) line number")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::STARTING_LINE_NUMBER)
                .short("v")
                .long(options::STARTING_LINE_NUMBER)
                .help("first line number on each logical page")
                .value_name("NUMBER"),
        )
        .arg(
            Arg::with_name(options::NUMBER_WIDTH)
                .short("w")
                .long(options::NUMBER_WIDTH)
                .help("use NUMBER columns for line numbers")
                .value_name("NUMBER"),
        )
        .get_matches_from(args);

    // A mutable settings object, initialized with the defaults.
    let mut settings = Settings {
        header_numbering: NumberingStyle::NumberForNone,
        body_numbering: NumberingStyle::NumberForAll,
        footer_numbering: NumberingStyle::NumberForNone,
        section_delimiter: ['\\', ':'],
        starting_line_number: 1,
        line_increment: 1,
        join_blank_lines: 1,
        number_width: 6,
        number_format: NumberFormat::Right,
        renumber: true,
        number_separator: String::from("\t"),
    };

    // Update the settings from the command line options, and terminate the
    // program if some options could not successfully be parsed.
    let parse_errors = helper::parse_options(&mut settings, &matches);
    if !parse_errors.is_empty() {
        show_error!("Invalid arguments supplied.");
        for message in &parse_errors {
            println!("{}", message);
        }
        return 1;
    }

    let mut read_stdin = false;
    let files: Vec<String> = match matches.values_of(options::FILE) {
        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
        None => vec!["-".to_owned()],
    };

    for file in &files {
        if file == "-" {
            // If both file names and '-' are specified, we choose to treat first all
            // regular files, and then read from stdin last.
            read_stdin = true;
            continue;
        }
        let path = Path::new(file);
        let reader = File::open(path).unwrap();
        let mut buffer = BufReader::new(reader);
        nl(&mut buffer, &settings);
    }

    if read_stdin {
        let mut buffer = BufReader::new(stdin());
        nl(&mut buffer, &settings);
    }
    0
}

// nl implements the main functionality for an individual buffer.
fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) {
    let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
    let mut line_no = settings.starting_line_number;
    // The current line number's width as a string. Using to_string is inefficient
    // but since we only do it once, it should not hurt.
    let mut line_no_width = line_no.to_string().len();
    let line_no_width_initial = line_no_width;
    // Stores the smallest integer with one more digit than line_no, so that
    // when line_no >= line_no_threshold, we need to use one more digit.
    let mut line_no_threshold = 10u64.pow(line_no_width as u32);
    let mut empty_line_count: u64 = 0;
    let fill_char = match settings.number_format {
        NumberFormat::RightZero => '0',
        _ => ' ',
    };
    // Initially, we use the body's line counting settings
    let mut regex_filter = match settings.body_numbering {
        NumberingStyle::NumberForRegularExpression(ref re) => re,
        _ => &regexp,
    };
    let mut line_filter: fn(&str, &regex::Regex) -> bool = pass_regex;
    for mut l in reader.lines().map(|r| r.unwrap()) {
        // Sanitize the string. We want to print the newline ourselves.
        if l.ends_with('\n') {
            l.pop();
        }
        // Next we iterate through the individual chars to see if this
        // is one of the special lines starting a new "section" in the
        // document.
        let line = l;
        let mut odd = false;
        // matched_group counts how many copies of section_delimiter
        // this string consists of (0 if there's anything else)
        let mut matched_groups = 0u8;
        for c in line.chars() {
            // If this is a newline character, the loop should end.
            if c == '\n' {
                break;
            }
            // If we have already seen three groups (corresponding to
            // a header) or the current char does not form part of
            // a new group, then this line is not a segment indicator.
            if matched_groups >= 3 || settings.section_delimiter[if odd { 1 } else { 0 }] != c {
                matched_groups = 0;
                break;
            }
            if odd {
                // We have seen a new group and count it.
                matched_groups += 1;
            }
            odd = !odd;
        }

        // See how many groups we matched. That will tell us if this is
        // a line starting a new segment, and the number of groups
        // indicates what type of segment.
        if matched_groups > 0 {
            // The current line is a section delimiter, so we output
            // a blank line.
            println!();
            // However the line does not count as a blank line, so we
            // reset the counter used for --join-blank-lines.
            empty_line_count = 0;
            match *match matched_groups {
                3 => {
                    // This is a header, so we may need to reset the
                    // line number and the line width
                    if settings.renumber {
                        line_no = settings.starting_line_number;
                        line_no_width = line_no_width_initial;
                        line_no_threshold = 10u64.pow(line_no_width as u32);
                    }
                    &settings.header_numbering
                }
                1 => &settings.footer_numbering,
                // The only option left is 2, but rust wants
                // a catch-all here.
                _ => &settings.body_numbering,
            } {
                NumberingStyle::NumberForAll => {
                    line_filter = pass_all;
                }
                NumberingStyle::NumberForNonEmpty => {
                    line_filter = pass_nonempty;
                }
                NumberingStyle::NumberForNone => {
                    line_filter = pass_none;
                }
                NumberingStyle::NumberForRegularExpression(ref re) => {
                    line_filter = pass_regex;
                    regex_filter = re;
                }
            }
            continue;
        }
        // From this point on we format and print a "regular" line.
        if line.is_empty() {
            // The line is empty, which means that we have to care
            // about the --join-blank-lines parameter.
            empty_line_count += 1;
        } else {
            // This saves us from having to check for an empty string
            // in the next selector.
            empty_line_count = 0;
        }
        if !line_filter(&line, regex_filter)
            || (empty_line_count > 0 && empty_line_count < settings.join_blank_lines)
        {
            // No number is printed for this line. Either we did not
            // want to print one in the first place, or it is a blank
            // line but we are still collecting more blank lines via
            // the option --join-blank-lines.
            println!("{}", line);
            continue;
        }
        // If we make it here, then either we are printing a non-empty
        // line or assigning a line number to an empty line. Either
        // way, start counting empties from zero once more.
        empty_line_count = 0;
        // A line number is to be printed.
        let w = if settings.number_width > line_no_width {
            settings.number_width - line_no_width
        } else {
            0
        };
        let fill: String = repeat(fill_char).take(w).collect();
        match settings.number_format {
            NumberFormat::Left => println!(
                "{1}{0}{2}{3}",
                fill, line_no, settings.number_separator, line
            ),
            _ => println!(
                "{0}{1}{2}{3}",
                fill, line_no, settings.number_separator, line
            ),
        }
        // Now update the variables for the (potential) next
        // line.
        line_no += settings.line_increment;
        while line_no >= line_no_threshold {
            // The line number just got longer.
            line_no_threshold *= 10;
            line_no_width += 1;
        }
    }
}

fn pass_regex(line: &str, re: &regex::Regex) -> bool {
    re.is_match(line)
}

fn pass_nonempty(line: &str, _: &regex::Regex) -> bool {
    !line.is_empty()
}

fn pass_none(_: &str, _: &regex::Regex) -> bool {
    false
}

fn pass_all(_: &str, _: &regex::Regex) -> bool {
    true
}
<|endoftext|>


<commit_before>use unicode_width::UnicodeWidthStr;

use crate::buffer::Buffer;
use crate::layout::Rect;
use crate::style::Style;
use crate::symbols::line;
use crate::widgets::{Block, Widget};

/// A widget to display available tabs in a multiple panels context.
///
/// # Examples
///
/// ```
/// # use tui::widgets::{Block, Borders, Tabs};
/// # use tui::style::{Style, Color};
/// # use tui::symbols::{DOT};
/// Tabs::default()
///     .block(Block::default().title("Tabs").borders(Borders::ALL))
///     .titles(&["Tab1", "Tab2", "Tab3", "Tab4"])
///     .style(Style::default().fg(Color::White))
///     .highlight_style(Style::default().fg(Color::Yellow))
///     .divider(DOT);
/// ```
#[derive(Debug, Clone)]
pub struct Tabs<'a, T>
where
    T: AsRef<str> + 'a,
{
    /// A block to wrap this widget in if necessary
    block: Option<Block<'a>>,
    /// One title for each tab
    titles: &'a [T],
    /// The index of the selected tabs
    selected: usize,
    /// The style used to draw the text
    style: Style,
    /// The style used to display the selected item
    highlight_style: Style,
    /// Tab divider
    divider: &'a str,
}

impl<'a, T> Default for Tabs<'a, T>
where
    T: AsRef<str>,
{
    fn default() -> Tabs<'a, T> {
        Tabs {
            block: None,
            titles: &[],
            selected: 0,
            style: Default::default(),
            highlight_style: Default::default(),
            divider: line::VERTICAL,
        }
    }
}

impl<'a, T> Tabs<'a, T>
where
    T: AsRef<str>,
{
    pub fn block(mut self, block: Block<'a>) -> Tabs<'a, T> {
        self.block = Some(block);
        self
    }

    pub fn titles(mut self, titles: &'a [T]) -> Tabs<'a, T> {
        self.titles = titles;
        self
    }

    pub fn select(mut self, selected: usize) -> Tabs<'a, T> {
        self.selected = selected;
        self
    }

    pub fn style(mut self, style: Style) -> Tabs<'a, T> {
        self.style = style;
        self
    }

    pub fn highlight_style(mut self, style: Style) -> Tabs<'a, T> {
        self.highlight_style = style;
        self
    }

    pub fn divider(mut self, divider: &'a str) -> Tabs<'a, T> {
        self.divider = divider;
        self
    }
}

impl<'a, T> Widget for Tabs<'a, T>
where
    T: AsRef<str>,
{
    fn render(mut self, area: Rect, buf: &mut Buffer) {
        let tabs_area = match self.block {
            Some(ref mut b) => {
                b.render(area, buf);
                b.inner(area)
            }
            None => area,
        };

        if tabs_area.height < 1 {
            return;
        }

        buf.set_background(tabs_area, self.style.bg);

        let mut x = tabs_area.left();
        let titles_length = self.titles.len();
        let divider_width = self.divider.width() as u16;
        for (title, style, last_title) in self.titles.iter().enumerate().map(|(i, t)| {
            let lt = i + 1 == titles_length;
            if i == self.selected {
                (t, self.highlight_style, lt)
            } else {
                (t, self.style, lt)
            }
        }) {
            x += 1;
            if x > tabs_area.right() {
                break;
            } else {
                buf.set_string(x, tabs_area.top(), title.as_ref(), style);
                x += title.as_ref().width() as u16 + 1;
                if x >= tabs_area.right() || last_title {
                    break;
                } else {
                    buf.set_string(x, tabs_area.top(), self.divider, self.style);
                    x += divider_width;
                }
            }
        }
    }
}
<commit_msg>fix panic on narrow buffers (fixes #293)<commit_after>use unicode_width::UnicodeWidthStr;

use crate::buffer::Buffer;
use crate::layout::Rect;
use crate::style::Style;
use crate::symbols::line;
use crate::widgets::{Block, Widget};

/// A widget to display available tabs in a multiple panels context.
///
/// # Examples
///
/// ```
/// # use tui::widgets::{Block, Borders, Tabs};
/// # use tui::style::{Style, Color};
/// # use tui::symbols::{DOT};
/// Tabs::default()
///     .block(Block::default().title("Tabs").borders(Borders::ALL))
///     .titles(&["Tab1", "Tab2", "Tab3", "Tab4"])
///     .style(Style::default().fg(Color::White))
///     .highlight_style(Style::default().fg(Color::Yellow))
///     .divider(DOT);
/// ```
#[derive(Debug, Clone)]
pub struct Tabs<'a, T>
where
    T: AsRef<str> + 'a,
{
    /// A block to wrap this widget in if necessary
    block: Option<Block<'a>>,
    /// One title for each tab
    titles: &'a [T],
    /// The index of the selected tabs
    selected: usize,
    /// The style used to draw the text
    style: Style,
    /// The style used to display the selected item
    highlight_style: Style,
    /// Tab divider
    divider: &'a str,
}

impl<'a, T> Default for Tabs<'a, T>
where
    T: AsRef<str>,
{
    fn default() -> Tabs<'a, T> {
        Tabs {
            block: None,
            titles: &[],
            selected: 0,
            style: Default::default(),
            highlight_style: Default::default(),
            divider: line::VERTICAL,
        }
    }
}

impl<'a, T> Tabs<'a, T>
where
    T: AsRef<str>,
{
    pub fn block(mut self, block: Block<'a>) -> Tabs<'a, T> {
        self.block = Some(block);
        self
    }

    pub fn titles(mut self, titles: &'a [T]) -> Tabs<'a, T> {
        self.titles = titles;
        self
    }

    pub fn select(mut self, selected: usize) -> Tabs<'a, T> {
        self.selected = selected;
        self
    }

    pub fn style(mut self, style: Style) -> Tabs<'a, T> {
        self.style = style;
        self
    }

    pub fn highlight_style(mut self, style: Style) -> Tabs<'a, T> {
        self.highlight_style = style;
        self
    }

    pub fn divider(mut self, divider: &'a str) -> Tabs<'a, T> {
        self.divider = divider;
        self
    }
}

impl<'a, T> Widget for Tabs<'a, T>
where
    T: AsRef<str>,
{
    fn render(mut self, area: Rect, buf: &mut Buffer) {
        let tabs_area = match self.block {
            Some(ref mut b) => {
                b.render(area, buf);
                b.inner(area)
            }
            None => area,
        };

        if tabs_area.height < 1 {
            return;
        }

        buf.set_background(tabs_area, self.style.bg);

        let mut x = tabs_area.left();
        let titles_length = self.titles.len();
        let divider_width = self.divider.width() as u16;
        for (title, style, last_title) in self.titles.iter().enumerate().map(|(i, t)| {
            let lt = i + 1 == titles_length;
            if i == self.selected {
                (t, self.highlight_style, lt)
            } else {
                (t, self.style, lt)
            }
        }) {
            x += 1;
            if x >= tabs_area.right() {
                break;
            } else {
                buf.set_string(x, tabs_area.top(), title.as_ref(), style);
                x += title.as_ref().width() as u16 + 1;
                if x >= tabs_area.right() || last_title {
                    break;
                } else {
                    buf.set_string(x, tabs_area.top(), self.divider, self.style);
                    x += divider_width;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::Vec3;
// use cgmath::point::Point3;

#[link_args="-lglfw"] extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  print(name);
  print(":\n");
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_WIDTH: uint = 640;
static WIN_HEIGHT: uint = 480;
static VERTICES_COUNT: i32 = 3 * 2;

// Vertex data
static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

// Shader sources
static VS_SRC: &'static str = "\
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FS_SRC: &'static str = "\
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vs);
  gl::AttachShader(program, fs);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);

  do glfw::start {
    // glfw::window_hint::context_version(3, 2);

    let window = glfw::Window::create(
      WIN_WIDTH, WIN_HEIGHT, "OpenGL", glfw::Windowed).unwrap();
    window.make_context_current();
    window.set_cursor_pos_callback(~CursorPosContext);
    window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut vao);
      gl::BindVertexArray(vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(program);
      gl::BindFragDataLocation(program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    while !window.should_close() {
      glfw::poll_events();

      upd(program);

      // Clear the screen to black
      gl::ClearColor(0.3, 0.3, 0.3, 1.0);
      gl::Clear(gl::COLOR_BUFFER_BIT);

      // Draw a triangle from the 3 vertices
      gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

      window.swap_buffers();
    }

    // Cleanup
    gl::DeleteProgram(program);
    gl::DeleteShader(fs);
    gl::DeleteShader(vs);
    unsafe {
      gl::DeleteBuffers(1, &vbo);
      gl::DeleteVertexArrays(1, &vao);
    }
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        POS.x = xpos as f32;
        POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Few style fixes<commit_after>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::Vec3;

#[link_args="-lglfw"] extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  print(name);
  print(":\n");
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_WIDTH: uint = 640;
static WIN_HEIGHT: uint = 480;
static VERTICES_COUNT: i32 = 3 * 2;

// Vertex data
static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

// Shader sources
static VERTEX_SHADER_SRC: &'static str = "\
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "\
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vs);
  gl::AttachShader(program, fs);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);

  do glfw::start {
    // glfw::window_hint::context_version(3, 2);

    let window = glfw::Window::create(
      WIN_WIDTH, WIN_HEIGHT, "OpenGL", glfw::Windowed).unwrap();
    window.make_context_current();
    window.set_cursor_pos_callback(~CursorPosContext);
    window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    let vs = compile_shader(VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut vao);
      gl::BindVertexArray(vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(program);
      gl::BindFragDataLocation(program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    while !window.should_close() {
      glfw::poll_events();

      upd(program);

      // Clear the screen to black
      gl::ClearColor(0.3, 0.3, 0.3, 1.0);
      gl::Clear(gl::COLOR_BUFFER_BIT);

      // Draw a triangle from the 3 vertices
      gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

      window.swap_buffers();
    }

    // Cleanup
    gl::DeleteProgram(program);
    gl::DeleteShader(fs);
    gl::DeleteShader(vs);
    unsafe {
      gl::DeleteBuffers(1, &vbo);
      gl::DeleteVertexArrays(1, &vao);
    }
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        POS.x = xpos as f32;
        POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;
extern crate collections;

use collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
//use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: ~str,
    methods: Vec<~str>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[~str]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert(&"d",|_, cfg| { cfg.decompress = true; });
        handlers.insert(&"block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
            if arg.starts_with(&"-") {
                match handlers.mut_iter().find(|&(&k,_)| arg.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(arg.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", *arg),
                }
            }else {
                cfg.methods.push(arg.to_owned());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |~Writer,&Config|:'static -> ~io::Writer,
    decode: |~Reader,&Config|:'static -> ~io::Reader,
    info: ~str,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<~str,Pass> = HashMap::new();
    passes.insert(~"dummy", Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: ~"pass-through",
    });
    /* // unclear what to do with Ari since it requires the size to be known
    passes.insert(~"ari", Pass {
        encode: |w,_c| {
            ~ari::ByteEncoder::new(w) as ~Writer
        },
        decode: |r,_c| {
            ~ari::ByteDecoder::new(r) as ~Reader
        },
        info: ~"Adaptive arithmetic byte coder",
    });*/
    passes.insert(~"bwt", Pass {
        encode: |w,c| {
            ~bwt::Encoder::new(w, c.block_size) as ~Writer
        },
        decode: |r,_c| {
            ~bwt::Decoder::new(r, true) as ~Reader
        },
        info: ~"Burrows-Wheeler Transformation",
    });
    passes.insert(~"mtf", Pass {
        encode: |w,_c| {
            ~bwt::mtf::Encoder::new(w) as ~Writer
        },
        decode: |r,_c| {
            ~bwt::mtf::Decoder::new(r) as ~Reader
        },
        info: ~"Move-To-Front Transformation",
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert(~"lz4", Pass {
        encode: |w,_c| {
            ~lz4::Encoder::new(w) as ~Writer
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            ~lz4::Decoder::new(r) as ~Reader
        },
        info: ~"Ziv-Lempel derivative, focused at speed",
    });

    let config = Config::query(os::args());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn( input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_owned()
        });
        let mut rsum: ~Reader = ~input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(*met).unwrap();
        }
        let mut wsum: ~Writer = ~output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<commit_msg>Update to master<commit_after>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;
extern crate collections;

use collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
//use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: ~str,
    methods: Vec<~str>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[~str]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert("d",|_, cfg| { cfg.decompress = true; });
        handlers.insert("block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
            if arg.starts_with("-") {
                match handlers.mut_iter().find(|&(&k,_)| arg.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(arg.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", *arg),
                }
            }else {
                cfg.methods.push(arg.to_owned());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |~Writer,&Config|:'static -> ~io::Writer,
    decode: |~Reader,&Config|:'static -> ~io::Reader,
    info: ~str,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<~str,Pass> = HashMap::new();
    passes.insert("dummy".to_str(), Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: "pass-through".to_str(),
    });
    /* // unclear what to do with Ari since it requires the size to be known
    passes.insert(~"ari", Pass {
        encode: |w,_c| {
            ~ari::ByteEncoder::new(w) as ~Writer
        },
        decode: |r,_c| {
            ~ari::ByteDecoder::new(r) as ~Reader
        },
        info: ~"Adaptive arithmetic byte coder",
    });*/
    passes.insert("bwt".to_str(), Pass {
        encode: |w,c| {
            ~bwt::Encoder::new(w, c.block_size) as ~Writer
        },
        decode: |r,_c| {
            ~bwt::Decoder::new(r, true) as ~Reader
        },
        info: "Burrows-Wheeler Transformation".to_str(),
    });
    passes.insert("mtf".to_str(), Pass {
        encode: |w,_c| {
            ~bwt::mtf::Encoder::new(w) as ~Writer
        },
        decode: |r,_c| {
            ~bwt::mtf::Decoder::new(r) as ~Reader
        },
        info: "Move-To-Front Transformation".to_str(),
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert("lz4".to_str(), Pass {
        encode: |w,_c| {
            ~lz4::Encoder::new(w) as ~Writer
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            ~lz4::Decoder::new(r) as ~Reader
        },
        info: "Ziv-Lempel derivative, focused at speed".to_str(),
    });

    let config = Config::query(os::args());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn( input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_owned()
        });
        let mut rsum: ~Reader = ~input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(*met).unwrap();
        }
        let mut wsum: ~Writer = ~output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<|endoftext|>