<commit_before>use crate::error::ParseMessageError;
use crate::structs;
use std::fmt;
use std::str::FromStr;

#[derive(Debug)]
pub enum ClientMessage {
    Key { user: String },
    Pam { user: String },
    CleanUp,
    RateLimit,
    SectorGroups,
    PwUid { uid: u64 },
}

#[derive(Debug)]
pub enum DaemonMessage {
    Error { message: String },
    Key { keys: String },
    Pam { result: bool },
    CleanUp,
    RateLimit { limit: usize },
    SectorGroups { sectors: Vec<structs::SectorGroup> },
    Pw { login: String, uid: u64, gid: u64 },
}

impl fmt::Display for ClientMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ClientMessage::Key { user } => write!(f, "c:key:{}", user),
            ClientMessage::Pam { user } => write!(f, "c:pam:{}", user),
            ClientMessage::CleanUp => write!(f, "c:cleanup"),
            ClientMessage::RateLimit => write!(f, "c:ratelimit"),
            ClientMessage::SectorGroups => write!(f, "c:sectors"),
            ClientMessage::PwUid { uid } => write!(f, "c:pwuid:{}", uid),
        }
    }
}

impl fmt::Display for DaemonMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DaemonMessage::Error { message } => write!(f, "d:error:{}", message),
            DaemonMessage::Key { keys } => write!(f, "d:key:{}", keys),
            DaemonMessage::Pam { result } => write!(f, "d:pam:{}", result),
            DaemonMessage::CleanUp => write!(f, "d:cleanup"),
            DaemonMessage::RateLimit { limit } => write!(f, "d:ratelimit:{}", limit),
            DaemonMessage::SectorGroups { sectors } => {
                let ss: Vec<String> = sectors.iter().map(|s| s.to_string()).collect();
                write!(f, "d:sectors:{}", ss.join("\n"))
            }
            DaemonMessage::Pw { login, uid, gid } => write!(f, "d:pw:{}:{}:{}", login, uid, gid),
        }
    }
}

impl FromStr for ClientMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("c:key:") {
            Ok(ClientMessage::Key { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("c:pam:") {
            Ok(ClientMessage::Pam { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s == "c:cleanup" {
            Ok(ClientMessage::CleanUp)
        } else if s == "c:ratelimit" {
            Ok(ClientMessage::RateLimit)
        } else if s == "c:sectors" {
            Ok(ClientMessage::SectorGroups)
        } else if s.starts_with("c:pwuid:") {
            Ok(ClientMessage::PwUid { uid: s.get(8..).unwrap_or_default().parse::<u64>().unwrap() })
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for DaemonMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("d:key:") {
            Ok(DaemonMessage::Key { keys: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("d:pam:") {
            Ok(DaemonMessage::Pam { result: FromStr::from_str(s.get(6..).unwrap_or("false")).unwrap_or(false) })
        } else if s == "d:cleanup" {
            Ok(DaemonMessage::CleanUp)
        } else if s.starts_with("d:ratelimit:") {
            Ok(DaemonMessage::RateLimit { limit: s.get(12..).unwrap_or("0").parse::<usize>().unwrap_or(0) })
        } else if s.starts_with("d:sectors:") {
            let sectors = s.get(10..)
                           .unwrap_or_default()
                           .split('\n')
                           .filter_map(|l| l.parse::<structs::SectorGroup>().ok())
                           .collect();
            Ok(DaemonMessage::SectorGroups { sectors })
        } else if s.starts_with("d:pw:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(":")
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 3 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let login: String = fields[0].clone();
            match (fields[1].parse::<u64>(), fields[2].parse::<u64>()) {
                (Ok(uid), Ok(gid)) => Ok(DaemonMessage::Pw { login, uid, gid }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else {
            Err(ParseMessageError::ParseDaemonMessageError)
        }
    }
}
<commit_msg>Allow an unused message<commit_after>use crate::error::ParseMessageError;
use crate::structs;
use std::fmt;
use std::str::FromStr;

#[derive(Debug)]
pub enum ClientMessage {
    Key { user: String },
    Pam { user: String },
    CleanUp,
    RateLimit,
    SectorGroups,
    PwUid { uid: u64 },
}

#[allow(unused)]
#[derive(Debug)]
pub enum DaemonMessage {
    Error { message: String },
    Key { keys: String },
    Pam { result: bool },
    CleanUp,
    RateLimit { limit: usize },
    SectorGroups { sectors: Vec<structs::SectorGroup> },
    Pw { login: String, uid: u64, gid: u64 },
}

impl fmt::Display for ClientMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ClientMessage::Key { user } => write!(f, "c:key:{}", user),
            ClientMessage::Pam { user } => write!(f, "c:pam:{}", user),
            ClientMessage::CleanUp => write!(f, "c:cleanup"),
            ClientMessage::RateLimit => write!(f, "c:ratelimit"),
            ClientMessage::SectorGroups => write!(f, "c:sectors"),
            ClientMessage::PwUid { uid } => write!(f, "c:pwuid:{}", uid),
        }
    }
}

impl fmt::Display for DaemonMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DaemonMessage::Error { message } => write!(f, "d:error:{}", message),
            DaemonMessage::Key { keys } => write!(f, "d:key:{}", keys),
            DaemonMessage::Pam { result } => write!(f, "d:pam:{}", result),
            DaemonMessage::CleanUp => write!(f, "d:cleanup"),
            DaemonMessage::RateLimit { limit } => write!(f, "d:ratelimit:{}", limit),
            DaemonMessage::SectorGroups { sectors } => {
                let ss: Vec<String> = sectors.iter().map(|s| s.to_string()).collect();
                write!(f, "d:sectors:{}", ss.join("\n"))
            }
            DaemonMessage::Pw { login, uid, gid } => write!(f, "d:pw:{}:{}:{}", login, uid, gid),
        }
    }
}

impl FromStr for ClientMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("c:key:") {
            Ok(ClientMessage::Key { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("c:pam:") {
            Ok(ClientMessage::Pam { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s == "c:cleanup" {
            Ok(ClientMessage::CleanUp)
        } else if s == "c:ratelimit" {
            Ok(ClientMessage::RateLimit)
        } else if s == "c:sectors" {
            Ok(ClientMessage::SectorGroups)
        } else if s.starts_with("c:pwuid:") {
            Ok(ClientMessage::PwUid { uid: s.get(8..).unwrap_or_default().parse::<u64>().unwrap() })
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for DaemonMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("d:key:") {
            Ok(DaemonMessage::Key { keys: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("d:pam:") {
            Ok(DaemonMessage::Pam { result: FromStr::from_str(s.get(6..).unwrap_or("false")).unwrap_or(false) })
        } else if s == "d:cleanup" {
            Ok(DaemonMessage::CleanUp)
        } else if s.starts_with("d:ratelimit:") {
            Ok(DaemonMessage::RateLimit { limit: s.get(12..).unwrap_or("0").parse::<usize>().unwrap_or(0) })
        } else if s.starts_with("d:sectors:") {
            let sectors = s.get(10..)
                           .unwrap_or_default()
                           .split('\n')
                           .filter_map(|l| l.parse::<structs::SectorGroup>().ok())
                           .collect();
            Ok(DaemonMessage::SectorGroups { sectors })
        } else if s.starts_with("d:pw:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(":")
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 3 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let login: String = fields[0].clone();
            match (fields[1].parse::<u64>(), fields[2].parse::<u64>()) {
                (Ok(uid), Ok(gid)) => Ok(DaemonMessage::Pw { login, uid, gid }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else {
            Err(ParseMessageError::ParseDaemonMessageError)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_results)]
#![allow(clippy::print_stdout)]

use std::sync::atomic::AtomicUsize;

#[cfg(not(target_arch = "x86_64"))]
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use crate::Lazy;

use super::*;

/// A metric collector for all pagecache users running in this
/// process.
pub static M: Lazy<Metrics, fn() -> Metrics> = Lazy::new(Metrics::default);

#[allow(clippy::cast_precision_loss)]
pub(crate) fn clock() -> u64 {
    if cfg!(feature = "no_metrics") {
        0
    } else {
        #[cfg(target_arch = "x86_64")]
        #[allow(unsafe_code)]
        unsafe {
            let mut aux = 0;
            core::arch::x86_64::__rdtscp(&mut aux)
        }

        #[cfg(not(target_arch = "x86_64"))]
        {
            let u = uptime();
            (u.as_secs() * 1_000_000_000) as u64 + u64::from(u.subsec_nanos())
        }
    }
}

// not correct, since it starts counting at the first observance...
#[cfg(not(target_arch = "x86_64"))]
pub(crate) fn uptime() -> Duration {
    static START: Lazy<Instant, fn() -> Instant> = Lazy::new(Instant::now);

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histogram::measure()`.
pub struct Measure<'h> {
    _start: u64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histogram,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline]
    pub fn new(_histo: &'h Histogram) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo: _histo,
            _start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self._start);
    }
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub accountant_bump_tip: Histogram,
    pub accountant_hold: Histogram,
    pub accountant_lock: Histogram,
    pub accountant_mark_link: Histogram,
    pub accountant_mark_replace: Histogram,
    pub accountant_next: Histogram,
    pub advance_snapshot: Histogram,
    pub assign_offset: Histogram,
    pub compress: Histogram,
    pub decompress: Histogram,
    pub deserialize: Histogram,
    pub get_page: Histogram,
    pub get_pagetable: Histogram,
    pub link_page: Histogram,
    pub log_reservation_attempts: CachePadded<AtomicUsize>,
    pub log_reservations: CachePadded<AtomicUsize>,
    pub make_stable: Histogram,
    pub page_out: Histogram,
    pub pull: Histogram,
    pub read: Histogram,
    pub read_segment_message: Histogram,
    pub replace_page: Histogram,
    pub reserve_lat: Histogram,
    pub reserve_sz: Histogram,
    pub rewrite_page: Histogram,
    pub segment_read: Histogram,
    pub segment_utilization_startup: Histogram,
    pub segment_utilization_shutdown: Histogram,
    pub serialize: Histogram,
    pub snapshot_apply: Histogram,
    pub start_pagecache: Histogram,
    pub start_segment_accountant: Histogram,
    pub tree_cas: Histogram,
    pub tree_child_split_attempt: CachePadded<AtomicUsize>,
    pub tree_child_split_success: CachePadded<AtomicUsize>,
    pub tree_del: Histogram,
    pub tree_get: Histogram,
    pub tree_loops: CachePadded<AtomicUsize>,
    pub tree_merge: Histogram,
    pub tree_parent_split_attempt: CachePadded<AtomicUsize>,
    pub tree_parent_split_success: CachePadded<AtomicUsize>,
    pub tree_reverse_scan: Histogram,
    pub tree_root_split_attempt: CachePadded<AtomicUsize>,
    pub tree_root_split_success: CachePadded<AtomicUsize>,
    pub tree_scan: Histogram,
    pub tree_set: Histogram,
    pub tree_start: Histogram,
    pub tree_traverse: Histogram,
    pub write_to_log: Histogram,
    pub written_bytes: Histogram,
    #[cfg(feature = "measure_allocs")]
    pub allocations: CachePadded<AtomicUsize>,
    #[cfg(feature = "measure_allocs")]
    pub allocated_bytes: CachePadded<AtomicUsize>,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    #[inline]
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_attempt(&self) {
        self.tree_child_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_success(&self) {
        self.tree_child_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_attempt(&self) {
        self.tree_parent_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_success(&self) {
        self.tree_parent_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_attempt(&self) {
        self.tree_root_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_success(&self) {
        self.tree_root_split_success.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "sled profile:\n\
             {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10} | {8: >10} | {9: >10}",
            "op",
            "min (us)",
            "med (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "99.99 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", std::iter::repeat("-").take(134).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.9 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                     | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.1} \
                     | {8: >10.1} | {9: >10.3}",
                    v.0, v.1, v.2, v.3, v.4, v.5, v.6, v.7, v.8, v.9,
                );
            }
        };

        let lat = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(50.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(99.99) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        let sz = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.),
                histo.percentile(50.),
                histo.percentile(90.),
                histo.percentile(99.),
                histo.percentile(99.9),
                histo.percentile(99.99),
                histo.percentile(100.),
                histo.count(),
                histo.sum() as f64,
            )
        };

        println!("tree:");
        p(vec![
            lat("traverse", &self.tree_traverse),
            lat("get", &self.tree_get),
            lat("set", &self.tree_set),
            lat("merge", &self.tree_merge),
            lat("del", &self.tree_del),
            lat("cas", &self.tree_cas),
            lat("scan", &self.tree_scan),
            lat("rev scan", &self.tree_reverse_scan),
        ]);
        let total_loops = self.tree_loops.load(Acquire);
        let total_ops = self.tree_get.count()
            + self.tree_set.count()
            + self.tree_merge.count()
            + self.tree_del.count()
            + self.tree_cas.count()
            + self.tree_scan.count()
            + self.tree_reverse_scan.count();
        let loop_pct = total_loops * 100 / total_ops;
        println!(
            "tree contention loops: {} ({}% retry rate)",
            total_loops, loop_pct
        );
        println!(
            "tree split success rates: child({}/{}) parent({}/{}) root({}/{})",
            self.tree_child_split_success.load(Acquire),
            self.tree_child_split_attempt.load(Acquire),
            self.tree_parent_split_success.load(Acquire),
            self.tree_parent_split_attempt.load(Acquire),
            self.tree_root_split_success.load(Acquire),
            self.tree_root_split_attempt.load(Acquire),
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("pagecache:");
        p(vec![
            lat("get", &self.get_page),
            lat("get pt", &self.get_pagetable),
            lat("rewrite", &self.rewrite_page),
            lat("replace", &self.replace_page),
            lat("link", &self.link_page),
            lat("pull", &self.pull),
            lat("page_out", &self.page_out),
        ]);
        let hit_ratio = (self.get_page.count() - self.pull.count()) * 100
            / std::cmp::max(1, self.get_page.count());
        println!("hit ratio: {}%", hit_ratio);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            lat("serialize", &self.serialize),
            lat("deserialize", &self.deserialize),
            #[cfg(feature = "compression")]
            lat("compress", &self.compress),
            #[cfg(feature = "compression")]
            lat("decompress", &self.decompress),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("log:");
        p(vec![
            lat("make_stable", &self.make_stable),
            lat("read", &self.read),
            lat("write", &self.write_to_log),
            sz("written bytes", &self.written_bytes),
            lat("assign offset", &self.assign_offset),
            lat("reserve lat", &self.reserve_lat),
            sz("reserve sz", &self.reserve_sz),
        ]);
        let log_reservations =
            std::cmp::max(1, self.log_reservations.load(Acquire));
        let log_reservation_attempts =
            self.log_reservation_attempts.load(Acquire);
        let log_reservation_retry_rate =
            (log_reservation_attempts - log_reservations) * 100
                / log_reservations;
        println!("log reservations: {}", log_reservations);
        println!(
            "log res attempts: {}, ({}% retry rate)",
            log_reservation_attempts, log_reservation_retry_rate,
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("segment accountant:");
        p(vec![
            lat("acquire", &self.accountant_lock),
            lat("hold", &self.accountant_hold),
            lat("next", &self.accountant_next),
            lat("replace", &self.accountant_mark_replace),
            lat("link", &self.accountant_mark_link),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("recovery:");
        p(vec![
            lat("start", &self.tree_start),
            lat("advance snapshot", &self.advance_snapshot),
            lat("load SA", &self.start_segment_accountant),
            lat("load PC", &self.start_pagecache),
            lat("snap apply", &self.snapshot_apply),
            lat("segment read", &self.segment_read),
            lat("log message read", &self.read_segment_message),
            sz("seg util start", &self.segment_utilization_startup),
            sz("seg util end", &self.segment_utilization_shutdown),
        ]);

        #[cfg(feature = "measure_allocs")]
        {
            println!(
                "{}",
                std::iter::repeat("-").take(134).collect::<String>()
            );
            println!("allocation statistics:");
            println!(
                "total allocations: {}",
                measure_allocs::ALLOCATIONS.load(Acquire)
            );
            println!(
                "allocated bytes: {}",
                measure_allocs::ALLOCATED_BYTES.load(Acquire)
            );
        }
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub const fn log_reservation_attempted(&self) {}

    pub const fn log_reservation_success(&self) {}

    pub const fn tree_child_split_attempt(&self) {}

    pub const fn tree_child_split_success(&self) {}

    pub const fn tree_parent_split_attempt(&self) {}

    pub const fn tree_parent_split_success(&self) {}

    pub const fn tree_root_split_attempt(&self) {}

    pub const fn tree_root_split_success(&self) {}

    pub const fn tree_looped(&self) {}

    pub const fn print_profile(&self) {}
}
<commit_msg>Avoid trivial cast<commit_after>#![allow(unused_results)]
#![allow(clippy::print_stdout)]

use std::sync::atomic::AtomicUsize;

#[cfg(not(target_arch = "x86_64"))]
use std::time::{Duration, Instant};

#[cfg(feature = "no_metrics")]
use std::marker::PhantomData;

#[cfg(not(feature = "no_metrics"))]
use std::sync::atomic::Ordering::{Acquire, Relaxed};

use crate::Lazy;

use super::*;

/// A metric collector for all pagecache users running in this
/// process.
pub static M: Lazy<Metrics, fn() -> Metrics> = Lazy::new(Metrics::default);

#[allow(clippy::cast_precision_loss)]
pub(crate) fn clock() -> u64 {
    if cfg!(feature = "no_metrics") {
        0
    } else {
        #[cfg(target_arch = "x86_64")]
        #[allow(unsafe_code)]
        unsafe {
            let mut aux = 0;
            core::arch::x86_64::__rdtscp(&mut aux)
        }

        #[cfg(not(target_arch = "x86_64"))]
        {
            let u = uptime();
            (u.as_secs() * 1_000_000_000) + u64::from(u.subsec_nanos())
        }
    }
}

// not correct, since it starts counting at the first observance...
#[cfg(not(target_arch = "x86_64"))]
pub(crate) fn uptime() -> Duration {
    static START: Lazy<Instant, fn() -> Instant> = Lazy::new(Instant::now);

    if cfg!(feature = "no_metrics") {
        Duration::new(0, 0)
    } else {
        START.elapsed()
    }
}

/// Measure the duration of an event, and call `Histogram::measure()`.
pub struct Measure<'h> {
    _start: u64,
    #[cfg(not(feature = "no_metrics"))]
    histo: &'h Histogram,
    #[cfg(feature = "no_metrics")]
    _pd: PhantomData<&'h ()>,
}

impl<'h> Measure<'h> {
    /// The time delta from ctor to dtor is recorded in `histo`.
    #[inline]
    pub fn new(_histo: &'h Histogram) -> Measure<'h> {
        Measure {
            #[cfg(feature = "no_metrics")]
            _pd: PhantomData,
            #[cfg(not(feature = "no_metrics"))]
            histo: _histo,
            _start: clock(),
        }
    }
}

impl<'h> Drop for Measure<'h> {
    #[inline]
    fn drop(&mut self) {
        #[cfg(not(feature = "no_metrics"))]
        self.histo.measure(clock() - self._start);
    }
}

#[derive(Default, Debug)]
pub struct Metrics {
    pub accountant_bump_tip: Histogram,
    pub accountant_hold: Histogram,
    pub accountant_lock: Histogram,
    pub accountant_mark_link: Histogram,
    pub accountant_mark_replace: Histogram,
    pub accountant_next: Histogram,
    pub advance_snapshot: Histogram,
    pub assign_offset: Histogram,
    pub compress: Histogram,
    pub decompress: Histogram,
    pub deserialize: Histogram,
    pub get_page: Histogram,
    pub get_pagetable: Histogram,
    pub link_page: Histogram,
    pub log_reservation_attempts: CachePadded<AtomicUsize>,
    pub log_reservations: CachePadded<AtomicUsize>,
    pub make_stable: Histogram,
    pub page_out: Histogram,
    pub pull: Histogram,
    pub read: Histogram,
    pub read_segment_message: Histogram,
    pub replace_page: Histogram,
    pub reserve_lat: Histogram,
    pub reserve_sz: Histogram,
    pub rewrite_page: Histogram,
    pub segment_read: Histogram,
    pub segment_utilization_startup: Histogram,
    pub segment_utilization_shutdown: Histogram,
    pub serialize: Histogram,
    pub snapshot_apply: Histogram,
    pub start_pagecache: Histogram,
    pub start_segment_accountant: Histogram,
    pub tree_cas: Histogram,
    pub tree_child_split_attempt: CachePadded<AtomicUsize>,
    pub tree_child_split_success: CachePadded<AtomicUsize>,
    pub tree_del: Histogram,
    pub tree_get: Histogram,
    pub tree_loops: CachePadded<AtomicUsize>,
    pub tree_merge: Histogram,
    pub tree_parent_split_attempt: CachePadded<AtomicUsize>,
    pub tree_parent_split_success: CachePadded<AtomicUsize>,
    pub tree_reverse_scan: Histogram,
    pub tree_root_split_attempt: CachePadded<AtomicUsize>,
    pub tree_root_split_success: CachePadded<AtomicUsize>,
    pub tree_scan: Histogram,
    pub tree_set: Histogram,
    pub tree_start: Histogram,
    pub tree_traverse: Histogram,
    pub write_to_log: Histogram,
    pub written_bytes: Histogram,
    #[cfg(feature = "measure_allocs")]
    pub allocations: CachePadded<AtomicUsize>,
    #[cfg(feature = "measure_allocs")]
    pub allocated_bytes: CachePadded<AtomicUsize>,
}

#[cfg(not(feature = "no_metrics"))]
impl Metrics {
    #[inline]
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_attempted(&self) {
        self.log_reservation_attempts.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn log_reservation_success(&self) {
        self.log_reservations.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_attempt(&self) {
        self.tree_child_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_child_split_success(&self) {
        self.tree_child_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_attempt(&self) {
        self.tree_parent_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_parent_split_success(&self) {
        self.tree_parent_split_success.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_attempt(&self) {
        self.tree_root_split_attempt.fetch_add(1, Relaxed);
    }

    #[inline]
    pub fn tree_root_split_success(&self) {
        self.tree_root_split_success.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "sled profile:\n\
             {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10} | {8: >10} | {9: >10}",
            "op",
            "min (us)",
            "med (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "99.99 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", std::iter::repeat("-").take(134).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.9 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                     | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.1} \
                     | {8: >10.1} | {9: >10.3}",
                    v.0, v.1, v.2, v.3, v.4, v.5, v.6, v.7, v.8, v.9,
                );
            }
        };

        let lat = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(50.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(99.99) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        let sz = |name: &str, histo: &Histogram| {
            (
                name.to_string(),
                histo.percentile(0.),
                histo.percentile(50.),
                histo.percentile(90.),
                histo.percentile(99.),
                histo.percentile(99.9),
                histo.percentile(99.99),
                histo.percentile(100.),
                histo.count(),
                histo.sum() as f64,
            )
        };

        println!("tree:");
        p(vec![
            lat("traverse", &self.tree_traverse),
            lat("get", &self.tree_get),
            lat("set", &self.tree_set),
            lat("merge", &self.tree_merge),
            lat("del", &self.tree_del),
            lat("cas", &self.tree_cas),
            lat("scan", &self.tree_scan),
            lat("rev scan", &self.tree_reverse_scan),
        ]);
        let total_loops = self.tree_loops.load(Acquire);
        let total_ops = self.tree_get.count()
            + self.tree_set.count()
            + self.tree_merge.count()
            + self.tree_del.count()
            + self.tree_cas.count()
            + self.tree_scan.count()
            + self.tree_reverse_scan.count();
        let loop_pct = total_loops * 100 / total_ops;
        println!(
            "tree contention loops: {} ({}% retry rate)",
            total_loops, loop_pct
        );
        println!(
            "tree split success rates: child({}/{}) parent({}/{}) root({}/{})",
            self.tree_child_split_success.load(Acquire),
            self.tree_child_split_attempt.load(Acquire),
            self.tree_parent_split_success.load(Acquire),
            self.tree_parent_split_attempt.load(Acquire),
            self.tree_root_split_success.load(Acquire),
            self.tree_root_split_attempt.load(Acquire),
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("pagecache:");
        p(vec![
            lat("get", &self.get_page),
            lat("get pt", &self.get_pagetable),
            lat("rewrite", &self.rewrite_page),
            lat("replace", &self.replace_page),
            lat("link", &self.link_page),
            lat("pull", &self.pull),
            lat("page_out", &self.page_out),
        ]);
        let hit_ratio = (self.get_page.count() - self.pull.count()) * 100
            / std::cmp::max(1, self.get_page.count());
        println!("hit ratio: {}%", hit_ratio);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            lat("serialize", &self.serialize),
            lat("deserialize", &self.deserialize),
            #[cfg(feature = "compression")]
            lat("compress", &self.compress),
            #[cfg(feature = "compression")]
            lat("decompress", &self.decompress),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("log:");
        p(vec![
            lat("make_stable", &self.make_stable),
            lat("read", &self.read),
            lat("write", &self.write_to_log),
            sz("written bytes", &self.written_bytes),
            lat("assign offset", &self.assign_offset),
            lat("reserve lat", &self.reserve_lat),
            sz("reserve sz", &self.reserve_sz),
        ]);
        let log_reservations =
            std::cmp::max(1, self.log_reservations.load(Acquire));
        let log_reservation_attempts =
            self.log_reservation_attempts.load(Acquire);
        let log_reservation_retry_rate =
            (log_reservation_attempts - log_reservations) * 100
                / log_reservations;
        println!("log reservations: {}", log_reservations);
        println!(
            "log res attempts: {}, ({}% retry rate)",
            log_reservation_attempts, log_reservation_retry_rate,
        );

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("segment accountant:");
        p(vec![
            lat("acquire", &self.accountant_lock),
            lat("hold", &self.accountant_hold),
            lat("next", &self.accountant_next),
            lat("replace", &self.accountant_mark_replace),
            lat("link", &self.accountant_mark_link),
        ]);

        println!("{}", std::iter::repeat("-").take(134).collect::<String>());
        println!("recovery:");
        p(vec![
            lat("start", &self.tree_start),
            lat("advance snapshot", &self.advance_snapshot),
            lat("load SA", &self.start_segment_accountant),
            lat("load PC", &self.start_pagecache),
            lat("snap apply", &self.snapshot_apply),
            lat("segment read", &self.segment_read),
            lat("log message read", &self.read_segment_message),
            sz("seg util start", &self.segment_utilization_startup),
            sz("seg util end", &self.segment_utilization_shutdown),
        ]);

        #[cfg(feature = "measure_allocs")]
        {
            println!(
                "{}",
                std::iter::repeat("-").take(134).collect::<String>()
            );
            println!("allocation statistics:");
            println!(
                "total allocations: {}",
                measure_allocs::ALLOCATIONS.load(Acquire)
            );
            println!(
                "allocated bytes: {}",
                measure_allocs::ALLOCATED_BYTES.load(Acquire)
            );
        }
    }
}

#[cfg(feature = "no_metrics")]
impl Metrics {
    pub const fn log_reservation_attempted(&self) {}

    pub const fn log_reservation_success(&self) {}

    pub const fn tree_child_split_attempt(&self) {}

    pub const fn tree_child_split_success(&self) {}

    pub const fn tree_parent_split_attempt(&self) {}

    pub const fn tree_parent_split_success(&self) {}

    pub const fn tree_root_split_attempt(&self) {}

    pub const fn tree_root_split_success(&self) {}

    pub const fn tree_looped(&self) {}

    pub const fn print_profile(&self) {}
}
<|endoftext|>


<commit_before>#![allow(clippy::upper_case_acronyms)]

use std::collections::{BTreeMap, BTreeSet};

use anyhow::Result;
use log::{debug, error, info};
#[macro_use]
extern crate clap;

use lancelot::{loader::pe::PE, util, VA};
use lancelot_flirt::*;

fn _main() -> Result<()> {
    better_panic::install();

    let matches = clap::clap_app!(lancelot =>
        (author: "Willi Ballenthin <william.ballenthin@mandiant.com>")
        (about: "Binary analysis framework")
        (@arg verbose: -v --verbose +multiple "log verbose messages")
        (@arg quiet: -q --quiet "disable informational messages")
        (@arg sig: +required "path to FLIRT sig/pat")
        (@arg input: +required "path to file to analyze"))
    .get_matches();

    // --quiet overrides --verbose
    let log_level = if matches.is_present("quiet") {
        log::LevelFilter::Error
    } else {
        match matches.occurrences_of("verbose") {
            0 => log::LevelFilter::Info,
            1 => log::LevelFilter::Debug,
            2 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Trace,
        }
    };

    fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{} [{:5}] {} {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                if log_level == log::LevelFilter::Trace {
                    record.target()
                } else {
                    ""
                },
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stderr())
        .filter(|metadata| !metadata.target().starts_with("goblin::pe"))
        .apply()
        .expect("failed to configure logging");

    let sigpath = matches.value_of("sig").unwrap();
    let sigs = if sigpath.ends_with(".pat") {
        FlirtSignatureSet::with_signatures(pat::parse(&String::from_utf8(util::read_file(sigpath)?)?)?)
    } else if sigpath.ends_with(".sig") {
        FlirtSignatureSet::with_signatures(sig::parse(&util::read_file(sigpath)?)?)
    } else {
        return Err(anyhow::anyhow!("--sig must end with .pat or .sig"));
    };

    let filename = matches.value_of("input").unwrap();
    debug!("input: {}", filename);

    let buf = util::read_file(filename)?;
    let pe = PE::from_bytes(&buf)?;

    let mut functions = lancelot::analysis::pe::find_function_starts(&pe)?;
    functions.sort_unstable();
    info!("found {} functions", functions.len());

    #[derive(PartialEq, Eq, PartialOrd, Ord)]
    enum Name {
        Public(String),
        Local(String),
    }

    impl std::fmt::Display for Name {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            match self {
                Name::Public(s) => write!(f, "(public) {}", s),
                Name::Local(s) => write!(f, "(local)  {}", s),
            }
        }
    }

    let mut names: BTreeMap<VA, BTreeSet<Name>> = Default::default();

    for &va in functions.iter() {
        for sig in lancelot::analysis::flirt::match_flirt(&pe.module, &sigs, va)
            .unwrap_or_default()
            .iter()
        {
            for name in sig.names.iter() {
                match name {
                    Symbol::Reference(_) => continue,
                    Symbol::Local(lancelot_flirt::Name { name, offset }) => {
                        names
                            .entry((va as i64 + *offset) as u64)
                            .or_default()
                            .insert(Name::Local(name.clone()));
                    }
                    Symbol::Public(lancelot_flirt::Name { name, offset }) => {
                        names
                            .entry((va as i64 + *offset) as u64)
                            .or_default()
                            .insert(Name::Public(name.clone()));
                    }
                }
            }
        }
    }

    for (va, names) in names.iter() {
        if names.len() == 1 {
            let names: Vec<_> = names.iter().collect();
            println!("{:#x}: {}", va, names[0]);
        } else {
            println!("{:#x}:", va);
            for name in names.iter() {
                println!("  - {}", name);
            }
        }
    }

    Ok(())
}

fn main() {
    if let Err(e) = _main() {
        #[cfg(debug_assertions)]
        error!("{:?}", e);
        #[cfg(not(debug_assertions))]
        error!("{:}", e);
    }
}
<commit_msg>bin: match_sig: accept multiple sigs via cli<commit_after>#![allow(clippy::upper_case_acronyms)]

use std::collections::{BTreeMap, BTreeSet};

use anyhow::Result;
use log::{debug, error, info};
#[macro_use]
extern crate clap;

use lancelot::{loader::pe::PE, util, VA};
use lancelot_flirt::*;

fn _main() -> Result<()> {
    better_panic::install();

    let matches = clap::clap_app!(lancelot =>
        (author: "Willi Ballenthin <william.ballenthin@mandiant.com>")
        (about: "Binary analysis framework")
        (@arg verbose: -v --verbose +multiple "log verbose messages")
        (@arg quiet: -q --quiet "disable informational messages")
        (@arg input: +required "path to file to analyze")
        (@arg sig: +required +multiple "path to FLIRT sig/pat"))
    .get_matches();

    // --quiet overrides --verbose
    let log_level = if matches.is_present("quiet") {
        log::LevelFilter::Error
    } else {
        match matches.occurrences_of("verbose") {
            0 => log::LevelFilter::Info,
            1 => log::LevelFilter::Debug,
            2 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Trace,
        }
    };

    fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{} [{:5}] {} {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                if log_level == log::LevelFilter::Trace {
                    record.target()
                } else {
                    ""
                },
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stderr())
        .filter(|metadata| !metadata.target().starts_with("goblin::pe"))
        .apply()
        .expect("failed to configure logging");

    let mut sigs = vec![];
    for sigpath in matches.values_of("sig").unwrap() {
        if sigpath.ends_with(".pat") {
            sigs.extend(pat::parse(&String::from_utf8(util::read_file(sigpath)?)?)?);
        } else if sigpath.ends_with(".sig") {
            sigs.extend(sig::parse(&util::read_file(sigpath)?)?);
        } else {
            return Err(anyhow::anyhow!("--sig must end with .pat or .sig"));
        };
    }
    let sigs = FlirtSignatureSet::with_signatures(sigs);

    let filename = matches.value_of("input").unwrap();
    debug!("input: {}", filename);

    let buf = util::read_file(filename)?;
    let pe = PE::from_bytes(&buf)?;

    let mut functions = lancelot::analysis::pe::find_function_starts(&pe)?;
    functions.sort_unstable();
    info!("found {} functions", functions.len());

    #[derive(PartialEq, Eq, PartialOrd, Ord)]
    enum Name {
        Public(String),
        Local(String),
    }

    impl std::fmt::Display for Name {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            match self {
                Name::Public(s) => write!(f, "(public) {}", s),
                Name::Local(s) => write!(f, "(local)  {}", s),
            }
        }
    }

    let mut names: BTreeMap<VA, BTreeSet<Name>> = Default::default();

    for &va in functions.iter() {
        for sig in lancelot::analysis::flirt::match_flirt(&pe.module, &sigs, va)
            .unwrap_or_default()
            .iter()
        {
            for name in sig.names.iter() {
                match name {
                    Symbol::Reference(_) => continue,
                    Symbol::Local(lancelot_flirt::Name { name, offset }) => {
                        names
                            .entry((va as i64 + *offset) as u64)
                            .or_default()
                            .insert(Name::Local(name.clone()));
                    }
                    Symbol::Public(lancelot_flirt::Name { name, offset }) => {
                        names
                            .entry((va as i64 + *offset) as u64)
                            .or_default()
                            .insert(Name::Public(name.clone()));
                    }
                }
            }
        }
    }

    for (va, names) in names.iter() {
        if names.len() == 1 {
            let names: Vec<_> = names.iter().collect();
            println!("{:#x}: {}", va, names[0]);
        } else {
            println!("{:#x}:", va);
            for name in names.iter() {
                println!("  - {}", name);
            }
        }
    }

    Ok(())
}

fn main() {
    if let Err(e) = _main() {
        #[cfg(debug_assertions)]
        error!("{:?}", e);
        #[cfg(not(debug_assertions))]
        error!("{:}", e);
    }
}
<|endoftext|>


<commit_before>use na::{self, Real, U3};

use aliases::{TVec2, TVec3, TVec4, TMat4};

/// Define a picking region.
///
/// # Parameters
///   * `center`: Specify the center of a picking region in window coordinates.
///   * `delta`: Specify the width and height, respectively, of the picking region in window coordinates.
///   * `viewport`: Rendering viewport
pub fn pick_matrix<N: Real>(center: &TVec2<N>, delta: &TVec2<N>, viewport: &TVec4<N>) -> TMat4<N> {
    let shift = TVec3::new(
        (viewport.z - (center.x - viewport.x) * na::convert(2.0)) / delta.x,
        (viewport.w - (center.y - viewport.y) * na::convert(2.0)) / delta.y,
        N::zero()
    );

    let result = TMat4::new_translation(&shift);
    result.prepend_nonuniform_scaling(&TVec3::new(viewport.z / delta.x, viewport.w / delta.y, N::one()))
}

/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates using OpenGL near and far clip planes definition.
///
/// # Parameters
///   * `obj`: Specify the object coordinates.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn project<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    project_no(obj, model, proj, viewport)
}

/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
///
/// # Parameters
///   * `obj`: Specify the object coordinates.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn project_no<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let proj = project_zo(obj, model, proj, viewport);
    TVec3::new(proj.x, proj.y, proj.z * na::convert(0.5) + na::convert(0.5))
}

/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
///
/// # Parameters
///   * `obj`: Specify the object coordinates.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn project_zo<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let normalized = proj * model * TVec4::new(obj.x, obj.y, obj.z, N::one());
    let scale = N::one() / normalized.w;

    TVec3::new(
        viewport.x + (viewport.z * (normalized.x * scale + N::one()) * na::convert(0.5)),
        viewport.y + (viewport.w * (normalized.y * scale + N::one()) * na::convert(0.5)),
        normalized.z * scale,
    )
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using OpenGL near and far clip planes definition.
///
/// # Parameters
///   * `obj`: Specify the window coordinates to be mapped.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn unproject<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    unproject_no(win, model, proj, viewport)
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
///
/// # Parameters
///   * `obj`: Specify the window coordinates to be mapped.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn unproject_no<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let _2: N = na::convert(2.0);
    let transform = (proj * model).try_inverse().unwrap_or(TMat4::zeros());
    let pt = TVec4::new(
        _2 * (win.x - viewport.x) / viewport.z - N::one(),
        _2 * (win.y - viewport.y) / viewport.w - N::one(),
        _2 * win.z - N::one(),
        N::one(),
    );

    let result = transform * pt;
    result.fixed_rows::<U3>(0) / result.w
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
///
/// # Parameters
///   * `obj`: Specify the window coordinates to be mapped.
///   * `model`: Specifies the current modelview matrix.
///   * `proj`: Specifies the current projection matrix.
///   * `viewport`: Specifies the current viewport.
pub fn unproject_zo<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let _2: N = na::convert(2.0);
    let transform = (proj * model).try_inverse().unwrap_or(TMat4::zeros());
    let pt = TVec4::new(
        _2 * (win.x - viewport.x) / viewport.z - N::one(),
        _2 * (win.y - viewport.y) / viewport.w - N::one(),
        win.z,
        N::one(),
    );

    let result = transform * pt;
    result.fixed_rows::<U3>(0) / result.w
}
<commit_msg>glm: Use - instead of : after parameter names.<commit_after>use na::{self, Real, U3};

use aliases::{TVec2, TVec3, TVec4, TMat4};

/// Define a picking region.
///
/// # Parameters
///   * `center` - Specify the center of a picking region in window coordinates.
///   * `delta` - Specify the width and height, respectively, of the picking region in window coordinates.
///   * `viewport` - Rendering viewport
pub fn pick_matrix<N: Real>(center: &TVec2<N>, delta: &TVec2<N>, viewport: &TVec4<N>) -> TMat4<N> {
    let shift = TVec3::new(
        (viewport.z - (center.x - viewport.x) * na::convert(2.0)) / delta.x,
        (viewport.w - (center.y - viewport.y) * na::convert(2.0)) / delta.y,
        N::zero()
    );

    let result = TMat4::new_translation(&shift);
    result.prepend_nonuniform_scaling(&TVec3::new(viewport.z / delta.x, viewport.w / delta.y, N::one()))
}

/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates using OpenGL near and far clip planes definition.
///
/// # Parameters
///   * `obj` - Specify the object coordinates.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn project<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    project_no(obj, model, proj, viewport)
}

/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
///
/// # Parameters
///   * `obj` - Specify the object coordinates.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn project_no<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let proj = project_zo(obj, model, proj, viewport);
    TVec3::new(proj.x, proj.y, proj.z * na::convert(0.5) + na::convert(0.5))
}

/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
///
/// # Parameters
///   * `obj` - Specify the object coordinates.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn project_zo<N: Real>(obj: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let normalized = proj * model * TVec4::new(obj.x, obj.y, obj.z, N::one());
    let scale = N::one() / normalized.w;

    TVec3::new(
        viewport.x + (viewport.z * (normalized.x * scale + N::one()) * na::convert(0.5)),
        viewport.y + (viewport.w * (normalized.y * scale + N::one()) * na::convert(0.5)),
        normalized.z * scale,
    )
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using OpenGL near and far clip planes definition.
///
/// # Parameters
///   * `obj` - Specify the window coordinates to be mapped.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn unproject<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    unproject_no(win, model, proj, viewport)
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)
///
/// # Parameters
///   * `obj` - Specify the window coordinates to be mapped.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn unproject_no<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let _2: N = na::convert(2.0);
    let transform = (proj * model).try_inverse().unwrap_or(TMat4::zeros());
    let pt = TVec4::new(
        _2 * (win.x - viewport.x) / viewport.z - N::one(),
        _2 * (win.y - viewport.y) / viewport.w - N::one(),
        _2 * win.z - N::one(),
        N::one(),
    );

    let result = transform * pt;
    result.fixed_rows::<U3>(0) / result.w
}

/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
///
/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)
///
/// # Parameters
///   * `obj` - Specify the window coordinates to be mapped.
///   * `model` - Specifies the current modelview matrix.
///   * `proj` - Specifies the current projection matrix.
///   * `viewport` - Specifies the current viewport.
pub fn unproject_zo<N: Real>(win: &TVec3<N>, model: &TMat4<N>, proj: &TMat4<N>, viewport: TVec4<N>) -> TVec3<N> {
    let _2: N = na::convert(2.0);
    let transform = (proj * model).try_inverse().unwrap_or(TMat4::zeros());
    let pt = TVec4::new(
        _2 * (win.x - viewport.x) / viewport.z - N::one(),
        _2 * (win.y - viewport.y) / viewport.w - N::one(),
        win.z,
        N::one(),
    );

    let result = transform * pt;
    result.fixed_rows::<U3>(0) / result.w
}
<|endoftext|>


<commit_before>use std::io;
use std::time::Duration;
use std::net::{IpAddr, SocketAddr, UdpSocket, Ipv4Addr};

use request::RequestBin;
use response;
use response::Response;

const DEBUG_ENABLED: bool = false;

pub struct Network {}

/// Represents a device on the network, as well as a response.
pub struct Device {
    pub socket_addr: SocketAddr,
    pub response: Option<Response>,
}

impl Network {
    pub fn send_discover_devices(msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = true;
        let broadcast_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 0, 0));
        let broadcast_port = 56700;
        let broadcast_sock_addr = SocketAddr::new(broadcast_ip, broadcast_port);

        send(msg_bin, use_broadcast, broadcast_sock_addr)
    }
}

impl Device {
    pub fn send_get_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_get_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }
}

fn send(msg_bin: RequestBin,
        broadcast: bool,
        device_socket_addr: SocketAddr)
        -> Result<Device, io::Error> {
    let local_ip = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
    let local_sock_addr = SocketAddr::new(local_ip, 56700);
    let local_sock = try!(UdpSocket::bind(local_sock_addr));
    let _ = local_sock.set_write_timeout(Some(Duration::new(3, 0)));
    let _ = local_sock.set_read_timeout(Some(Duration::new(3, 0)));
    local_sock.set_broadcast(broadcast)?;

    let msg = &msg_bin.0;
    display(msg);
    print_debug("** sending...");
    let send_res = match local_sock.send_to(&msg, device_socket_addr) {
        Ok(v) => {
            print_debug("** sent");
        },
        Err(e) => {
            print_debug(&format!("** err sending: {}", e));
            return Err(e);
        },
    };

    // Read from the socket
    print_debug("** reading...");
    let mut resp_buf = [0; 1024];
    let (sz, src_sock_addr) = match local_sock.recv_from(&mut resp_buf) {
        Ok(v)   => {
            print_debug("** response read done");
            v
        },
        Err(e)  => {
            print_debug(&format!("** response read failed: {}", e));
            return Err(e);
        },
    };

    let resp_msg = &resp_buf[0..sz];
    print_debug(&format!("Received from {} : \n{:?}", src_sock_addr, resp_msg));

    let resp = response::parse_response(response::ResponseData(resp_msg.to_vec()));
    // let resp = response::parse_response(response::ResponseMessage(resp_msg.to_vec()));

    let device = Device {
        socket_addr: src_sock_addr,
        response: Some(resp),
    };

    Ok(device)
}

fn display(msg_bin: &Vec<u8>) {
    print_debug("---- Sending request: ----\n");
    print_debug(&format!("Dec: {:?}\n", msg_bin));
    print_debug("Bytes: \n");
    for b in msg_bin.iter() {
        print_debug(&format!("{:x} ", b));
    }
    print_debug("\n----\n");
}

pub fn print_debug(s: &str) {
    if !DEBUG_ENABLED {
        return;
    }

    print!("{}", s);
}

<commit_msg>Tidy.<commit_after>use std::io;
use std::time::Duration;
use std::net::{IpAddr, SocketAddr, UdpSocket, Ipv4Addr};

use request::RequestBin;
use response;
use response::Response;

const DEBUG_ENABLED: bool = false;

pub struct Network {}

/// Represents a device on the network, as well as a response.
pub struct Device {
    pub socket_addr: SocketAddr,
    pub response: Option<Response>,
}

impl Network {
    pub fn send_discover_devices(msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = true;
        let broadcast_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 0, 0));
        let broadcast_port = 56700;
        let broadcast_sock_addr = SocketAddr::new(broadcast_ip, broadcast_port);

        send(msg_bin, use_broadcast, broadcast_sock_addr)
    }
}

impl Device {
    pub fn send_get_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_get_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }
}

fn send(msg_bin: RequestBin,
        broadcast: bool,
        device_socket_addr: SocketAddr)
        -> Result<Device, io::Error> {
    let local_ip = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
    let local_sock_addr = SocketAddr::new(local_ip, 56700);
    let local_sock = UdpSocket::bind(local_sock_addr)?;
    let _ = local_sock.set_write_timeout(Some(Duration::new(3, 0)));
    let _ = local_sock.set_read_timeout(Some(Duration::new(3, 0)));
    local_sock.set_broadcast(broadcast)?;

    let msg = &msg_bin.0;
    display(msg);
    print_debug("** sending...");
    match local_sock.send_to(&msg, device_socket_addr) {
        Ok(v) => {
            print_debug(&format!("** sent {} bytes.", v));
        },
        Err(e) => {
            print_debug(&format!("** err sending: {}", e));
            return Err(e);
        },
    };

    // Read from the socket
    print_debug("** reading...");
    let mut resp_buf = [0; 1024];
    let (sz, src_sock_addr) = match local_sock.recv_from(&mut resp_buf) {
        Ok(v)   => {
            print_debug("** response read done");
            v
        },
        Err(e)  => {
            print_debug(&format!("** response read failed: {}", e));
            return Err(e);
        },
    };

    let resp_msg = &resp_buf[0..sz];
    print_debug(&format!("Received from {} : \n{:?}", src_sock_addr, resp_msg));

    let resp = response::parse_response(response::ResponseData(resp_msg.to_vec()));
    // let resp = response::parse_response(response::ResponseMessage(resp_msg.to_vec()));

    let device = Device {
        socket_addr: src_sock_addr,
        response: Some(resp),
    };

    Ok(device)
}

fn display(msg_bin: &[u8]) {
    print_debug("---- Sending request: ----\n");
    print_debug(&format!("Dec: {:?}\n", msg_bin));
    print_debug("Bytes: \n");
    for b in msg_bin.iter() {
        print_debug(&format!("{:x} ", b));
    }
    print_debug("\n----\n");
}

pub fn print_debug(s: &str) {
    if !DEBUG_ENABLED {
        return;
    }

    print!("{}", s);
}

<|endoftext|>


<commit_before>use super::{AssertionFailure, Spec};

use std::fmt::Debug;
use std::cmp::PartialOrd;

#[cfg(feature = "num")]
use num::Float;

pub trait OrderedAssertions<T>
    where T: Debug + PartialOrd
{
    fn is_less_than(&mut self, other: &T);
    fn is_less_than_or_equal_to(&mut self, other: &T);
    fn is_greater_than(&mut self, other: &T);
    fn is_greater_than_or_equal_to(&mut self, other: &T);
}

impl<'s, T> OrderedAssertions<T> for Spec<'s, T>
    where T: Debug + PartialOrd
{
    /// Asserts that the subject is less than the expected value. The subject type must
    /// implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&1).is_less_than(&2);
    /// ```
    fn is_less_than(&mut self, other: &T) {
        let subject = self.subject;

        if subject >= other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value less than <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is less than or equal to the expected value. The subject type
    /// must implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_less_than_or_equal_to(&2);
    /// ```
    fn is_less_than_or_equal_to(&mut self, other: &T) {
        let subject = self.subject;

        if subject > other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value less than or equal to <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is greater than the expected value. The subject type must
    /// implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_greater_than(&1);
    /// ```
    fn is_greater_than(&mut self, other: &T) {
        let subject = self.subject;

        if subject <= other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value greater than <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is greater than or equal to the expected value. The subject
    /// type must implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_greater_than_or_equal_to(&1);
    /// ```
    fn is_greater_than_or_equal_to(&mut self, other: &T) {
        let subject = self.subject;

        if subject < other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value greater than or equal to <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }
}

#[cfg(feature = "num")]
pub trait FloatAssertions<T: Float> {
    fn is_close_to(&mut self, expected: T, tolerance: T);
}

#[cfg(feature = "num")]
impl<'s, T: Float + Debug> FloatAssertions<T> for Spec<'s, T> {
    fn is_close_to(&mut self, expected: T, tolerance: T) {
        let subject = *self.subject;

        let difference = (subject - expected).abs();

        if !subject.is_finite() || difference > tolerance.abs() {
            AssertionFailure::from_spec(self)
                .with_expected(format!("float close to <{:?}> (tolerance of <{:?}>)",
                                       expected,
                                       tolerance))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    use num::Float;

    #[test]
    fn should_not_panic_if_value_is_less_than_expected() {
        assert_that(&1).is_less_than(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value less than <2>\n\t but was: <3>")]
    fn should_panic_if_value_is_greater_than_expected() {
        assert_that(&3).is_less_than(&2);
    }

    #[test]
    fn should_not_panic_if_value_is_less_than_or_equal_to_than_expected() {
        assert_that(&2).is_less_than_or_equal_to(&2);
        assert_that(&2).is_less_than_or_equal_to(&3);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value less than or equal to <2>\n\t but was: <3>")]
    fn should_panic_if_value_is_greater_than_or_not_equal_to_expected() {
        assert_that(&3).is_less_than_or_equal_to(&2);
    }

    #[test]
    fn should_not_panic_if_value_is_greater_than_expected() {
        assert_that(&3).is_greater_than(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value greater than <3>\n\t but was: <2>")]
    fn should_panic_if_value_is_less_than_expected() {
        assert_that(&2).is_greater_than(&3);
    }

    #[test]
    fn should_not_panic_if_value_is_greater_than_or_equal_to_expected() {
        assert_that(&3).is_greater_than_or_equal_to(&3);
        assert_that(&3).is_greater_than_or_equal_to(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value greater than or equal to <3>\n\t but was: <2>")]
    fn should_panic_if_value_is_less_than_or_not_equal_to_expected() {
        assert_that(&2).is_greater_than_or_equal_to(&3);
    }

    #[test]
    fn should_not_panic_if_float_exactly_matches() {
        assert_that(&2.0f64).is_close_to(2.0f64, 0.01f64);
        assert_that(&0f64).is_close_to(0f64, 0.01f64);
    }

    #[test]
    fn should_not_panic_if_float_is_close_to() {
        assert_that(&1e-40f32).is_close_to(0.0f32, 0.1f32);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <2>")]
    fn should_panic_if_float_is_not_close_to() {
        assert_that(&2.0f64).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <NaN>")]
    fn should_panic_if_float_is_nan() {
        assert_that(&Float::nan()).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <inf>")]
    fn should_panic_if_float_is_infinity() {
        assert_that(&Float::infinity()).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <-inf>")]
    fn should_panic_if_float_is_negative_infinity() {
        assert_that(&Float::neg_infinity()).is_close_to(1.0f64, 0.01f64);
    }
}
<commit_msg>Add rust doc for .is_close_to()<commit_after>use super::{AssertionFailure, Spec};

use std::fmt::Debug;
use std::cmp::PartialOrd;

#[cfg(feature = "num")]
use num::Float;

pub trait OrderedAssertions<T>
    where T: Debug + PartialOrd
{
    fn is_less_than(&mut self, other: &T);
    fn is_less_than_or_equal_to(&mut self, other: &T);
    fn is_greater_than(&mut self, other: &T);
    fn is_greater_than_or_equal_to(&mut self, other: &T);
}

impl<'s, T> OrderedAssertions<T> for Spec<'s, T>
    where T: Debug + PartialOrd
{
    /// Asserts that the subject is less than the expected value. The subject type must
    /// implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&1).is_less_than(&2);
    /// ```
    fn is_less_than(&mut self, other: &T) {
        let subject = self.subject;

        if subject >= other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value less than <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is less than or equal to the expected value. The subject type
    /// must implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_less_than_or_equal_to(&2);
    /// ```
    fn is_less_than_or_equal_to(&mut self, other: &T) {
        let subject = self.subject;

        if subject > other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value less than or equal to <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is greater than the expected value. The subject type must
    /// implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_greater_than(&1);
    /// ```
    fn is_greater_than(&mut self, other: &T) {
        let subject = self.subject;

        if subject <= other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value greater than <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }

    /// Asserts that the subject is greater than or equal to the expected value. The subject type
    /// must implement `PartialOrd`.
    ///
    /// ```rust,ignore
    /// assert_that(&2).is_greater_than_or_equal_to(&1);
    /// ```
    fn is_greater_than_or_equal_to(&mut self, other: &T) {
        let subject = self.subject;

        if subject < other {
            AssertionFailure::from_spec(self)
                .with_expected(format!("value greater than or equal to <{:?}>", other))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }
}

#[cfg(feature = "num")]
pub trait FloatAssertions<T: Float> {
    fn is_close_to(&mut self, expected: T, tolerance: T);
}

#[cfg(feature = "num")]
impl<'s, T: Float + Debug> FloatAssertions<T> for Spec<'s, T> {
    /// Asserts that the subject is close to the expected value by the specified tolerance.
    /// The subject type must implement `Float` and `Debug`.
    ///
    /// ```rust,ignore
    /// assert_that(&2.0f64).is_close_to(2.0f64, 0.01f64);
    /// ```
    fn is_close_to(&mut self, expected: T, tolerance: T) {
        let subject = *self.subject;

        let difference = (subject - expected).abs();

        if !subject.is_finite() || difference > tolerance.abs() {
            AssertionFailure::from_spec(self)
                .with_expected(format!("float close to <{:?}> (tolerance of <{:?}>)",
                                       expected,
                                       tolerance))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    use num::Float;

    #[test]
    fn should_not_panic_if_value_is_less_than_expected() {
        assert_that(&1).is_less_than(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value less than <2>\n\t but was: <3>")]
    fn should_panic_if_value_is_greater_than_expected() {
        assert_that(&3).is_less_than(&2);
    }

    #[test]
    fn should_not_panic_if_value_is_less_than_or_equal_to_than_expected() {
        assert_that(&2).is_less_than_or_equal_to(&2);
        assert_that(&2).is_less_than_or_equal_to(&3);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value less than or equal to <2>\n\t but was: <3>")]
    fn should_panic_if_value_is_greater_than_or_not_equal_to_expected() {
        assert_that(&3).is_less_than_or_equal_to(&2);
    }

    #[test]
    fn should_not_panic_if_value_is_greater_than_expected() {
        assert_that(&3).is_greater_than(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value greater than <3>\n\t but was: <2>")]
    fn should_panic_if_value_is_less_than_expected() {
        assert_that(&2).is_greater_than(&3);
    }

    #[test]
    fn should_not_panic_if_value_is_greater_than_or_equal_to_expected() {
        assert_that(&3).is_greater_than_or_equal_to(&3);
        assert_that(&3).is_greater_than_or_equal_to(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: value greater than or equal to <3>\n\t but was: <2>")]
    fn should_panic_if_value_is_less_than_or_not_equal_to_expected() {
        assert_that(&2).is_greater_than_or_equal_to(&3);
    }

    #[test]
    fn should_not_panic_if_float_exactly_matches() {
        assert_that(&2.0f64).is_close_to(2.0f64, 0.01f64);
        assert_that(&0f64).is_close_to(0f64, 0.01f64);
    }

    #[test]
    fn should_not_panic_if_float_is_close_to() {
        assert_that(&1e-40f32).is_close_to(0.0f32, 0.1f32);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <2>")]
    fn should_panic_if_float_is_not_close_to() {
        assert_that(&2.0f64).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <NaN>")]
    fn should_panic_if_float_is_nan() {
        assert_that(&Float::nan()).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <inf>")]
    fn should_panic_if_float_is_infinity() {
        assert_that(&Float::infinity()).is_close_to(1.0f64, 0.01f64);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: float close to <1> (tolerance of <0.01>)\
                   \n\t but was: <-inf>")]
    fn should_panic_if_float_is_negative_infinity() {
        assert_that(&Float::neg_infinity()).is_close_to(1.0f64, 0.01f64);
    }
}
<|endoftext|>


<commit_before>// TODO define all the lib things and linking stuff up here

// the glorious logging crate
#![feature(phase)]
#[phase(syntax, link)] extern crate log;
// holds references to HashMap
extern crate collections;
// need to pass the time info to
extern crate time;
// needed for some Encodable stuff
extern crate serialize;
// templating is provided by rust-mustache -- making that required in userland only!
// extern crate mustache;
// handles all the http stuff
extern crate http;
// used for holding the pcre struct in a mutable multithreaded way
extern crate sync;

// It turns out its real easy to reexport mods :D
// People that extern mod oxidize can use oxidize::reexported::mod;
pub use http::status;
pub use request::Request;
pub use conf::Config;
pub use http::server::ResponseWriter;
pub use http::headers::content_type::MediaType;

use http::server::{Server, ResponseWriter};
use http::server::request::{Star, AbsoluteUri, AbsolutePath, Authority};

use conf::Config;
use route::Router;
use sync::Arc;
use std::cell::RefCell;

pub mod route;
pub mod renderer;
pub mod request;
pub mod conf;

#[deriving(Clone)]
pub struct Oxidize {
    conf: Arc<Config>,
    router: RefCell<~Router>,
    // TODO: Add these other fields
    // db : &'a DatabaseThingy,
    // middleware :
    // template : &'a Template,
    // template_dir : Path, // should this be a part of Template?
    // add whatever other plugable things we wanna make
}

impl Oxidize {
    pub fn new(conf: Config, router: ~Router) -> Oxidize {
        Oxidize {
            conf: Arc::new(conf),
            router: RefCell::new(router),
        }
    }

    pub fn serve(self) {
        debug!("Server is now running at {}", self.conf.bind_addr.to_str());
        self.serve_forever();
    }

}

impl Server for Oxidize {
    fn get_config(&self) -> http::server::Config {
        let bind_addr = self.conf.bind_addr;
        http::server::Config { bind_address: bind_addr }
    }

    fn handle_request(&self, req: &http::server::Request, response: &mut ResponseWriter) {
        response.headers.date = Some(time::now_utc());
        response.headers.server = Some(~"Oxidize/0.0.0 (Ubuntu)");

        // create a request object
        let path = match req.request_uri {
            AbsolutePath(ref i) => i.to_str(),
            AbsoluteUri(ref i) => i.to_str(),
            Authority(ref i) => i.to_str(),
            Star => ~"error" // ?
        };
        let test_method = match from_str("GET") {
            Some(m) => m,
            None => http::method::Get
        };
        let my_request = &mut request::Request {
            method: test_method,
            uri: path,
            GET : None,
            POST : None,
            context : None,
            router : self.router.borrow()
        };

        // self.router.with(|r: &~Router| {r.route(my_request, response);});
        self.router.get().route(my_request, response);
    }
}
<commit_msg>Removed some bad comments<commit_after>// TODO define all the lib things and linking stuff up here

// the glorious logging crate
#![feature(phase)]
#[phase(syntax, link)] extern crate log;
// holds references to HashMap
extern crate collections;
// need to pass the time info to
extern crate time;
// needed for some Encodable stuff
extern crate serialize;
// templating is provided by rust-mustache -- making that required in userland only!
// extern crate mustache;
// handles all the http stuff
extern crate http;
// used for holding the pcre struct in a mutable multithreaded way
extern crate sync;

// It turns out its real easy to reexport mods :D
// People that extern mod oxidize can use oxidize::reexported::mod;
pub use http::status;
pub use request::Request;
pub use conf::Config;
pub use http::server::ResponseWriter;
pub use http::headers::content_type::MediaType;

use http::server::{Server, ResponseWriter};
use http::server::request::{Star, AbsoluteUri, AbsolutePath, Authority};

use conf::Config;
use route::Router;
use sync::Arc;
use std::cell::RefCell;

pub mod route;
pub mod renderer;
pub mod request;
pub mod conf;

#[deriving(Clone)]
pub struct Oxidize {
    conf: Arc<Config>,
    router: RefCell<~Router>,
}

impl Oxidize {
    pub fn new(conf: Config, router: ~Router) -> Oxidize {
        Oxidize {
            conf: Arc::new(conf),
            router: RefCell::new(router),
        }
    }

    pub fn serve(self) {
        debug!("Server is now running at {}", self.conf.bind_addr.to_str());
        self.serve_forever();
    }

}

impl Server for Oxidize {
    fn get_config(&self) -> http::server::Config {
        let bind_addr = self.conf.bind_addr;
        http::server::Config { bind_address: bind_addr }
    }

    fn handle_request(&self, req: &http::server::Request, response: &mut ResponseWriter) {
        response.headers.date = Some(time::now_utc());
        response.headers.server = Some(~"Oxidize/0.0.0 (Ubuntu)");

        // create a request object
        let path = match req.request_uri {
            AbsolutePath(ref i) => i.to_str(),
            AbsoluteUri(ref i) => i.to_str(),
            Authority(ref i) => i.to_str(),
            Star => ~"error" // ?
        };
        let test_method = match from_str("GET") {
            Some(m) => m,
            None => http::method::Get
        };
        let my_request = &mut request::Request {
            method: test_method,
            uri: path,
            GET : None,
            POST : None,
            context : None,
            router : self.router.borrow()
        };

        // self.router.with(|r: &~Router| {r.route(my_request, response);});
        self.router.get().route(my_request, response);
    }
}
<|endoftext|>


<commit_before>extern crate num;
use self::num::complex::Complex32;

/// describes a sinusoidal of the form:
/// y = coeff * exp(i*ang_freq*t) * u(t - start_usec)
/// where u(t) is the unit step function,
/// and coeff is a complex exponential, which is used to encode both the
/// amplitude and phase shift of the sinusoid.
pub struct Partial {
    /// time at which the partial should be gated on, in microseconds
    start_usec : u64,
    /// complex amplitude coefficient
    coeff : Complex32,
    /// frequency of the sinusoid, in radians/second
    ang_freq : f32,
    /// index of the stereo/surround channel that this wave occupies
    /// e.g. 0 for left, 1 for right.
    channel : u8,
}

impl Partial {
    pub fn new() -> Partial {
        Partial{ start_usec:0, coeff:Complex32::new(0.0f32, 0.0f32), ang_freq:0.0f32, channel:0 }
    }
}<commit_msg>Make Partial copy/clone-able<commit_after>extern crate num;
use self::num::complex::Complex32;

/// describes a sinusoidal of the form:
/// y = coeff * exp(i*ang_freq*t) * u(t - start_usec)
/// where u(t) is the unit step function,
/// and coeff is a complex exponential, which is used to encode both the
/// amplitude and phase shift of the sinusoid.
#[derive(Copy, Clone)]
pub struct Partial {
    /// time at which the partial should be gated on, in microseconds
    start_usec : u64,
    /// complex amplitude coefficient
    coeff : Complex32,
    /// frequency of the sinusoid, in radians/second
    ang_freq : f32,
    /// index of the stereo/surround channel that this wave occupies
    /// e.g. 0 for left, 1 for right.
    channel : u8,
}

impl Partial {
    pub fn new() -> Partial {
        Partial{ start_usec:0, coeff:Complex32::new(0.0f32, 0.0f32), ang_freq:0.0f32, channel:0 }
    }
}<|endoftext|>