<commit_before>#[crate_type = "rlib"];

use std::{iter, vec};

pub static EXPECTED_ANSWER: &'static str = "18407904";

// [定理]
// a + b = c のとき、
// GCD(a, b) = 1 => GCD(a, c) = GCD(b, c) = 1
//
// [証明]
// まず、GCD(a, b) = 1 => GCD(a, c) = 1 を示す。
// GCD(a, b) のとき、GCD(a, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて a = kn, c = km と表すことができる。
// b = c - a = km - kn = k(m, n) より、GCD(a, b) >= k となり矛盾。
// よって、GCD(a, c) = 1 である。
//
// 次に、GCD(a, b) = 1 => GCD(b, c) = 1 を示す。
// GCD(a, b) = 1 のとき、GCD(b, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて b = kn, c = km と表すことができる。
// ここで、a = c - b = km - kn = k(m - n) より、 GCD(a, b) >= k となり矛盾。
// よって、GCD(b, c) = 1 である。

#[deriving(Eq)]
struct Rad(uint, ~[uint]);

fn create_rad_vec(n_limit: uint) -> ~[Rad] {
    let mut rad_vec = vec::from_fn(n_limit, |_| Rad(1, ~[]));
    for p in range(2, rad_vec.len()) {
        let Rad(n, _) = rad_vec[p];
        if n != 1 { continue }

        for np in iter::count(p, p).take_while(|&np| np < n_limit) {
            let Rad(ref mut n, ref mut facts) = rad_vec[np];
            (*n) *= p;
            facts.push(p);
        }
    }
    rad_vec
}

fn rad_has_union(&Rad(_, ref a): &Rad, &Rad(_, ref b): &Rad) -> bool {
    let mut i_a = 0;
    let mut i_b = 0;

    loop {
        if i_a >= a.len() || i_b >= b.len() { return false }
        match a[i_a].cmp(&b[i_b]) {
            Equal   => return true,
            Less    => i_a += 1,
            Greater => i_b += 1
        }
    }
}

fn abc_hits_c_sum(c_limit: uint) -> uint {
    let rad_vec = create_rad_vec(c_limit);
    let mut c_sum = 0;

    for c in range(3, c_limit) {
        let Rad(rad_c, _) = rad_vec[c];
        for a in range(1, (c + 1) / 2) {
            let b = c - a;
            let Rad(rad_a, _) = rad_vec[a];
            let Rad(rad_b, _) = rad_vec[b];
            let rad_abc = rad_a * rad_b * rad_c;
            if rad_abc >= c || (a > 1 && rad_has_union(&rad_vec[a], &rad_vec[c])) { continue; }
            c_sum += c;
        }
    }

    c_sum
}

pub fn solve() -> ~str { abc_hits_c_sum(120000).to_str() }

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

    #[test]
    fn create_rad_vec() {
        let rad_vec = ~[
            Rad(1, ~[]), Rad(1, ~[]), Rad(2, ~[2]), Rad(3, ~[3]), Rad(2, ~[2]), Rad(5, ~[5]),
            Rad(6, ~[2, 3]), Rad(7, ~[7]), Rad(2, ~[2]), Rad(3, ~[3])];
        assert_eq!(rad_vec, super::create_rad_vec(10))
    }

    #[test]
    fn rad_has_union() {
        assert!(super::rad_has_union(&Rad(2, ~[2]), &Rad(2, ~[2])));
        assert!(!super::rad_has_union(&Rad(2, ~[2]), &Rad(3, ~[4])));

        assert!(super::rad_has_union(&Rad(3, ~[3]), &Rad(6, ~[2, 3])));
        assert!(super::rad_has_union(&Rad(15, ~[3, 5]), &Rad(10, ~[2, 5])));

        assert!(!super::rad_has_union(&Rad(30, ~[2, 3, 5]), &Rad(1001, ~[7, 11, 13])));
    }

    #[test]
    fn abc_hits_c_sum() {
        assert_eq!(12523, super::abc_hits_c_sum(1000));
    }
}
<commit_msg>Some optimization for #127<commit_after>#[crate_type = "rlib"];

use std::{iter, vec};

pub static EXPECTED_ANSWER: &'static str = "18407904";

// [定理]
// a + b = c のとき、
// GCD(a, b) = 1 => GCD(a, c) = GCD(b, c) = 1
//
// [証明]
// まず、GCD(a, b) = 1 => GCD(a, c) = 1 を示す。
// GCD(a, b) のとき、GCD(a, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて a = kn, c = km と表すことができる。
// b = c - a = km - kn = k(m, n) より、GCD(a, b) >= k となり矛盾。
// よって、GCD(a, c) = 1 である。
//
// 次に、GCD(a, b) = 1 => GCD(b, c) = 1 を示す。
// GCD(a, b) = 1 のとき、GCD(b, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて b = kn, c = km と表すことができる。
// ここで、a = c - b = km - kn = k(m - n) より、 GCD(a, b) >= k となり矛盾。
// よって、GCD(b, c) = 1 である。

#[deriving(Eq)]
struct Rad(uint, ~[uint]);

fn create_rad_vec(n_limit: uint) -> ~[Rad] {
    let mut rad_vec = vec::from_fn(n_limit, |_| Rad(1, ~[]));
    for p in range(2, rad_vec.len()) {
        let Rad(n, _) = rad_vec[p];
        if n != 1 { continue }

        for np in iter::count(p, p).take_while(|&np| np < n_limit) {
            let Rad(ref mut n, ref mut facts) = rad_vec[np];
            (*n) *= p;
            facts.push(p);
        }
    }
    rad_vec
}

fn rad_has_union(&Rad(_, ref a): &Rad, &Rad(_, ref b): &Rad) -> bool {
    let mut i_a = 0;
    let mut i_b = 0;

    loop {
        if i_a >= a.len() || i_b >= b.len() { return false }
        match a[i_a].cmp(&b[i_b]) {
            Equal   => return true,
            Less    => i_a += 1,
            Greater => i_b += 1
        }
    }
}

fn abc_hits_c_sum(c_limit: uint) -> uint {
    let rad_vec = create_rad_vec(c_limit);
    let mut c_sum = 0;

    for c in range(3, c_limit) {
        let Rad(rad_c, _) = rad_vec[c];
        if rad_c == c { continue } // if rad(c) == c, rad(ab) must be 1. this doesn't satisfy condition 2.

        // if a == 1, GCD(a, b) == GCD(b, c) == GCD(c, a) == 1 is always satisfied.
        {
            let Rad(rad_b, _) = rad_vec[c - 1];
            if rad_b * rad_c < c { c_sum += c; }
        }

        // if c is even, a and b must be odd
        if c.is_even() {
            for a in iter::range_step(3, (c + 1) / 2, 2) {
                let b = c - a;
                let Rad(rad_a, _) = rad_vec[a];
                let Rad(rad_b, _) = rad_vec[b];
                let rad_abc = rad_a * rad_b * rad_c;
                if rad_abc >= c || rad_has_union(&rad_vec[a], &rad_vec[c]) { continue; }
                c_sum += c;
            }
        } else {
            for a in range(2, (c + 1) / 2) {
                let b = c - a;
                let Rad(rad_a, _) = rad_vec[a];
                let Rad(rad_b, _) = rad_vec[b];
                let rad_abc = rad_a * rad_b * rad_c;
                if rad_abc >= c || rad_has_union(&rad_vec[a], &rad_vec[c]) { continue; }
                c_sum += c;
            }
        }
    }

    c_sum
}

pub fn solve() -> ~str { abc_hits_c_sum(120000).to_str() }

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

    #[test]
    fn create_rad_vec() {
        let rad_vec = ~[
            Rad(1, ~[]), Rad(1, ~[]), Rad(2, ~[2]), Rad(3, ~[3]), Rad(2, ~[2]), Rad(5, ~[5]),
            Rad(6, ~[2, 3]), Rad(7, ~[7]), Rad(2, ~[2]), Rad(3, ~[3])];
        assert_eq!(rad_vec, super::create_rad_vec(10))
    }

    #[test]
    fn rad_has_union() {
        assert!(super::rad_has_union(&Rad(2, ~[2]), &Rad(2, ~[2])));
        assert!(!super::rad_has_union(&Rad(2, ~[2]), &Rad(3, ~[4])));

        assert!(super::rad_has_union(&Rad(3, ~[3]), &Rad(6, ~[2, 3])));
        assert!(super::rad_has_union(&Rad(15, ~[3, 5]), &Rad(10, ~[2, 5])));

        assert!(!super::rad_has_union(&Rad(30, ~[2, 3, 5]), &Rad(1001, ~[7, 11, 13])));
    }

    #[test]
    fn abc_hits_c_sum() {
        assert_eq!(12523, super::abc_hits_c_sum(1000));
    }
}
<|endoftext|>


<commit_before>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.

use std::{
    env, fs,
    path::{Path, PathBuf},
    process::Command,
};

use cargo_metadata::Message;

fn main() {
    println!("cargo:rerun-if-changed=imp");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");

    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
    // this'll error out if the staging dir didn't previously exist. using
    // `std::fs::exists` would suffer from TOCTOU so just do our best to
    // wipe it and ignore errors.
    let _ = std::fs::remove_dir_all(&staging_dir);

    println!("Creating {}", staging_dir.display());
    std::fs::create_dir_all(&staging_dir).unwrap();

    let src_dir = staging_dir.join("src");
    println!("Creating {}", src_dir.display());
    std::fs::create_dir_all(src_dir).unwrap();

    for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        println!("Copying {} to {}", src.display(), dst.display());
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");
    let output = Command::new(toolchain::cargo())
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<commit_msg>Auto merge of #12834 - fasterthanlime:proc-macro-test-toolchain, r=Veykril<commit_after>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.
//!
//! The `PROC_MACRO_TEST_TOOLCHAIN` environment variable can be exported to use
//! a specific rustup toolchain: this allows testing against older ABIs (e.g.
//! 1.58) and future ABIs (stage1, nightly)

use std::{
    env, fs,
    path::{Path, PathBuf},
    process::Command,
};

use cargo_metadata::Message;

fn main() {
    println!("cargo:rerun-if-changed=imp");
    println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");

    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
    // this'll error out if the staging dir didn't previously exist. using
    // `std::fs::exists` would suffer from TOCTOU so just do our best to
    // wipe it and ignore errors.
    let _ = std::fs::remove_dir_all(&staging_dir);

    println!("Creating {}", staging_dir.display());
    std::fs::create_dir_all(&staging_dir).unwrap();

    let src_dir = staging_dir.join("src");
    println!("Creating {}", src_dir.display());
    std::fs::create_dir_all(src_dir).unwrap();

    for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        println!("Copying {} to {}", src.display(), dst.display());
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");

    let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
        // leverage rustup to find user-specific toolchain
        let mut cmd = Command::new("cargo");
        cmd.arg(format!("+{toolchain}"));
        cmd
    } else {
        Command::new(toolchain::cargo())
    };

    let output = cmd
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<|endoftext|>


<commit_before>use super::behaviors::{MouseBehavior, SelectionBehavior};
use crate::prelude::*;

widget!(
    /// The `CheckBox` widget can be switch its selected state. It contains a selection box and a text.
    ///
    /// **CSS element:** `check-box`
    CheckBox: MouseHandler,
    ChangedHandler {
	/// Sets or shares the background property.
	background: Brush,

	/// Sets or shares the border radius property.
	border_radius: f64,

	/// Sets or shares the border thickness property.
	border_width: Thickness,

	/// Sets or shares the border brush property.
	border_brush: Brush,

	/// Sets or shares the padding property.
	padding: Thickness,

	/// Sets or shares the foreground property.
	foreground: Brush,

	/// Sets or shares the text property.
	text: String16,

	/// Sets or share the font size property.
	font_size: f64,

	/// Sets or shares the font property.
	font: String,

	/// Sets or shares the icon property.
	icon: String,

	/// Sets or shares the icon brush property.
	icon_brush: Brush,

	/// Sets or share the icon font size property.
	icon_size: f64,

	/// Sets or shares the icon font property.
	icon_font: String,

	/// Sets or shares the pressed property.
	pressed: bool,

	/// Sets or shares the selected property.
	selected: bool
    }
);

impl Template for CheckBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
	self.name("CheckBox")
	    .element("check-box")
	    .selected(false)
	    .height(24.0)
	    .background(colors::LYNCH_COLOR)
	    .border_radius(2.0)
	    .border_width(0.0)
	    .border_brush("transparent")
	    .padding((8.0, 0.0, 8.0, 0.0))
	    .foreground(colors::LINK_WATER_COLOR)
	    .text("")
	    .font_size(fonts::FONT_SIZE_12)
	    .font("Roboto Regular")
	    .icon(material_icons_font_ttf::CHECK_FONT_ICON)
	    .icon_font("Material Icons")
	    .icon_size(fonts::ICON_FONT_SIZE_12)
	    .icon_brush(colors::LINK_WATER_COLOR)
	    .pressed(false)
	    .child(
		MouseBehavior::new()
		    .pressed(id)
		    .enabled(id)
		    .target(id.0)
		    .child(
			SelectionBehavior::new()
			    .selected(id)
			    .enabled(id)
			    .target(id.0)
			    .child(
				Stack::new()
				    .orientation("horizontal")
				    .spacing(8.0)
				    .child(
					Container::new()
					    .size(24.0, 24.0)
					    .background(id)
					    .border_radius(id)
					    .border_width(id)
					    .border_brush(id)
					    .padding(id)
					    .opacity(id)
					    .child(
						FontIconBlock::new()
						    .v_align("center")
						    .h_align("center")
						    .icon(id)
						    .icon_brush(id)
						    .icon_size(id)
						    .icon_font(id)
						    .opacity(id)
						    .build(ctx),
					    )
					    .build(ctx),
				    )
				    .child(
					TextBlock::new()
					    .v_align("center")
					    .foreground(id)
					    .text(id)
					    .font_size(id)
					    .font(id)
					    .opacity(id)
					    .build(ctx),
				    )
				    .build(ctx),
			    )
			    .build(ctx),
		    )
		    .build(ctx),
	    )
    }
}
<commit_msg>widgets: checkbox.rs update<commit_after>use super::behaviors::{MouseBehavior, SelectionBehavior};
use crate::prelude::*;

widget!(
    /// The `CheckBox` widget can be switch its selected state. It contains a selection box and a text.
    ///
    /// **CSS element:** `check-box`
    CheckBox: MouseHandler,
    ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the text property.
        text: String16,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the icon property.
        icon: String,

        /// Sets or shares the icon brush property.
        icon_brush: Brush,

        /// Sets or share the icon font size property.
        icon_size: f64,

        /// Sets or shares the icon font property.
        icon_font: String,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl Template for CheckBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("CheckBox")
            .element("check-box")
            .selected(false)
            .height(24.0)
            .background(colors::LYNCH_COLOR)
            .border_radius(2.0)
            .border_width(0.0)
            .border_brush("transparent")
            .padding((8.0, 0.0, 8.0, 0.0))
            .foreground(colors::LINK_WATER_COLOR)
            .text("")
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .icon(material_icons_font_ttf::MD_CHECK)
            .icon_font("Material Icons")
            .icon_size(fonts::ICON_FONT_SIZE_12)
            .icon_brush(colors::LINK_WATER_COLOR)
            .pressed(false)
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::new()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(
                                Stack::new()
                                    .orientation("horizontal")
                                    .spacing(8.0)
                                    .child(
                                        Container::new()
                                            .size(24.0, 24.0)
                                            .background(id)
                                            .border_radius(id)
                                            .border_width(id)
                                            .border_brush(id)
                                            .padding(id)
                                            .opacity(id)
                                            .child(
                                                FontIconBlock::new()
                                                    .v_align("center")
                                                    .h_align("center")
                                                    .icon(id)
                                                    .icon_brush(id)
                                                    .icon_size(id)
                                                    .icon_font(id)
                                                    .opacity(id)
                                                    .build(ctx),
                                            )
                                            .build(ctx),
                                    )
                                    .child(
                                        TextBlock::new()
                                            .v_align("center")
                                            .foreground(id)
                                            .text(id)
                                            .font_size(id)
                                            .font(id)
                                            .opacity(id)
                                            .build(ctx),
                                    )
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<|endoftext|>


<commit_before>//! Primitives for non-blocking SSDP message receiving.

use std::io;
use std::result::Result;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError, RecvError, Iter};
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{UdpSocket, SocketAddr};
use std::time::Duration;

use SSDPResult;
use net::packet::PacketReceiver;

/// Trait for constructing an object from some serialized SSDP message.
pub trait FromRawSSDP: Sized {
    fn raw_ssdp(bytes: &[u8]) -> SSDPResult<Self>;
}

/// Iterator for an `SSDPReceiver`.
pub struct SSDPIter<T> {
    recv: SSDPReceiver<T>,
}

impl<T> SSDPIter<T> {
    fn new(recv: SSDPReceiver<T>) -> SSDPIter<T> {
        SSDPIter { recv: recv }
    }
}

impl<T> Iterator for SSDPIter<T> {
    type Item = (T, SocketAddr);

    fn next(&mut self) -> Option<Self::Item> {
        self.recv.recv().ok()
    }
}

/// A non-blocking SSDP message receiver.
pub struct SSDPReceiver<T> {
    recvr: Receiver<(T, SocketAddr)>,
    socks: Vec<UdpSocket>,
    addrs: Vec<SocketAddr>,
    kill: Arc<AtomicBool>,
}

impl<T> SSDPReceiver<T>
    where T: FromRawSSDP + Send + 'static
{
    /// Construct a receiver that receives bytes from a number of UdpSockets and
    /// tries to construct an object T from them. If a duration is provided, the
    /// channel will be shutdown after the specified duration.
    ///
    /// Due to implementation details, none of the UdpSockets should be bound to
    /// the default route, 0.0.0.0, address.
    pub fn new(socks: Vec<UdpSocket>, time: Option<Duration>) -> io::Result<SSDPReceiver<T>> {
        let (send, recv) = mpsc::channel();

        let mut send_socks = try!(clone_socks(&socks[..]));
        let recv_addrs = try!(clone_addrs(&socks[..]));

        let self_kill = Arc::new(AtomicBool::new(false));

        // Ensure `receive_packets` times out in the event the timeout packet is not received
        for sock in &mut send_socks {
            try!(sock.set_read_timeout(time));
        }

        // Spawn Receiver Threads
        spawn_receivers(send_socks, self_kill.clone(), send);

        // Spawn Single Kill Timer
        let spawn_result = maybe_spawn_timer(time, self_kill.clone(), &socks[..]);

        // If Timer Failed To Spawn, Kill Our Receivers
        if let Err(e) = spawn_result {
            syncronize_kill(&*self_kill, &socks[..], &recv_addrs[..]);

            return Err(e);
        }

        Ok(SSDPReceiver {
            recvr: recv,
            socks: socks,
            addrs: recv_addrs,
            kill: self_kill,
        })
    }
}

/// Attempt to clone all `UdpSocket`'s into a new vector.
fn clone_socks(socks: &[UdpSocket]) -> io::Result<Vec<UdpSocket>> {
    let mut clone_socks = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_socks.push(try!(sock.try_clone()));
    }

    Ok(clone_socks)
}

/// Attempt to copy all `SocketAddr`'s from the `UdpSocket`'s into a new vector.
fn clone_addrs(socks: &[UdpSocket]) -> io::Result<Vec<SocketAddr>> {
    let mut clone_addrs = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_addrs.push(try!(sock.local_addr()));
    }

    Ok(clone_addrs)
}

/// Spawn a number of receiver threads that will receive packets, forward the
/// bytes on to T, and send successfully constructed objects through the sender.
fn spawn_receivers<T>(socks: Vec<UdpSocket>, kill_flag: Arc<AtomicBool>, sender: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send + 'static
{
    for sock in socks {
        let pckt_recv = PacketReceiver::new(sock);
        let kill_flag = kill_flag.clone();
        let sender = sender.clone();

        thread::spawn(move || {
            receive_packets(pckt_recv, kill_flag, sender);
        });
    }
}

/// Spawn a timer if a duration was passed in and link the timer with the given sockets.
///
/// If some of the sockets or socket addresses could not be cloned, an error is returned.
fn maybe_spawn_timer(time: Option<Duration>, kill: Arc<AtomicBool>, socks: &[UdpSocket]) -> io::Result<()> {
    if let Some(n) = time {
        let timer_socks = try!(clone_socks(socks));
        let timer_addrs = try!(clone_addrs(socks));

        thread::spawn(move || {
            kill_timer(n, kill, timer_socks, timer_addrs);
        });
    };

    Ok(())
}

impl<T> SSDPReceiver<T> {
    /// Non-blocking method that attempts to read a value from the receiver.
    pub fn try_recv(&self) -> Result<(T, SocketAddr), TryRecvError> {
        self.recvr.try_recv()
    }

    /// Blocking method that reads a value from the receiver until one is available.
    pub fn recv(&self) -> Result<(T, SocketAddr), RecvError> {
        self.recvr.recv()
    }
}

impl<'a, T> IntoIterator for &'a SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<T> IntoIterator for SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = SSDPIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        SSDPIter::new(self)
    }
}

impl<T> Drop for SSDPReceiver<T> {
    fn drop(&mut self) {
        syncronize_kill(&*self.kill, &self.socks[..], &self.addrs[..]);
    }
}

/// Receives bytes and attempts to construct a T which will be sent through the
/// supplied channel.
///
/// This should almost always be run in it's own thread.
fn receive_packets<T>(recv: PacketReceiver, kill: Arc<AtomicBool>, send: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send
{
    // TODO: Add logging to this function. Maybe forward sender IP Address along
    // so that we can do some checks when we parse the http.
    loop {
        trace!("Waiting on packet at {}...", recv);
        let (msg_bytes, addr) = match recv.recv_pckt() {
            Ok((bytes, addr)) => (bytes, addr),
            // Unix returns WouldBlock on timeout while Windows returns TimedOut
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock ||
                            err.kind() == io::ErrorKind::TimedOut => {
                // We have waited for at least the desired timeout (or possibly longer)
                trace!("Receiver at {} timed out", recv);
                return;
            },
            Err(_) => {
                continue;
            }
        };

        trace!("Received packet with {} bytes", msg_bytes.len());

        // Check If We Were Unblocked Intentionally
        if kill.load(Ordering::Acquire) {
            // With acquire, there is a chance that the code below could
            // be moved up and our unblock message could be processed. This
            // should not affect execution but keep in mind for logging
            // purposes.
            trace!("Receiver at {} timed out", recv);
            return;
        }

        // Unwrap Will Cause A Panic If Receiver Hung Up Which Is Desired
        match T::raw_ssdp(&msg_bytes[..]) {
            Ok(n) => send.send((n, addr)).unwrap(),
            Err(_) => {
                continue;
            }
        };
    }
}

/// Sleeps the current thread for the specified duration, after which, it will activate
/// the kill flag and send a message on all `UdpSocket`'s to unblock whatever threads are
/// blocking on them so that they can see that the kill flag has been activated.
///
/// This should be run in it's own thread.
fn kill_timer(time: Duration, kill: Arc<AtomicBool>, socks: Vec<UdpSocket>, addrs: Vec<SocketAddr>) {
    thread::sleep(time);

    syncronize_kill(&*kill, &socks[..], &addrs[..]);
}

#[allow(unused)]
/// Sets the kill flag and sends a one byte message through the `UdpSocket`'s,
/// making sure that the operations are sequentially consistent (not re-ordered).
fn syncronize_kill(kill: &AtomicBool, socks: &[UdpSocket], local_addrs: &[SocketAddr]) {
    kill.store(true, Ordering::SeqCst);

    for (sock, addr) in socks.iter().zip(local_addrs.iter()) {
        sock.send_to(&[0], addr);
    }
}
<commit_msg>Remove Kill Code For SSDPReceiver To Rely On Read Timeouts Instead<commit_after>//! Primitives for non-blocking SSDP message receiving.

use std::io;
use std::result::Result;
use std::thread;
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError, RecvError, Iter};
use std::net::{UdpSocket, SocketAddr};
use std::time::Duration;

use SSDPResult;
use net::packet::PacketReceiver;

/// Trait for constructing an object from some serialized SSDP message.
pub trait FromRawSSDP: Sized {
    fn raw_ssdp(bytes: &[u8]) -> SSDPResult<Self>;
}

/// Iterator for an `SSDPReceiver`.
pub struct SSDPIter<T> {
    recv: SSDPReceiver<T>,
}

impl<T> SSDPIter<T> {
    fn new(recv: SSDPReceiver<T>) -> SSDPIter<T> {
        SSDPIter { recv: recv }
    }
}

impl<T> Iterator for SSDPIter<T> {
    type Item = (T, SocketAddr);

    fn next(&mut self) -> Option<Self::Item> {
        self.recv.recv().ok()
    }
}

/// A non-blocking SSDP message receiver.
pub struct SSDPReceiver<T> {
    recvr: Receiver<(T, SocketAddr)>
}

impl<T> SSDPReceiver<T>
    where T: FromRawSSDP + Send + 'static
{
    /// Construct a receiver that receives bytes from a number of UdpSockets and
    /// tries to construct an object T from them. If a duration is provided, the
    /// channel will be shutdown after the specified duration.
    ///
    /// Due to implementation details, none of the UdpSockets should be bound to
    /// the default route, 0.0.0.0, address.
    pub fn new(socks: Vec<UdpSocket>, time: Option<Duration>) -> io::Result<SSDPReceiver<T>> {
        let (send, recv) = mpsc::channel();

        // Ensure `receive_packets` times out in the event the timeout packet is not received
        for sock in socks.iter() {
            try!(sock.set_read_timeout(time));
        }

        // Spawn Receiver Threads
        spawn_receivers(socks, send);

        Ok(SSDPReceiver {
            recvr: recv
        })
    }
}

/// Spawn a number of receiver threads that will receive packets, forward the
/// bytes on to T, and send successfully constructed objects through the sender.
fn spawn_receivers<T>(socks: Vec<UdpSocket>, sender: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send + 'static
{
    for sock in socks {
        let pckt_recv = PacketReceiver::new(sock);
        let sender = sender.clone();

        thread::spawn(move || {
            receive_packets(pckt_recv, sender);
        });
    }
}

impl<T> SSDPReceiver<T> {
    /// Non-blocking method that attempts to read a value from the receiver.
    pub fn try_recv(&self) -> Result<(T, SocketAddr), TryRecvError> {
        self.recvr.try_recv()
    }

    /// Blocking method that reads a value from the receiver until one is available.
    pub fn recv(&self) -> Result<(T, SocketAddr), RecvError> {
        self.recvr.recv()
    }
}

impl<'a, T> IntoIterator for &'a SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<T> IntoIterator for SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = SSDPIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        SSDPIter::new(self)
    }
}

/// Receives bytes and attempts to construct a T which will be sent through the supplied channel.
///
/// This should almost always be run in it's own thread.
fn receive_packets<T>(recv: PacketReceiver, send: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send
{
    // TODO: Add logging to this function. Maybe forward sender IP Address along
    // so that we can do some checks when we parse the http.
    loop {
        trace!("Waiting on packet at {}...", recv);
        let (msg_bytes, addr) = match recv.recv_pckt() {
            Ok((bytes, addr)) => (bytes, addr),
            // Unix returns WouldBlock on timeout while Windows returns TimedOut
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock ||
                            err.kind() == io::ErrorKind::TimedOut => {
                // We have waited for at least the desired timeout (or possibly longer)
                trace!("Receiver at {} timed out", recv);
                return;
            },
            Err(_) => {
                continue;
            }
        };

        trace!("Received packet with {} bytes", msg_bytes.len());

        // Unwrap Will Cause A Panic If Receiver Hung Up Which Is Desired
        match T::raw_ssdp(&msg_bytes[..]) {
            Ok(n) => send.send((n, addr)).unwrap(),
            Err(_) => {
                continue;
            }
        };
    }
}<|endoftext|>


<commit_before>// FIXME: add the support of transient objects

use any_cache::{self, Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use model::Model;
use object::Object;
use shader::Program;
use spline::Spline;
use texture::TextureImage;

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = T;

  fn deref(&self) -> &Self::Target {
    &self.0.borrow()
  }
}

impl<T> DerefMut for Res<T> {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.0.borrow_mut()
  }
}

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 1.; // 1s

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>>,
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_timestamp: Timestamp // timestamp of the last update
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), precise_time_s()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf) {
      Some(res) => {
        deb!("cache hit for {} ({})", key, path_str);
        Some(res.clone())
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args) {
            Ok(resource) => {
              let res = Res(Rc::new(RefCell::new(resource)));
              let res_ = res.clone();

              let path_buf_ = path_buf.clone();
              let args_ = args.clone();
              // closure used to reload the object when needed
              let on_reload = Box::new(move |cache_| {
                match T::load(&path_buf_, cache_, args_) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    *res_ = new_resource;
                    deb!("reloaded resource from {:?}", path_buf_);
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
                  }
                }
              });

              let metadata = ResMetaData {
                on_reload: on_reload,
                last_update_timestamp: precise_time_s()
              };

              // cache the resource and its meta data
              self.cache.save(path_buf.clone(), res);
              self.metadata.insert(path_buf, metadata);

              Some(res)
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

  // TODO: maybe we should have a ResCache::update() instead of get() + save()?
  ///// Synchronize the cache by updating the resource that ought to.
  //pub fn sync(&mut self) {
  //  let mut dirty = self.dirty.lock().unwrap();

  //  for &(ref path, ref timestamp) in dirty.iter() {
  //    let mut cache_entry = self.cache.get::<ResCacheEntry>(&path).cloned().unwrap();

  //    if timestamp - cache_entry.last_update_timestamp >= UPDATE_AWAIT_TIME {
  //      cache_entry.on_reload();
  //    }

  //    cache_entry.last_update_timestamp = timestamp;
  //    self.cache.save(path.clone(), cache_entry);
  //  }

  //  dirty.clear();
  //}
}
<commit_msg>We’re getting there!<commit_after>// FIXME: add the support of transient objects

use any_cache::{self, Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use model::Model;
use object::Object;
use shader::Program;
use spline::Spline;
use texture::TextureImage;

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = T;

  fn deref(&self) -> &Self::Target {
    &self.0.borrow()
  }
}

impl<T> DerefMut for Res<T> {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.0.borrow_mut()
  }
}

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 1.; // 1s

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>>,
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_timestamp: Timestamp // timestamp of the last update
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), precise_time_s()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf).cloned() {
      r@Some(..) => {
        deb!("cache hit for {} ({})", key, path_str);
        r
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args.clone()) {
            Ok(resource) => {
              let res = Res(Rc::new(RefCell::new(resource)));
              let res_ = res.clone();

              let path_buf_ = path_buf.clone();
              // closure used to reload the object when needed
              let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
                match T::load(&path_buf_, cache_, args.clone()) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    *res_ = new_resource;
                    deb!("reloaded resource from {:?}", path_buf_);
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
                  }
                }
              });

              let metadata = ResMetaData {
                on_reload: on_reload,
                last_update_timestamp: precise_time_s()
              };

              // cache the resource and its meta data
              self.cache.save(path_buf.clone(), res.clone());
              self.metadata.insert(path_buf, metadata);

              Some(res)
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

  // TODO: maybe we should have a ResCache::update() instead of get() + save()?
  ///// Synchronize the cache by updating the resource that ought to.
  //pub fn sync(&mut self) {
  //  let mut dirty = self.dirty.lock().unwrap();

  //  for &(ref path, ref timestamp) in dirty.iter() {
  //    let mut cache_entry = self.cache.get::<ResCacheEntry>(&path).cloned().unwrap();

  //    if timestamp - cache_entry.last_update_timestamp >= UPDATE_AWAIT_TIME {
  //      cache_entry.on_reload();
  //    }

  //    cache_entry.last_update_timestamp = timestamp;
  //    self.cache.save(path.clone(), cache_entry);
  //  }

  //  dirty.clear();
  //}
}
<|endoftext|>


<commit_before>use hyper::header::{self, CookiePair as Cookie, ContentType, Header, SetCookie};
use hyper::status::StatusCode as Status;

use hyper::{Control, Headers, Next};

use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

use handlebars::Handlebars;
use serde::ser::Serialize as ToJson;

pub use serde_json::value as value;

use std::any::Any;
use std::fmt::Debug;
use std::borrow::Cow;
use std::io::{ErrorKind, Read, Result, Write};
use std::marker::PhantomData;

use std::fs::{File, read_dir};
use std::path::Path;

use std::boxed::Box;
use std::sync::atomic::{AtomicBool, Ordering};

use buffer::Buffer;
use deque::{self, Stealer, Worker};

pub struct Resp {
    status: Status,
    headers: Headers,
    body: Buffer,
    worker: Option<Worker<Buffer>>,
    stealer: Option<Stealer<Buffer>>,

    ctrl: Control,
    ended_or_notify: AtomicBool
}

impl Resp {
    pub fn new(ctrl: Control) -> Resp {
        Resp {
            status: Status::Ok,
            headers: Headers::default(),
            body: Buffer::new(),
            worker: None,
            stealer: None,

            ctrl: ctrl,
            ended_or_notify: AtomicBool::new(false)
        }
    }

    /// called by handler to know whether we can write the response or not
    ///
    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    fn can_write(&self) -> bool {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, response already ended, we can write it
            true
        } else {
            // if false, response did not end yet
            // ended has been set to true to mean "need to notify handler"
            false
        }
    }

    /// mirror function of can_write, called by Response
    fn done(&self) {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, means we need to notify, the flag is not updated
            self.notify();
        } else {
            // if previously false: no need to notify
            // ended has been set to true to mean "response ended"
        }
    }

    /// notify handler we have something to write
    /// called by done and append
    fn notify(&self) {
        self.ctrl.ready(Next::write()).unwrap();
    }

    fn is_streaming(&self) -> bool {
        self.worker.is_some()
    }

    fn status(&mut self, status: Status) {
        self.status = status;
    }

    fn has_header<H: Header>(&self) -> bool {
        self.headers.has::<H>()
    }

    fn header<H: Header>(&mut self, header: H) {
        self.headers.set(header);
    }

    fn header_raw<K: Into<Cow<'static, str>> + Debug>(&mut self, name: K, value: Vec<Vec<u8>>) {
        self.headers.set_raw(name, value);
    }

    fn push_cookie(&mut self, cookie: Cookie) {
        self.headers.get_mut::<SetCookie>().unwrap().push(cookie)
    }

    fn len(&self) -> usize {
        self.body.len()
    }

    fn append<D: Into<Buffer>>(&self, buffer: D) {
        self.worker.as_ref().unwrap().push(buffer.into());
        self.notify();
    }

    fn send<D: Into<Vec<u8>>>(&mut self, content: D) {
        self.body.send(content);
    }

    fn init_deque(&mut self) {
        let (worker, stealer) = deque::new();
        self.worker = Some(worker);
        self.stealer = Some(stealer);
    }
}

/// This holds data for the response.
pub struct ResponseHolder {
    resp: Box<Resp>
}

impl ResponseHolder {

    pub fn new(control: Control) -> ResponseHolder {
        ResponseHolder {
            resp: Box::new(Resp::new(control))
        }
    }

    pub fn new_response(&mut self) -> Response {
        Response {
            resp: RespPtr(&mut *self.resp),
            streaming: false,
            _marker: PhantomData
        }
    }

    pub fn get_status(&self) -> Status {
        self.resp.status
    }

    pub fn set_headers(&self, headers: &mut Headers) {
        *headers = self.resp.headers.clone();
    }

    pub fn is_streaming(&self) -> bool {
        self.resp.is_streaming()
    }

    pub fn body(&mut self) -> &mut Buffer {
        &mut self.resp.body
    }

    pub fn pop(&mut self) -> Option<Buffer> {
        match self.resp.stealer.as_ref().unwrap().steal() {
            deque::Data(buffer) => Some(buffer),
            deque::Empty => None,
            deque::Abort => panic!("abort")
        }
    }

    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    pub fn can_write(&self) -> bool {
        self.resp.can_write()
    }
}

struct RespPtr(*mut Resp);

/// This represents the response that will be sent back to the application.
///
/// Includes a status code (default 200 OK), headers, and a body.
/// The response can be updated and sent back immediately in a synchronous way,
/// or deferred pending some computation (asynchronous mode).
///
/// The response is sent when it is dropped.
pub struct Response<W: Any = Fresh> {
    resp: RespPtr,
    streaming: bool,
    _marker: PhantomData<W>
}

// no worries, the response is always modified by only one thread at a time
unsafe impl Send for RespPtr {}

impl Drop for ResponseHolder {
    fn drop(&mut self) {
        debug!("drop response holder");
    }
}

impl<T: Any> Drop for Response<T> {
    fn drop(&mut self) {
        debug!("drop response (streaming? {})", self.streaming);
        if self.streaming {
            // append an empty buffer to indicate there is no more data left, and notify handler
            self.resp().append(vec![]);
        } else {
            self.resp().done();
        }
    }
}

impl Drop for Resp {
    fn drop(&mut self) {
        debug!("drop resp");
    }
}

pub enum Fresh {}
pub enum Streaming {}

impl<W: Any> Response<W> {
    fn resp(&self) -> &Resp {
        unsafe {
            &*self.resp.0
        }
    }

    fn resp_mut(&self) -> &mut Resp {
        unsafe {
            &mut *self.resp.0
        }
    }
}

impl Response<Fresh> {
    /// Sets the status code of this response.
    pub fn status(&mut self, status: Status) -> &mut Self {
        self.resp_mut().status(status);
        self
    }

    /// Sets the Content-Type header.
    pub fn content_type<S: Into<Vec<u8>>>(&mut self, mime: S) -> &mut Self {
        self.header_raw("Content-Type", mime)
    }

    /// Sets the Content-Length header.
    pub fn len(&mut self, len: u64) -> &mut Self {
        self.header(header::ContentLength(len))
    }

    /// Sets the given cookie.
    pub fn cookie(&mut self, cookie: Cookie) {
        let has_cookie_header = self.resp().has_header::<SetCookie>();
        if has_cookie_header {
            self.resp_mut().push_cookie(cookie)
        } else {
            self.resp_mut().header(SetCookie(vec![cookie]))
        }
    }

    /// Sets the given header.
    pub fn header<H: Header>(&mut self, header: H) -> &mut Self {
        self.resp_mut().header(header);
        self
    }

    /// Sets the given header with raw strings.
    pub fn header_raw<K: Into<Cow<'static, str>> + Debug, V: Into<Vec<u8>>>(&mut self, name: K, value: V) -> &mut Self {
        self.resp_mut().header_raw(name, vec![value.into()]);
        self
    }

    /// Sets the Location header.
    pub fn location<S: Into<String>>(&mut self, url: S) -> &mut Self {
        self.header(header::Location(url.into()))
    }

    /// Redirects to the given URL with the given status, or 302 Found if none is given.
    pub fn redirect(mut self, url: &str, status: Option<Status>) {
        self.location(url);
        self.end(status.unwrap_or(Status::Found))
    }

    /// Ends this response with the given status and an empty body
    pub fn end(mut self, status: Status) {
        self.status(status);
        self.len(0);
    }

    /// Renders the template at the given path using the given data.
    ///
    /// If no Content-Type header is set, the content type is set to `text/html`.
    pub fn render<P: AsRef<Path>, T: ToJson>(self, path: P, data: T) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            self.resp_mut().header(ContentType::html());
        }

        let mut handlebars = Handlebars::new();
        let path = path.as_ref();
        let name = path.file_stem().unwrap().to_str().unwrap();

        handlebars.register_template_file(name, path).unwrap();
        // ignore errors if partials folder does not exist
        let _ = register_partials(&mut handlebars);
        let result = handlebars.render(name, &data);
        self.send(result.unwrap())
    }

    /// Sends the given content and ends this response.
    ///
    /// Status defaults to 200 Ok, headers must have been set before this method is called.
    pub fn send<D: Into<Vec<u8>>>(mut self, content: D) {
        self.resp_mut().send(content);
        let length = self.resp().len();
        self.len(length as u64);
    }

    /// Sends the given file, setting the Content-Type based on the file's extension.
    ///
    /// Known extensions are htm, html, jpg, jpeg, png, js, css.
    /// If the file does not exist, this method sends a 404 Not Found response.
    pub fn send_file<P: AsRef<Path>>(mut self, path: P) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            let extension = path.as_ref().extension();
            if let Some(ext) = extension {
                let content_type = match ext.to_string_lossy().as_ref() {
                    "htm" | "html" => Some(ContentType::html()),
                    "jpg" | "jpeg" => Some(ContentType::jpeg()),
                    "png" => Some(ContentType::png()),
                    "js" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Javascript, vec![(Attr::Charset, Value::Utf8)]))),
                    "css" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![(Attr::Charset, Value::Utf8)]))),
                    _ => None
                };

                if let Some(content_type) = content_type {
                    self.resp_mut().header(content_type);
                }
            }
        }

        // read the whole file at once and send it
        // probably not the best idea for big files, we should use stream instead in that case
        match File::open(path) {
            Ok(mut file) => {
                let mut buf = Vec::with_capacity(file.metadata().ok().map_or(1024, |meta| meta.len() as usize));
                if let Err(err) = file.read_to_end(&mut buf) {
                    self.status(Status::InternalServerError).content_type("text/plain");
                    self.send(format!("{}", err))
                } else {
                    self.send(buf)
                }
            },
            Err(ref err) if err.kind() == ErrorKind::NotFound => self.end(Status::NotFound),
            Err(ref err) => {
                self.status(Status::InternalServerError).content_type("text/plain");
                self.send(format!("{}", err))
            }
        }
    }

    /// Moves to streaming mode.
    ///
    /// If no Content-Length is set, use Transfer-Encoding: chunked
    pub fn stream(self) -> Response<Streaming> {
        self.resp_mut().init_deque();
        Response {
            resp: RespPtr(self.resp.0),
            streaming: true,
            _marker: PhantomData
        }
    }
}

impl Response<Streaming> {
    /// Appends the given content to this response's body.
    pub fn append<D: Into<Vec<u8>>>(&mut self, content: D) {
        let vec = content.into();
        debug!("append {} bytes", vec.len());
        self.resp().append(vec);
    }
}

fn register_partials(handlebars: &mut Handlebars) -> Result<()> {
    for it in try!(read_dir("views/partials")) {
        let entry = try!(it);
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == "hbs" {
            let name = path.file_stem().unwrap().to_str().unwrap();
            handlebars.register_template_file(name, path.as_path()).unwrap();
        }
    }
    Ok(())
}
<commit_msg>added more known extensions<commit_after>use hyper::header::{self, CookiePair as Cookie, ContentType, Header, SetCookie};
use hyper::status::StatusCode as Status;

use hyper::{Control, Headers, Next};

use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

use handlebars::Handlebars;
use serde::ser::Serialize as ToJson;

pub use serde_json::value as value;

use std::any::Any;
use std::fmt::Debug;
use std::borrow::Cow;
use std::io::{ErrorKind, Read, Result, Write};
use std::marker::PhantomData;

use std::fs::{File, read_dir};
use std::path::Path;

use std::boxed::Box;
use std::sync::atomic::{AtomicBool, Ordering};

use buffer::Buffer;
use deque::{self, Stealer, Worker};

pub struct Resp {
    status: Status,
    headers: Headers,
    body: Buffer,
    worker: Option<Worker<Buffer>>,
    stealer: Option<Stealer<Buffer>>,

    ctrl: Control,
    ended_or_notify: AtomicBool
}

impl Resp {
    pub fn new(ctrl: Control) -> Resp {
        Resp {
            status: Status::Ok,
            headers: Headers::default(),
            body: Buffer::new(),
            worker: None,
            stealer: None,

            ctrl: ctrl,
            ended_or_notify: AtomicBool::new(false)
        }
    }

    /// called by handler to know whether we can write the response or not
    ///
    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    fn can_write(&self) -> bool {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, response already ended, we can write it
            true
        } else {
            // if false, response did not end yet
            // ended has been set to true to mean "need to notify handler"
            false
        }
    }

    /// mirror function of can_write, called by Response
    fn done(&self) {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, means we need to notify, the flag is not updated
            self.notify();
        } else {
            // if previously false: no need to notify
            // ended has been set to true to mean "response ended"
        }
    }

    /// notify handler we have something to write
    /// called by done and append
    fn notify(&self) {
        self.ctrl.ready(Next::write()).unwrap();
    }

    fn is_streaming(&self) -> bool {
        self.worker.is_some()
    }

    fn status(&mut self, status: Status) {
        self.status = status;
    }

    fn has_header<H: Header>(&self) -> bool {
        self.headers.has::<H>()
    }

    fn header<H: Header>(&mut self, header: H) {
        self.headers.set(header);
    }

    fn header_raw<K: Into<Cow<'static, str>> + Debug>(&mut self, name: K, value: Vec<Vec<u8>>) {
        self.headers.set_raw(name, value);
    }

    fn push_cookie(&mut self, cookie: Cookie) {
        self.headers.get_mut::<SetCookie>().unwrap().push(cookie)
    }

    fn len(&self) -> usize {
        self.body.len()
    }

    fn append<D: Into<Buffer>>(&self, buffer: D) {
        self.worker.as_ref().unwrap().push(buffer.into());
        self.notify();
    }

    fn send<D: Into<Vec<u8>>>(&mut self, content: D) {
        self.body.send(content);
    }

    fn init_deque(&mut self) {
        let (worker, stealer) = deque::new();
        self.worker = Some(worker);
        self.stealer = Some(stealer);
    }
}

/// This holds data for the response.
pub struct ResponseHolder {
    resp: Box<Resp>
}

impl ResponseHolder {

    pub fn new(control: Control) -> ResponseHolder {
        ResponseHolder {
            resp: Box::new(Resp::new(control))
        }
    }

    pub fn new_response(&mut self) -> Response {
        Response {
            resp: RespPtr(&mut *self.resp),
            streaming: false,
            _marker: PhantomData
        }
    }

    pub fn get_status(&self) -> Status {
        self.resp.status
    }

    pub fn set_headers(&self, headers: &mut Headers) {
        *headers = self.resp.headers.clone();
    }

    pub fn is_streaming(&self) -> bool {
        self.resp.is_streaming()
    }

    pub fn body(&mut self) -> &mut Buffer {
        &mut self.resp.body
    }

    pub fn pop(&mut self) -> Option<Buffer> {
        match self.resp.stealer.as_ref().unwrap().steal() {
            deque::Data(buffer) => Some(buffer),
            deque::Empty => None,
            deque::Abort => panic!("abort")
        }
    }

    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    pub fn can_write(&self) -> bool {
        self.resp.can_write()
    }
}

struct RespPtr(*mut Resp);

/// This represents the response that will be sent back to the application.
///
/// Includes a status code (default 200 OK), headers, and a body.
/// The response can be updated and sent back immediately in a synchronous way,
/// or deferred pending some computation (asynchronous mode).
///
/// The response is sent when it is dropped.
pub struct Response<W: Any = Fresh> {
    resp: RespPtr,
    streaming: bool,
    _marker: PhantomData<W>
}

// no worries, the response is always modified by only one thread at a time
unsafe impl Send for RespPtr {}

impl Drop for ResponseHolder {
    fn drop(&mut self) {
        debug!("drop response holder");
    }
}

impl<T: Any> Drop for Response<T> {
    fn drop(&mut self) {
        debug!("drop response (streaming? {})", self.streaming);
        if self.streaming {
            // append an empty buffer to indicate there is no more data left, and notify handler
            self.resp().append(vec![]);
        } else {
            self.resp().done();
        }
    }
}

impl Drop for Resp {
    fn drop(&mut self) {
        debug!("drop resp");
    }
}

pub enum Fresh {}
pub enum Streaming {}

impl<W: Any> Response<W> {
    fn resp(&self) -> &Resp {
        unsafe {
            &*self.resp.0
        }
    }

    fn resp_mut(&self) -> &mut Resp {
        unsafe {
            &mut *self.resp.0
        }
    }
}

impl Response<Fresh> {
    /// Sets the status code of this response.
    pub fn status(&mut self, status: Status) -> &mut Self {
        self.resp_mut().status(status);
        self
    }

    /// Sets the Content-Type header.
    pub fn content_type<S: Into<Vec<u8>>>(&mut self, mime: S) -> &mut Self {
        self.header_raw("Content-Type", mime)
    }

    /// Sets the Content-Length header.
    pub fn len(&mut self, len: u64) -> &mut Self {
        self.header(header::ContentLength(len))
    }

    /// Sets the given cookie.
    pub fn cookie(&mut self, cookie: Cookie) {
        let has_cookie_header = self.resp().has_header::<SetCookie>();
        if has_cookie_header {
            self.resp_mut().push_cookie(cookie)
        } else {
            self.resp_mut().header(SetCookie(vec![cookie]))
        }
    }

    /// Sets the given header.
    pub fn header<H: Header>(&mut self, header: H) -> &mut Self {
        self.resp_mut().header(header);
        self
    }

    /// Sets the given header with raw strings.
    pub fn header_raw<K: Into<Cow<'static, str>> + Debug, V: Into<Vec<u8>>>(&mut self, name: K, value: V) -> &mut Self {
        self.resp_mut().header_raw(name, vec![value.into()]);
        self
    }

    /// Sets the Location header.
    pub fn location<S: Into<String>>(&mut self, url: S) -> &mut Self {
        self.header(header::Location(url.into()))
    }

    /// Redirects to the given URL with the given status, or 302 Found if none is given.
    pub fn redirect(mut self, url: &str, status: Option<Status>) {
        self.location(url);
        self.end(status.unwrap_or(Status::Found))
    }

    /// Ends this response with the given status and an empty body
    pub fn end(mut self, status: Status) {
        self.status(status);
        self.len(0);
    }

    /// Renders the template at the given path using the given data.
    ///
    /// If no Content-Type header is set, the content type is set to `text/html`.
    pub fn render<P: AsRef<Path>, T: ToJson>(self, path: P, data: T) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            self.resp_mut().header(ContentType::html());
        }

        let mut handlebars = Handlebars::new();
        let path = path.as_ref();
        let name = path.file_stem().unwrap().to_str().unwrap();

        handlebars.register_template_file(name, path).unwrap();
        // ignore errors if partials folder does not exist
        let _ = register_partials(&mut handlebars);
        let result = handlebars.render(name, &data);
        self.send(result.unwrap())
    }

    /// Sends the given content and ends this response.
    ///
    /// Status defaults to 200 Ok, headers must have been set before this method is called.
    pub fn send<D: Into<Vec<u8>>>(mut self, content: D) {
        self.resp_mut().send(content);
        let length = self.resp().len();
        self.len(length as u64);
    }

    /// Sends the given file, setting the Content-Type based on the file's extension.
    ///
    /// Known extensions are:
    ///   - application: js, m3u8, mpd, xml
    ///   - image: gif, jpg, jpeg, png
    ///   - text: css, htm, html, txt
    ///   - video: avi, mp4, mpg, mpeg, ts
    /// If the file does not exist, this method sends a 404 Not Found response.
    pub fn send_file<P: AsRef<Path>>(mut self, path: P) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            let extension = path.as_ref().extension();
            if let Some(ext) = extension {
                let content_type = match ext.to_string_lossy().as_ref() {
                    // application
                    "js" => Some(("application", "javascript", None)),
                    "m3u8" => Some(("application", "vnd.apple.mpegurl", None)),
                    "mpd" => Some(("application", "dash+xml", None)),
                    "xml" => Some(("application", "xml", None)),

                    // image
                    "gif" => Some(("image", "gif", None)),
                    "jpg" | "jpeg" => Some(("image", "jpeg", None)),
                    "png" => Some(("image", "png", None)),

                    // text
                    "css" => Some(("text", "css", None)),
                    "htm" | "html" => Some(("text", "html", Some((Attr::Charset, Value::Utf8)))),
                    "txt" => Some(("text", "plain", Some((Attr::Charset, Value::Utf8)))),

                    // video
                    "avi" => Some(("video", "x-msvideo", None)),
                    "mp4" => Some(("video", "mp4", None)),
                    "mpg" | "mpeg" => Some(("video", "mpeg", None)),
                    "ts" => Some(("video", "mp2t", None)),
                    _ => None
                };

                if let Some((top, sub, attr)) = content_type {
                    self.resp_mut().header(ContentType(Mime(TopLevel::Ext(top.to_string()),
                        SubLevel::Ext(sub.to_string()),
                        match attr {
                            None => vec![],
                            Some(val) => vec![val]
                        }
                    )));
                }
            }
        }

        // read the whole file at once and send it
        // probably not the best idea for big files, we should use stream instead in that case
        match File::open(path) {
            Ok(mut file) => {
                let mut buf = Vec::with_capacity(file.metadata().ok().map_or(1024, |meta| meta.len() as usize));
                if let Err(err) = file.read_to_end(&mut buf) {
                    self.status(Status::InternalServerError).content_type("text/plain");
                    self.send(format!("{}", err))
                } else {
                    self.send(buf)
                }
            },
            Err(ref err) if err.kind() == ErrorKind::NotFound => self.end(Status::NotFound),
            Err(ref err) => {
                self.status(Status::InternalServerError).content_type("text/plain");
                self.send(format!("{}", err))
            }
        }
    }

    /// Moves to streaming mode.
    ///
    /// If no Content-Length is set, use Transfer-Encoding: chunked
    pub fn stream(self) -> Response<Streaming> {
        self.resp_mut().init_deque();
        Response {
            resp: RespPtr(self.resp.0),
            streaming: true,
            _marker: PhantomData
        }
    }
}

impl Response<Streaming> {
    /// Appends the given content to this response's body.
    pub fn append<D: Into<Vec<u8>>>(&mut self, content: D) {
        let vec = content.into();
        debug!("append {} bytes", vec.len());
        self.resp().append(vec);
    }
}

fn register_partials(handlebars: &mut Handlebars) -> Result<()> {
    for it in try!(read_dir("views/partials")) {
        let entry = try!(it);
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == "hbs" {
            let name = path.file_stem().unwrap().to_str().unwrap();
            handlebars.register_template_file(name, path.as_path()).unwrap();
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::io::{stdout, Write};

pub trait ProgressBar<T> {
    fn new() -> T;
}

#[derive(Default)]
pub struct PercentageProgressBar {
    value: u8, //0..100
    msg:   String
}

impl ProgressBar<PercentageProgressBar> for PercentageProgressBar {

    fn new() -> PercentageProgressBar {
        PercentageProgressBar { ..Default::default()}
    }
}

impl PercentageProgressBar {

    pub fn render(&self) {
        print!("\r{msg}{value}%", msg=self.msg, value=self.value);
        stdout().flush().ok().expect("write to stdout failed");
    }

    pub fn set_value(&mut self, value: u8) { if value <= 100 { self.value = value } }
    pub fn get_value(&self) -> u8 { self.value }

    pub fn set_msg(&mut self, msg: &str) { self.msg = msg.to_owned() }
    pub fn get_msg(&self) -> &str { self.msg.as_ref() }

    pub fn inc(&mut self) { if self.value < 100 { self.value += 1; } }
    pub fn dec(&mut self) { if self.value > 0 { self.value -= 1; } }

}

pub struct InfiniteProgressBar {
    msg:   String,
    marker_position:  i8,
    step: i8
}

impl Default for InfiniteProgressBar {
    fn default() -> InfiniteProgressBar {
        InfiniteProgressBar {
            step: 1,
            msg: "".to_owned(),
            marker_position: 0
        }
    }
}

impl ProgressBar<InfiniteProgressBar> for InfiniteProgressBar {

    fn new() -> InfiniteProgressBar {
        InfiniteProgressBar { ..Default::default()}
    }
}

impl InfiniteProgressBar {

    pub fn set_msg(&mut self, msg: &str) { self.msg = msg.to_owned() }
    pub fn get_msg(&self) -> &str { self.msg.as_ref() }

    pub fn render(&mut self) {
        if self.marker_position <= 0 {
            self.marker_position = 0;
            self.step = 1;
        } else if self.marker_position > 9 {
            self.marker_position = 10;
            self.step = -1;
        }
        self.marker_position = self.marker_position + self.step;

        let mut bar:String = "..........".to_owned(); //10 dots
        bar.insert(self.marker_position as usize, '#');
        print!("\r{msg}[{bar}]", msg=self.msg, bar=bar);
        stdout().flush().ok().expect("write to stdout failed");
    }

}
<commit_msg>obtain terminal width<commit_after>use std::io::{stdout, Write};

use term_utils;

pub trait ProgressBar<T> {
    fn new() -> T;
}

#[derive(Default)]
pub struct PercentageProgressBar {
    value: u8, //0..100
    msg:   String
}

impl ProgressBar<PercentageProgressBar> for PercentageProgressBar {

    fn new() -> PercentageProgressBar {
        PercentageProgressBar { ..Default::default()}
    }
}

impl PercentageProgressBar {

    pub fn render(&self) {
        print!("\r{msg}{value}%", msg=self.msg, value=self.value);
        stdout().flush().ok().expect("write to stdout failed");
    }

    pub fn set_value(&mut self, value: u8) { if value <= 100 { self.value = value } }
    pub fn get_value(&self) -> u8 { self.value }

    pub fn set_msg(&mut self, msg: &str) { self.msg = msg.to_owned() }
    pub fn get_msg(&self) -> &str { self.msg.as_ref() }

    pub fn inc(&mut self) { if self.value < 100 { self.value += 1; } }
    pub fn dec(&mut self) { if self.value > 0 { self.value -= 1; } }

}

pub struct InfiniteProgressBar {
    msg:   String,
    marker_position:  i8,
    step: i8
}

impl Default for InfiniteProgressBar {
    fn default() -> InfiniteProgressBar {
        InfiniteProgressBar {
            step: 1,
            msg: "".to_owned(),
            marker_position: 0
        }
    }
}

impl ProgressBar<InfiniteProgressBar> for InfiniteProgressBar {

    fn new() -> InfiniteProgressBar {
        InfiniteProgressBar { ..Default::default()}
    }
}

impl InfiniteProgressBar {

    pub fn set_msg(&mut self, msg: &str) { self.msg = msg.to_owned() }
    pub fn get_msg(&self) -> &str { self.msg.as_ref() }

    pub fn render(&mut self) {

        let (screen_w, screen_h) = term_utils::get_winsize().unwrap();

        if self.marker_position <= 0 {
            self.marker_position = 0;
            self.step = 1;
        } else if self.marker_position > 9 {
            self.marker_position = 10;
            self.step = -1;
        }
        self.marker_position = self.marker_position + self.step;

        let mut bar:String = "..........".to_owned(); //10 dots
        bar.insert(self.marker_position as usize, '#');
        print!("\r{msg}[{bar}]", msg=self.msg, bar=bar);
        stdout().flush().ok().expect("write to stdout failed");
    }

}
<|endoftext|>


<commit_before>use crate::{get_book_dir, open};
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::Result;
use mdbook::utils;
use mdbook::MDBook;
use notify::Watcher;
use std::path::{Path, PathBuf};
use std::sync::mpsc::channel;
use std::thread::sleep;
use std::time::Duration;

// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("watch")
        .about("Watches a book's files and rebuilds it on changes")
        .arg_from_usage(
            "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
             Relative paths are interpreted relative to the book's root directory.{n}\
             If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
        )
        .arg_from_usage(
            "[dir] 'Root directory for the book{n}\
             (Defaults to the Current Directory when omitted)'",
        )
        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
}

// Watch command implementation
pub fn execute(args: &ArgMatches) -> Result<()> {
    let book_dir = get_book_dir(args);
    let book = MDBook::load(&book_dir)?;

    if args.is_present("open") {
        book.build()?;
        open(book.build_dir_for("html").join("index.html"));
    }

    trigger_on_change(&book, |paths, book_dir| {
        info!("Files changed: {:?}\nBuilding book...\n", paths);
        let result = MDBook::load(&book_dir).and_then(|b| b.build());

        if let Err(e) = result {
            error!("Unable to build the book");
            utils::log_backtrace(&e);
        }
    });

    Ok(())
}

fn remove_ignored_files(book_root: &PathBuf, paths: &[PathBuf]) -> Vec<PathBuf> {
    if paths.is_empty() {
        return vec![];
    }

    let gitignore_path = book_root.join(".gitignore");

    match gitignore::File::new(gitignore_path.as_path()) {
        Ok(exclusion_checker) => paths
            .iter()
            .filter(|path| match exclusion_checker.is_excluded(path) {
                Ok(exclude) => !exclude,
                Err(error) => {
                    warn!(
                        "Unable to determine if {:?} is excluded: {:?}. Including it.",
                        &path, error
                    );
                    true
                }
            })
            .map(|path| path.to_path_buf())
            .collect(),
        Err(error) => {
            warn!(
                "Unable to read gitignore file at {:?} file: {:?}. All files will be allowed.",
                gitignore_path, error
            );
            paths.iter().map(|path| path.to_path_buf()).collect()
        }
    }
}

/// Calls the closure when a book source file is changed, blocking indefinitely.
pub fn trigger_on_change<F>(book: &MDBook, closure: F)
where
    F: Fn(Vec<PathBuf>, &Path),
{
    use notify::DebouncedEvent::*;
    use notify::RecursiveMode::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            error!("Error while trying to watch the files:\n\n\t{:?}", e);
            std::process::exit(1)
        }
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.source_dir(), Recursive) {
        error!("Error while watching {:?}:\n    {:?}", book.source_dir(), e);
        std::process::exit(1);
    };

    let _ = watcher.watch(book.theme_dir(), Recursive);

    // Add the book.toml file to the watcher if it exists
    let _ = watcher.watch(book.root.join("book.toml"), NonRecursive);

    info!("Listening for changes...");

    loop {
        let first_event = rx.recv().unwrap();
        sleep(Duration::from_millis(50));
        let other_events = rx.try_iter();

        let all_events = std::iter::once(first_event).chain(other_events);

        let paths = all_events
            .filter_map(|event| {
                debug!("Received filesystem event: {:?}", event);

                match event {
                    Create(path) | Write(path) | Remove(path) | Rename(_, path) => Some(path),
                    _ => None,
                }
            })
            .collect::<Vec<_>>();

        let paths = remove_ignored_files(&book.root, &paths[..]);

        if !paths.is_empty() {
            closure(paths, &book.root);
        }
    }
}
<commit_msg>The .gitignore file is now searched for recursively. Removed a warning if .gitignore is missing.<commit_after>use crate::{get_book_dir, open};
use clap::{App, ArgMatches, SubCommand};
use mdbook::errors::Result;
use mdbook::utils;
use mdbook::MDBook;
use notify::Watcher;
use std::path::{Path, PathBuf};
use std::sync::mpsc::channel;
use std::thread::sleep;
use std::time::Duration;

// Create clap subcommand arguments
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("watch")
        .about("Watches a book's files and rebuilds it on changes")
        .arg_from_usage(
            "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\
             Relative paths are interpreted relative to the book's root directory.{n}\
             If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'",
        )
        .arg_from_usage(
            "[dir] 'Root directory for the book{n}\
             (Defaults to the Current Directory when omitted)'",
        )
        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
}

// Watch command implementation
pub fn execute(args: &ArgMatches) -> Result<()> {
    let book_dir = get_book_dir(args);
    let book = MDBook::load(&book_dir)?;

    if args.is_present("open") {
        book.build()?;
        open(book.build_dir_for("html").join("index.html"));
    }

    trigger_on_change(&book, |paths, book_dir| {
        info!("Files changed: {:?}\nBuilding book...\n", paths);
        let result = MDBook::load(&book_dir).and_then(|b| b.build());

        if let Err(e) = result {
            error!("Unable to build the book");
            utils::log_backtrace(&e);
        }
    });

    Ok(())
}

fn remove_ignored_files(book_root: &PathBuf, paths: &[PathBuf]) -> Vec<PathBuf> {
    if paths.is_empty() {
        return vec![];
    }

    match find_gitignore(book_root) {
        Some(gitignore_path) => {
            match gitignore::File::new(gitignore_path.as_path()) {
                Ok(exclusion_checker) => filter_ignored_files(exclusion_checker, paths),
                Err(_) => {
                    // We're unable to read the .gitignore file, so we'll silently allow everything.
                    // Please see discussion: https://github.com/rust-lang-nursery/mdBook/pull/1051
                    paths.iter().map(|path| path.to_path_buf()).collect()
                }
            }
        }
        None => {
            // There is no .gitignore file.
            paths.iter().map(|path| path.to_path_buf()).collect()
        }
    }
}

fn find_gitignore(book_root: &PathBuf) -> Option<PathBuf> {
    book_root
        .ancestors()
        .map(|p| p.join(".gitignore"))
        .find(|p| p.exists())
}

fn filter_ignored_files(exclusion_checker: gitignore::File, paths: &[PathBuf]) -> Vec<PathBuf> {
    paths
        .iter()
        .filter(|path| match exclusion_checker.is_excluded(path) {
            Ok(exclude) => !exclude,
            Err(error) => {
                warn!(
                    "Unable to determine if {:?} is excluded: {:?}. Including it.",
                    &path, error
                );
                true
            }
        })
        .map(|path| path.to_path_buf())
        .collect()
}

/// Calls the closure when a book source file is changed, blocking indefinitely.
pub fn trigger_on_change<F>(book: &MDBook, closure: F)
where
    F: Fn(Vec<PathBuf>, &Path),
{
    use notify::DebouncedEvent::*;
    use notify::RecursiveMode::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            error!("Error while trying to watch the files:\n\n\t{:?}", e);
            std::process::exit(1)
        }
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.source_dir(), Recursive) {
        error!("Error while watching {:?}:\n    {:?}", book.source_dir(), e);
        std::process::exit(1);
    };

    let _ = watcher.watch(book.theme_dir(), Recursive);

    // Add the book.toml file to the watcher if it exists
    let _ = watcher.watch(book.root.join("book.toml"), NonRecursive);

    info!("Listening for changes...");

    loop {
        let first_event = rx.recv().unwrap();
        sleep(Duration::from_millis(50));
        let other_events = rx.try_iter();

        let all_events = std::iter::once(first_event).chain(other_events);

        let paths = all_events
            .filter_map(|event| {
                debug!("Received filesystem event: {:?}", event);

                match event {
                    Create(path) | Write(path) | Remove(path) | Rename(_, path) => Some(path),
                    _ => None,
                }
            })
            .collect::<Vec<_>>();

        let paths = remove_ignored_files(&book.root, &paths[..]);

        if !paths.is_empty() {
            closure(paths, &book.root);
        }
    }
}
<|endoftext|>


<commit_before>use super::RdxSort;

use core::ptr;

use std::cmp;
use std::mem;

/// Generic Radix Sort implementation
///
/// Works by splitting the work in rounds. During every round, the data is sorted into buckets and
/// is then collected again. Rounds are count from `0` to (exclusive) `cfg_nrounds()`.
///
/// The number of buckets is fixed for all rounds. That does not mean that the template has to use
/// all of them, since unused buckets are just empty and have no effect on the collected results.
/// Same hold for the number of rounds. Over-booking one or both of them wastes resources of
/// course.
///
/// **WARNING: The result returned from `get_bucket()` is not checked. Wrong implementations may
/// crash the program, or destroy the world, or both!!!**
pub trait RdxSortTemplate {
    /// Sets the number of buckets used by the generic implementation.
    fn cfg_nbuckets() -> usize;

    /// Sets the number of rounds scheduled by the generic implementation.
    fn cfg_nrounds() -> usize;

    /// Returns the bucket, depending on the round.
    ///
    /// This should respect the radix, e.g.:
    ///
    /// - if the number of buckets is `2` and the type is an unsigned integer, then the result is
    ///   the bit starting with the least significant one.
    /// - if the number of buckets is `8` and the type is an unsigned integer, then the result is
    ///   the byte starting with the least significant one.
    ///
    /// **Never** return a bucker greater or equal the number of buckets. See warning above!
    fn get_bucket(&self, round: usize) -> usize;

    /// Describes the fact that the content of a bucket should be copied back in reverse order
    /// after a certain round.
    fn reverse(round: usize, bucket: usize) -> bool;
}

#[inline]
fn helper_bucket<T, I>(buckets_b: &mut Vec<Vec<T>>, iter: I, cfg_nbuckets: usize, round: usize)
    where T: RdxSortTemplate,
          I: Iterator<Item = T>
{
    for x in iter {
        let b = x.get_bucket(round);
        assert!(b < cfg_nbuckets,
                "Your RdxSortTemplate implementation returns a bucket >= cfg_nbuckets()!");
        unsafe {
            buckets_b.get_unchecked_mut(b).push(x);
        }
    }
}

impl<T> RdxSort for [T] where T: RdxSortTemplate + Clone
{
    fn rdxsort(&mut self) {
        // config
        let cfg_nbuckets = T::cfg_nbuckets();
        let cfg_nrounds = T::cfg_nrounds();

        // early return
        if cfg_nrounds == 0 {
            return;
        }

        let n = self.len();
        let presize = cmp::max(16, (n << 2) / cfg_nbuckets);  // TODO: justify the presize value
        let mut buckets_a: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
        let mut buckets_b: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
        for _ in 0..cfg_nbuckets {
            buckets_a.push(Vec::with_capacity(presize));
            buckets_b.push(Vec::with_capacity(presize));
        }

        for x in self.iter().cloned() {
            let b = x.get_bucket(0);
            assert!(b < cfg_nbuckets,
                    "Your RdxSortTemplate implementation returns a bucket >= cfg_nbuckets()!");
            unsafe {
                buckets_a.get_unchecked_mut(b).push(x);
            }
        }

        for round in 1..cfg_nrounds {
            for bucket in &mut buckets_b {
                bucket.clear();
            }
            for (i, bucket) in buckets_a.iter().enumerate() {
                if T::reverse(round - 1, i) {
                    helper_bucket(&mut buckets_b,
                                  bucket.iter().rev().cloned(),
                                  cfg_nbuckets,
                                  round);
                } else {
                    helper_bucket(&mut buckets_b, bucket.iter().cloned(), cfg_nbuckets, round);
                }
            }
            mem::swap(&mut buckets_a, &mut buckets_b);
        }

        let mut pos = 0;
        for (i, bucket) in buckets_a.iter_mut().enumerate() {
            assert!(pos + bucket.len() <= self.len(),
                    "bug: a buckets got oversized");

            if T::reverse(cfg_nrounds - 1, i) {
                for x in bucket.iter().rev().cloned() {
                    unsafe {
                        *self.get_unchecked_mut(pos) = x;
                    }
                    pos += 1;
                }
            } else {
                unsafe {
                    ptr::copy_nonoverlapping(bucket.as_ptr(),
                                             self.get_unchecked_mut(pos),
                                             bucket.len());
                }
                pos += bucket.len();
            }
        }

        assert!(pos == self.len(), "bug: bucket size does not sum up");
    }
}

impl<T> RdxSort for Vec<T> where [T]: RdxSort
{
    fn rdxsort(&mut self) {
        self.as_mut_slice().rdxsort();
    }
}
<commit_msg>code deduplication<commit_after>use super::RdxSort;

use core::ptr;

use std::cmp;
use std::mem;

/// Generic Radix Sort implementation
///
/// Works by splitting the work in rounds. During every round, the data is sorted into buckets and
/// is then collected again. Rounds are count from `0` to (exclusive) `cfg_nrounds()`.
///
/// The number of buckets is fixed for all rounds. That does not mean that the template has to use
/// all of them, since unused buckets are just empty and have no effect on the collected results.
/// Same hold for the number of rounds. Over-booking one or both of them wastes resources of
/// course.
///
/// **WARNING: The result returned from `get_bucket()` is not checked. Wrong implementations may
/// crash the program, or destroy the world, or both!!!**
pub trait RdxSortTemplate {
    /// Sets the number of buckets used by the generic implementation.
    fn cfg_nbuckets() -> usize;

    /// Sets the number of rounds scheduled by the generic implementation.
    fn cfg_nrounds() -> usize;

    /// Returns the bucket, depending on the round.
    ///
    /// This should respect the radix, e.g.:
    ///
    /// - if the number of buckets is `2` and the type is an unsigned integer, then the result is
    ///   the bit starting with the least significant one.
    /// - if the number of buckets is `8` and the type is an unsigned integer, then the result is
    ///   the byte starting with the least significant one.
    ///
    /// **Never** return a bucker greater or equal the number of buckets. See warning above!
    fn get_bucket(&self, round: usize) -> usize;

    /// Describes the fact that the content of a bucket should be copied back in reverse order
    /// after a certain round.
    fn reverse(round: usize, bucket: usize) -> bool;
}

#[inline]
fn helper_bucket<T, I>(buckets_b: &mut Vec<Vec<T>>, iter: I, cfg_nbuckets: usize, round: usize)
    where T: RdxSortTemplate,
          I: Iterator<Item = T>
{
    for x in iter {
        let b = x.get_bucket(round);
        assert!(b < cfg_nbuckets,
                "Your RdxSortTemplate implementation returns a bucket >= cfg_nbuckets()!");
        unsafe {
            buckets_b.get_unchecked_mut(b).push(x);
        }
    }
}

impl<T> RdxSort for [T] where T: RdxSortTemplate + Clone
{
    fn rdxsort(&mut self) {
        // config
        let cfg_nbuckets = T::cfg_nbuckets();
        let cfg_nrounds = T::cfg_nrounds();

        // early return
        if cfg_nrounds == 0 {
            return;
        }

        let n = self.len();
        let presize = cmp::max(16, (n << 2) / cfg_nbuckets);  // TODO: justify the presize value
        let mut buckets_a: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
        let mut buckets_b: Vec<Vec<T>> = Vec::with_capacity(cfg_nbuckets);
        for _ in 0..cfg_nbuckets {
            buckets_a.push(Vec::with_capacity(presize));
            buckets_b.push(Vec::with_capacity(presize));
        }

        helper_bucket(&mut buckets_a, self.iter().cloned(), cfg_nbuckets, 0);

        for round in 1..cfg_nrounds {
            for bucket in &mut buckets_b {
                bucket.clear();
            }
            for (i, bucket) in buckets_a.iter().enumerate() {
                if T::reverse(round - 1, i) {
                    helper_bucket(&mut buckets_b,
                                  bucket.iter().rev().cloned(),
                                  cfg_nbuckets,
                                  round);
                } else {
                    helper_bucket(&mut buckets_b, bucket.iter().cloned(), cfg_nbuckets, round);
                }
            }
            mem::swap(&mut buckets_a, &mut buckets_b);
        }

        let mut pos = 0;
        for (i, bucket) in buckets_a.iter_mut().enumerate() {
            assert!(pos + bucket.len() <= self.len(),
                    "bug: a buckets got oversized");

            if T::reverse(cfg_nrounds - 1, i) {
                for x in bucket.iter().rev().cloned() {
                    unsafe {
                        *self.get_unchecked_mut(pos) = x;
                    }
                    pos += 1;
                }
            } else {
                unsafe {
                    ptr::copy_nonoverlapping(bucket.as_ptr(),
                                             self.get_unchecked_mut(pos),
                                             bucket.len());
                }
                pos += bucket.len();
            }
        }

        assert!(pos == self.len(), "bug: bucket size does not sum up");
    }
}

impl<T> RdxSort for Vec<T> where [T]: RdxSort
{
    fn rdxsort(&mut self) {
        self.as_mut_slice().rdxsort();
    }
}
<|endoftext|>