<commit_before>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::time::{SystemTime, Duration};
use std::thread::{self, JoinHandle, Builder};
use std::sync::mpsc::{self, Sender};
use std::ops::{Add, Sub};
use std::cmp::Ordering;

use time::{Timespec, Duration as TimeDuration};

/// Convert Duration to milliseconds.
#[inline]
pub fn duration_to_ms(d: Duration) -> u64 {
    let nanos = d.subsec_nanos() as u64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() * 1_000 + (nanos / 1_000_000)
}

/// Convert Duration to seconds.
#[inline]
pub fn duration_to_sec(d: Duration) -> f64 {
    let nanos = d.subsec_nanos() as f64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() as f64 + (nanos / 1_000_000_000.0)
}

/// Convert Duration to nanoseconds.
#[inline]
pub fn duration_to_nanos(d: Duration) -> u64 {
    let nanos = d.subsec_nanos() as u64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() * 1_000_000_000 + nanos
}

pub struct SlowTimer {
    slow_time: Duration,
    t: Instant,
}

impl SlowTimer {
    pub fn new() -> SlowTimer {
        SlowTimer::default()
    }

    pub fn from(slow_time: Duration) -> SlowTimer {
        SlowTimer {
            slow_time: slow_time,
            t: Instant::now_coarse(),
        }
    }

    pub fn from_secs(secs: u64) -> SlowTimer {
        SlowTimer::from(Duration::from_secs(secs))
    }

    pub fn from_millis(millis: u64) -> SlowTimer {
        SlowTimer::from(Duration::from_millis(millis))
    }

    pub fn elapsed(&self) -> Duration {
        self.t.elapsed()
    }

    pub fn is_slow(&self) -> bool {
        self.elapsed() >= self.slow_time
    }
}

const DEFAULT_SLOW_SECS: u64 = 1;

impl Default for SlowTimer {
    fn default() -> SlowTimer {
        SlowTimer::from_secs(DEFAULT_SLOW_SECS)
    }
}

const DEFAULT_WAIT_MS: u64 = 100;

pub struct Monitor {
    tx: Sender<bool>,
    handle: Option<JoinHandle<()>>,
}

impl Monitor {
    pub fn new<D, N>(on_jumped: D, now: N) -> Monitor
        where D: Fn() + Send + 'static,
              N: Fn() -> SystemTime + Send + 'static
    {
        let (tx, rx) = mpsc::channel();
        let h = Builder::new()
            .name(thd_name!("time-monitor-worker"))
            .spawn(move || {
                while let Err(_) = rx.try_recv() {
                    let before = now();
                    thread::sleep(Duration::from_millis(DEFAULT_WAIT_MS));

                    let after = now();
                    if let Err(e) = after.duration_since(before) {
                        error!("system time jumped back, {:?} -> {:?}, err {:?}",
                               before,
                               after,
                               e);
                        on_jumped()
                    }
                }
            })
            .unwrap();

        Monitor {
            tx: tx,
            handle: Some(h),
        }
    }
}

impl Default for Monitor {
    fn default() -> Monitor {
        Monitor::new(|| {}, SystemTime::now)
    }
}

impl Drop for Monitor {
    fn drop(&mut self) {
        let h = self.handle.take();
        if h.is_none() {
            return;
        }

        if let Err(e) = self.tx.send(true) {
            error!("send quit message for time monitor worker failed {:?}", e);
            return;
        }

        if let Err(e) = h.unwrap().join() {
            error!("join time monitor worker failed {:?}", e);
            return;
        }
    }
}

#[inline]
fn elapsed_duration(later: Timespec, earlier: Timespec) -> Duration {
    if later >= earlier {
        Duration::new((later.sec - earlier.sec) as u64,
                      (later.nsec - earlier.nsec) as u32)
    } else {
        panic!("system time jumped back, {:.9} -> {:.9}",
               earlier.sec as f64 + earlier.nsec as f64 / NANOSECONDS_PER_SECOND as f64,
               later.sec as f64 + later.nsec as f64 / NANOSECONDS_PER_SECOND as f64);
    }
}

/// `monotonic_raw_now` returns the monotonic raw time since some unspecified starting point.
pub use self::inner::monotonic_raw_now;
use self::inner::monotonic_now;
use self::inner::monotonic_coarse_now;

const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;

#[cfg(not(target_os = "linux"))]
mod inner {
    use time::{self, Timespec};
    use super::NANOSECONDS_PER_SECOND;

    pub fn monotonic_raw_now() -> Timespec {
        // TODO Add monotonic raw clock time impl for macos and windows
        // Currently use `time::get_precise_ns()` instead.
        let ns = time::precise_time_ns();
        let s = ns / NANOSECONDS_PER_SECOND;
        let ns = ns % NANOSECONDS_PER_SECOND;
        Timespec::new(s as i64, ns as i32)
    }

    pub fn monotonic_now() -> Timespec {
        // TODO Add monotonic clock time impl for macos and windows
        monotonic_raw_now()
    }

    pub fn monotonic_coarse_now() -> Timespec {
        // TODO Add monotonic coarse clock time impl for macos and windows
        monotonic_raw_now()
    }
}

#[cfg(target_os = "linux")]
mod inner {
    use std::io;
    use time::Timespec;
    use libc;

    pub fn monotonic_raw_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC_RAW)
    }

    pub fn monotonic_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC)
    }

    pub fn monotonic_coarse_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC_COARSE)
    }

    fn get_time(clock: libc::clockid_t) -> Timespec {
        let mut t = libc::timespec {
            tv_sec: 0,
            tv_nsec: 0,
        };
        let errno = unsafe { libc::clock_gettime(clock, &mut t) };
        if errno != 0 {
            panic!("failed to get monotonic raw locktime, err {}",
                   io::Error::last_os_error());
        }
        Timespec::new(t.tv_sec, t.tv_nsec as _)
    }
}

/// A measurement of a monotonically increasing clock.
/// It's similar and meat to replace `std::time::Instant`,
/// for providing extra features.
#[derive(Copy, Clone, Debug, Eq)]
pub enum Instant {
    Monotonic(Timespec),
    MonotonicCoarse(Timespec),
}

impl Instant {
    pub fn now() -> Instant {
        Instant::Monotonic(monotonic_now())
    }

    pub fn now_coarse() -> Instant {
        Instant::MonotonicCoarse(monotonic_coarse_now())
    }

    pub fn elapsed(&self) -> Duration {
        match *self {
            Instant::Monotonic(t) => {
                let now = monotonic_now();
                elapsed_duration(now, t)
            }
            Instant::MonotonicCoarse(t) => {
                let now = monotonic_coarse_now();
                elapsed_duration(now, t)
            }
        }
    }

    pub fn duration_since(&self, earlier: Instant) -> Duration {
        let later = self.get_timespec();
        let earlier = earlier.get_timespec();
        elapsed_duration(later, earlier)
    }

    fn get_timespec(&self) -> Timespec {
        match *self {
            Instant::Monotonic(t) |
            Instant::MonotonicCoarse(t) => t,
        }
    }
}

impl PartialEq for Instant {
    fn eq(&self, other: &Instant) -> bool {
        self.get_timespec().eq(&other.get_timespec())
    }
}

impl Ord for Instant {
    fn cmp(&self, other: &Instant) -> Ordering {
        self.get_timespec().cmp(&other.get_timespec())
    }
}

impl PartialOrd for Instant {
    fn partial_cmp(&self, other: &Instant) -> Option<Ordering> {
        self.get_timespec().partial_cmp(&other.get_timespec())
    }
}

impl Add<Duration> for Instant {
    type Output = Instant;

    fn add(self, other: Duration) -> Instant {
        match self {
            Instant::Monotonic(t) => Instant::Monotonic(t + TimeDuration::from_std(other).unwrap()),
            Instant::MonotonicCoarse(t) => {
                Instant::MonotonicCoarse(t + TimeDuration::from_std(other).unwrap())
            }
        }
    }
}

impl Sub<Duration> for Instant {
    type Output = Instant;

    fn sub(self, other: Duration) -> Instant {
        match self {
            Instant::Monotonic(t) => Instant::Monotonic(t - TimeDuration::from_std(other).unwrap()),
            Instant::MonotonicCoarse(t) => {
                Instant::MonotonicCoarse(t - TimeDuration::from_std(other).unwrap())
            }
        }
    }
}

impl Sub<Instant> for Instant {
    type Output = Duration;

    fn sub(self, other: Instant) -> Duration {
        self.duration_since(other)
    }
}

#[cfg(test)]
mod tests {
    use std::time::{SystemTime, Duration};
    use std::thread;
    use std::ops::Sub;
    use std::f64;
    use super::*;

    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::Arc;

    #[test]
    fn test_time_monitor() {
        let jumped = Arc::new(AtomicBool::new(false));
        let triggered = AtomicBool::new(false);
        let now = move || {
            if !triggered.load(Ordering::SeqCst) {
                triggered.store(true, Ordering::SeqCst);
                SystemTime::now()
            } else {
                SystemTime::now().sub(Duration::from_secs(2))
            }
        };

        let jumped2 = jumped.clone();
        let on_jumped = move || {
            jumped2.store(true, Ordering::SeqCst);
        };

        let _m = Monitor::new(on_jumped, now);
        thread::sleep(Duration::from_secs(1));

        assert_eq!(jumped.load(Ordering::SeqCst), true);
    }

    #[test]
    fn test_duration_to() {
        let tbl = vec![0, 100, 1_000, 5_000, 9999, 1_000_000, 1_000_000_000];
        for ms in tbl {
            let d = Duration::from_millis(ms);
            assert_eq!(ms, duration_to_ms(d));
            let exp_sec = ms as f64 / 1000.0;
            let act_sec = duration_to_sec(d);
            assert!((act_sec - exp_sec).abs() < f64::EPSILON);
            assert_eq!(ms * 1_000_000, duration_to_nanos(d));
        }
    }

    #[test]
    fn test_now() {
        let pairs = vec![
            (monotonic_raw_now(), monotonic_raw_now()),
            (monotonic_now(), monotonic_now()),
            (monotonic_coarse_now(), monotonic_coarse_now()),
        ];
        for (early_time, late_time) in pairs {
            // The monotonic clocktime must be strictly monotonic increasing.
            assert!(late_time >= early_time,
                    "expect late time {:?} >= early time {:?}",
                    late_time,
                    early_time);
        }
    }

    #[test]
    #[allow(eq_op)]
    fn test_instant() {
        Instant::now().elapsed();
        Instant::now_coarse().elapsed();

        // Ordering.
        let early_raw = Instant::now();
        let late_raw = Instant::now();
        assert!(early_raw <= late_raw);
        assert!(late_raw >= early_raw);

        assert_eq!(early_raw, early_raw);
        assert!(early_raw >= early_raw);
        assert!(early_raw <= early_raw);

        let early_coarse = Instant::now_coarse();
        let late_coarse = Instant::now_coarse();
        assert!(late_coarse >= early_coarse);
        assert!(early_coarse <= late_coarse);

        assert_eq!(early_coarse, early_coarse);
        assert!(early_coarse >= early_coarse);
        assert!(early_coarse <= early_coarse);

        let zero = Duration::new(0, 0);
        // Sub Instant.
        assert!(late_raw - early_raw > zero);
        assert!(late_coarse - early_coarse >= zero);

        // Sub Duration.
        assert_eq!(late_raw - zero, late_raw);
        assert_eq!(late_coarse - zero, late_coarse);

        // Add Duration.
        assert_eq!(late_raw + zero, late_raw);
        assert_eq!(late_coarse + zero, late_coarse);
    }
}
<commit_msg>util/time: use millisecond resolution for coarse Instant (#2165)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::time::{SystemTime, Duration};
use std::thread::{self, JoinHandle, Builder};
use std::sync::mpsc::{self, Sender};
use std::ops::{Add, Sub};
use std::cmp::Ordering;

use time::{Timespec, Duration as TimeDuration};

/// Convert Duration to milliseconds.
#[inline]
pub fn duration_to_ms(d: Duration) -> u64 {
    let nanos = d.subsec_nanos() as u64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() * 1_000 + (nanos / 1_000_000)
}

/// Convert Duration to seconds.
#[inline]
pub fn duration_to_sec(d: Duration) -> f64 {
    let nanos = d.subsec_nanos() as f64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() as f64 + (nanos / 1_000_000_000.0)
}

/// Convert Duration to nanoseconds.
#[inline]
pub fn duration_to_nanos(d: Duration) -> u64 {
    let nanos = d.subsec_nanos() as u64;
    // Most of case, we can't have so large Duration, so here just panic if overflow now.
    d.as_secs() * 1_000_000_000 + nanos
}

pub struct SlowTimer {
    slow_time: Duration,
    t: Instant,
}

impl SlowTimer {
    pub fn new() -> SlowTimer {
        SlowTimer::default()
    }

    pub fn from(slow_time: Duration) -> SlowTimer {
        SlowTimer {
            slow_time: slow_time,
            t: Instant::now_coarse(),
        }
    }

    pub fn from_secs(secs: u64) -> SlowTimer {
        SlowTimer::from(Duration::from_secs(secs))
    }

    pub fn from_millis(millis: u64) -> SlowTimer {
        SlowTimer::from(Duration::from_millis(millis))
    }

    pub fn elapsed(&self) -> Duration {
        self.t.elapsed()
    }

    pub fn is_slow(&self) -> bool {
        self.elapsed() >= self.slow_time
    }
}

const DEFAULT_SLOW_SECS: u64 = 1;

impl Default for SlowTimer {
    fn default() -> SlowTimer {
        SlowTimer::from_secs(DEFAULT_SLOW_SECS)
    }
}

const DEFAULT_WAIT_MS: u64 = 100;

pub struct Monitor {
    tx: Sender<bool>,
    handle: Option<JoinHandle<()>>,
}

impl Monitor {
    pub fn new<D, N>(on_jumped: D, now: N) -> Monitor
        where D: Fn() + Send + 'static,
              N: Fn() -> SystemTime + Send + 'static
    {
        let (tx, rx) = mpsc::channel();
        let h = Builder::new()
            .name(thd_name!("time-monitor-worker"))
            .spawn(move || {
                while let Err(_) = rx.try_recv() {
                    let before = now();
                    thread::sleep(Duration::from_millis(DEFAULT_WAIT_MS));

                    let after = now();
                    if let Err(e) = after.duration_since(before) {
                        error!("system time jumped back, {:?} -> {:?}, err {:?}",
                               before,
                               after,
                               e);
                        on_jumped()
                    }
                }
            })
            .unwrap();

        Monitor {
            tx: tx,
            handle: Some(h),
        }
    }
}

impl Default for Monitor {
    fn default() -> Monitor {
        Monitor::new(|| {}, SystemTime::now)
    }
}

impl Drop for Monitor {
    fn drop(&mut self) {
        let h = self.handle.take();
        if h.is_none() {
            return;
        }

        if let Err(e) = self.tx.send(true) {
            error!("send quit message for time monitor worker failed {:?}", e);
            return;
        }

        if let Err(e) = h.unwrap().join() {
            error!("join time monitor worker failed {:?}", e);
            return;
        }
    }
}

/// `monotonic_raw_now` returns the monotonic raw time since some unspecified starting point.
pub use self::inner::monotonic_raw_now;
use self::inner::monotonic_now;
use self::inner::monotonic_coarse_now;

const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;
const MILLISECOND_PER_SECOND: i64 = 1_000;
const NANOSECONDS_PER_MILLISECOND: i32 = 1_000_000;

#[cfg(not(target_os = "linux"))]
mod inner {
    use time::{self, Timespec};
    use super::NANOSECONDS_PER_SECOND;

    pub fn monotonic_raw_now() -> Timespec {
        // TODO Add monotonic raw clock time impl for macos and windows
        // Currently use `time::get_precise_ns()` instead.
        let ns = time::precise_time_ns();
        let s = ns / NANOSECONDS_PER_SECOND;
        let ns = ns % NANOSECONDS_PER_SECOND;
        Timespec::new(s as i64, ns as i32)
    }

    pub fn monotonic_now() -> Timespec {
        // TODO Add monotonic clock time impl for macos and windows
        monotonic_raw_now()
    }

    pub fn monotonic_coarse_now() -> Timespec {
        // TODO Add monotonic coarse clock time impl for macos and windows
        monotonic_raw_now()
    }
}

#[cfg(target_os = "linux")]
mod inner {
    use std::io;
    use time::Timespec;
    use libc;

    pub fn monotonic_raw_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC_RAW)
    }

    pub fn monotonic_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC)
    }

    pub fn monotonic_coarse_now() -> Timespec {
        get_time(libc::CLOCK_MONOTONIC_COARSE)
    }

    fn get_time(clock: libc::clockid_t) -> Timespec {
        let mut t = libc::timespec {
            tv_sec: 0,
            tv_nsec: 0,
        };
        let errno = unsafe { libc::clock_gettime(clock, &mut t) };
        if errno != 0 {
            panic!("failed to get monotonic raw locktime, err {}",
                   io::Error::last_os_error());
        }
        Timespec::new(t.tv_sec, t.tv_nsec as _)
    }
}

/// A measurement of a monotonically increasing clock.
/// It's similar and meat to replace `std::time::Instant`,
/// for providing extra features.
#[derive(Copy, Clone, Debug)]
pub enum Instant {
    Monotonic(Timespec),
    MonotonicCoarse(Timespec),
}

impl Instant {
    pub fn now() -> Instant {
        Instant::Monotonic(monotonic_now())
    }

    pub fn now_coarse() -> Instant {
        Instant::MonotonicCoarse(monotonic_coarse_now())
    }

    pub fn elapsed(&self) -> Duration {
        match *self {
            Instant::Monotonic(t) => {
                let now = monotonic_now();
                Instant::elapsed_duration(now, t)
            }
            Instant::MonotonicCoarse(t) => {
                let now = monotonic_coarse_now();
                Instant::elapsed_duration_coarse(now, t)
            }
        }
    }

    pub fn duration_since(&self, earlier: Instant) -> Duration {
        match (*self, earlier) {
            (Instant::Monotonic(later), Instant::Monotonic(earlier)) => {
                Instant::elapsed_duration(later, earlier)
            }
            (Instant::MonotonicCoarse(later), Instant::MonotonicCoarse(earlier)) => {
                Instant::elapsed_duration_coarse(later, earlier)
            }
            _ => {
                panic!("duration between different types of Instants");
            }
        }
    }

    fn elapsed_duration(later: Timespec, earlier: Timespec) -> Duration {
        if later >= earlier {
            (later - earlier).to_std().unwrap()
        } else {
            panic!("system time jumped back, {:.9} -> {:.9}",
                   earlier.sec as f64 + earlier.nsec as f64 / NANOSECONDS_PER_SECOND as f64,
                   later.sec as f64 + later.nsec as f64 / NANOSECONDS_PER_SECOND as f64);
        }
    }

    // It is different from `elapsed_duration`, the resolution here is millisecond.
    // The processors in an SMP system do not start all at exactly the same time
    // and therefore the timer registers are typically running at an offset.
    // Use millisecond resolution for ignoring the error.
    fn elapsed_duration_coarse(later: Timespec, earlier: Timespec) -> Duration {
        let later_ms = later.sec * MILLISECOND_PER_SECOND +
                       (later.nsec / NANOSECONDS_PER_MILLISECOND) as i64;
        let earlier_ms = earlier.sec * MILLISECOND_PER_SECOND +
                         (earlier.nsec / NANOSECONDS_PER_MILLISECOND) as i64;
        if later_ms >= earlier_ms {
            Duration::from_millis((later_ms - earlier_ms) as u64)
        } else {
            panic!("system time jumped back, {:.3} -> {:.3}",
                   earlier.sec as f64 + earlier.nsec as f64 / NANOSECONDS_PER_SECOND as f64,
                   later.sec as f64 + later.nsec as f64 / NANOSECONDS_PER_SECOND as f64);
        }
    }
}

impl PartialEq for Instant {
    fn eq(&self, other: &Instant) -> bool {
        match (*self, *other) {
            (Instant::Monotonic(this), Instant::Monotonic(other)) |
            (Instant::MonotonicCoarse(this), Instant::MonotonicCoarse(other)) => this.eq(&other),
            _ => false,
        }
    }
}

impl PartialOrd for Instant {
    fn partial_cmp(&self, other: &Instant) -> Option<Ordering> {
        match (*self, *other) {
            (Instant::Monotonic(this), Instant::Monotonic(other)) |
            (Instant::MonotonicCoarse(this), Instant::MonotonicCoarse(other)) => {
                this.partial_cmp(&other)
            }
            // The Order of different types of Instants is meaningless.
            _ => None,
        }
    }
}

impl Add<Duration> for Instant {
    type Output = Instant;

    fn add(self, other: Duration) -> Instant {
        match self {
            Instant::Monotonic(t) => Instant::Monotonic(t + TimeDuration::from_std(other).unwrap()),
            Instant::MonotonicCoarse(t) => {
                Instant::MonotonicCoarse(t + TimeDuration::from_std(other).unwrap())
            }
        }
    }
}

impl Sub<Duration> for Instant {
    type Output = Instant;

    fn sub(self, other: Duration) -> Instant {
        match self {
            Instant::Monotonic(t) => Instant::Monotonic(t - TimeDuration::from_std(other).unwrap()),
            Instant::MonotonicCoarse(t) => {
                Instant::MonotonicCoarse(t - TimeDuration::from_std(other).unwrap())
            }
        }
    }
}

impl Sub<Instant> for Instant {
    type Output = Duration;

    fn sub(self, other: Instant) -> Duration {
        self.duration_since(other)
    }
}

#[cfg(test)]
mod tests {
    use std::time::{SystemTime, Duration};
    use std::thread;
    use std::ops::Sub;
    use std::f64;
    use super::*;

    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::Arc;

    #[test]
    fn test_time_monitor() {
        let jumped = Arc::new(AtomicBool::new(false));
        let triggered = AtomicBool::new(false);
        let now = move || {
            if !triggered.load(Ordering::SeqCst) {
                triggered.store(true, Ordering::SeqCst);
                SystemTime::now()
            } else {
                SystemTime::now().sub(Duration::from_secs(2))
            }
        };

        let jumped2 = jumped.clone();
        let on_jumped = move || {
            jumped2.store(true, Ordering::SeqCst);
        };

        let _m = Monitor::new(on_jumped, now);
        thread::sleep(Duration::from_secs(1));

        assert_eq!(jumped.load(Ordering::SeqCst), true);
    }

    #[test]
    fn test_duration_to() {
        let tbl = vec![0, 100, 1_000, 5_000, 9999, 1_000_000, 1_000_000_000];
        for ms in tbl {
            let d = Duration::from_millis(ms);
            assert_eq!(ms, duration_to_ms(d));
            let exp_sec = ms as f64 / 1000.0;
            let act_sec = duration_to_sec(d);
            assert!((act_sec - exp_sec).abs() < f64::EPSILON);
            assert_eq!(ms * 1_000_000, duration_to_nanos(d));
        }
    }

    #[test]
    fn test_now() {
        let pairs = vec![
            (monotonic_raw_now(), monotonic_raw_now()),
            (monotonic_now(), monotonic_now()),
            (monotonic_coarse_now(), monotonic_coarse_now()),
        ];
        for (early_time, late_time) in pairs {
            // The monotonic clocktime must be strictly monotonic increasing.
            assert!(late_time >= early_time,
                    "expect late time {:?} >= early time {:?}",
                    late_time,
                    early_time);
        }
    }

    #[test]
    #[allow(eq_op)]
    fn test_instant() {
        Instant::now().elapsed();
        Instant::now_coarse().elapsed();

        // Ordering.
        let early_raw = Instant::now();
        let late_raw = Instant::now();
        assert!(early_raw <= late_raw);
        assert!(late_raw >= early_raw);

        assert_eq!(early_raw, early_raw);
        assert!(early_raw >= early_raw);
        assert!(early_raw <= early_raw);

        let early_coarse = Instant::now_coarse();
        let late_coarse = Instant::now_coarse();
        assert!(late_coarse >= early_coarse);
        assert!(early_coarse <= late_coarse);

        assert_eq!(early_coarse, early_coarse);
        assert!(early_coarse >= early_coarse);
        assert!(early_coarse <= early_coarse);

        let zero = Duration::new(0, 0);
        // Sub Instant.
        assert!(late_raw - early_raw > zero);
        assert!(late_coarse - early_coarse >= zero);

        // Sub Duration.
        assert_eq!(late_raw - zero, late_raw);
        assert_eq!(late_coarse - zero, late_coarse);

        // Add Duration.
        assert_eq!(late_raw + zero, late_raw);
        assert_eq!(late_coarse + zero, late_coarse);

        // PartialEq and PartialOrd
        let ts = Timespec::new(1, 1);
        let now1 = Instant::Monotonic(ts);
        let now2 = Instant::MonotonicCoarse(ts);
        assert_ne!(now1, now2);
        assert_eq!(now1.partial_cmp(&now2), None);
    }

    #[test]
    fn test_coarse_instant_on_smp() {
        for i in 0..100000 {
            let now = Instant::now_coarse();
            if i % 100 == 0 {
                thread::yield_now();
            }
            now.elapsed();
        }
    }
}
<|endoftext|>


<commit_before>//! Write DWARF debugging information.
//!
//! ## API Structure
//!
//! This module works by building up a representation of the debugging information
//! in memory, and then writing it all at once. It supports two major use cases:
//!
//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF
//! for a single compilation unit.
//!
//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple
//! compilation units.
//!
//! The module also supports reading in DWARF debugging information and writing it out
//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html)
//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert
//! it to a writable instance.

use std::error;
use std::fmt;
use std::result;

mod endian_vec;
pub use self::endian_vec::*;

mod writer;
pub use self::writer::*;

#[macro_use]
mod section;
pub use self::section::*;

macro_rules! define_id {
    ($name:ident, $docs:expr) => {
        #[doc=$docs]
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        pub struct $name {
            base_id: BaseId,
            index: usize,
        }

        impl $name {
            #[inline]
            fn new(base_id: BaseId, index: usize) -> Self {
                $name { base_id, index }
            }
        }
    };
}

macro_rules! define_offsets {
    ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => {
        #[doc=$off_doc]
        #[derive(Debug)]
        pub struct $offsets {
            base_id: BaseId,
            // We know ids start at 0.
            offsets: Vec<$offset>,
        }

        impl $offsets {
            /// Return an empty list of offsets.
            #[inline]
            pub fn none() -> Self {
                $offsets {
                    base_id: BaseId::default(),
                    offsets: Vec::new(),
                }
            }

            /// Get the offset
            ///
            /// # Panics
            ///
            /// Panics if `id` is invalid.
            #[inline]
            pub fn get(&self, id: $id) -> $offset {
                debug_assert_eq!(self.base_id, id.base_id);
                self.offsets[id.index]
            }

            /// Return the number of offsets.
            #[inline]
            pub fn count(&self) -> usize {
                self.offsets.len()
            }
        }
    };
}

mod dwarf;
pub use self::dwarf::*;

mod abbrev;
pub use self::abbrev::*;

mod line;
pub use self::line::*;

mod str;
pub use self::str::*;

mod unit;
pub use self::unit::*;

mod range;
pub use self::range::*;

/// An error that occurred when writing.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
    /// The given offset is out of bounds.
    OffsetOutOfBounds,
    /// The given length is out of bounds.
    LengthOutOfBounds,
    /// The attribute value is an invalid for writing.
    InvalidAttributeValue,
    /// The value is too large for the encoding form.
    ValueTooLarge,
    /// Unsupported word size.
    UnsupportedWordSize(u8),
    /// Unsupported DWARF version.
    UnsupportedVersion(u16),
    /// The unit length is too large for the requested DWARF format.
    InitialLengthOverflow,
    /// The address is invalid.
    InvalidAddress,
    /// A requested feature requires a different DWARF version.
    NeedVersion(u16),
    /// Strings in line number program have mismatched forms.
    LineStringFormMismatch,
    /// The range is empty or otherwise invalid.
    InvalidRange,
    /// The line number program encoding is incompatible with the unit encoding.
    IncompatibleLineProgramEncoding,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."),
            Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."),
            Error::InvalidAttributeValue => {
                write!(f, "The attribute value is an invalid for writing.")
            }
            Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."),
            Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size),
            Error::UnsupportedVersion(version) => {
                write!(f, "Unsupported DWARF version: {}", version)
            }
            Error::InitialLengthOverflow => write!(
                f,
                "The unit length is too large for the requested DWARF format."
            ),
            Error::InvalidAddress => write!(f, "The address is invalid."),
            Error::NeedVersion(version) => write!(
                f,
                "A requested feature requires a DWARF version {}.",
                version
            ),
            Error::LineStringFormMismatch => {
                write!(f, "Strings in line number program have mismatched forms.")
            }
            Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."),
            Error::IncompatibleLineProgramEncoding => write!(
                f,
                "The line number program encoding is incompatible with the unit encoding."
            ),
        }
    }
}

impl error::Error for Error {}

/// The result of a write.
pub type Result<T> = result::Result<T, Error>;

/// An address.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Address {
    /// An absolute address that does not require relocation.
    Absolute(u64),
    /// An address that is relative to a symbol which may be relocated.
    Relative {
        /// The symbol that the address is relative to.
        ///
        /// The meaning of this value is decided by the writer, but
        /// will typically be an index into a symbol table.
        symbol: usize,
        /// The offset of the address relative to the symbol.
        ///
        /// This will typically be used as the addend in a relocation.
        addend: i64,
    },
}

// This type is only used in debug assertions.
#[cfg(not(debug_assertions))]
type BaseId = ();

#[cfg(debug_assertions)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct BaseId(usize);

#[cfg(debug_assertions)]
impl Default for BaseId {
    fn default() -> Self {
        use std::sync::atomic;
        static BASE_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
        BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed))
    }
}

#[cfg(feature = "read")]
mod convert {
    use super::*;
    use read;

    pub(crate) use super::unit::convert::*;

    /// An error that occurred when converting a read value into a write value.
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum ConvertError {
        /// An error occurred when reading.
        Read(read::Error),
        /// Writing of this attribute value is not implemented yet.
        UnsupportedAttributeValue,
        /// This attribute value is an invalid name/form combination.
        InvalidAttributeValue,
        /// A `.debug_info` reference does not refer to a valid entry.
        InvalidDebugInfoOffset,
        /// An address could not be converted.
        InvalidAddress,
        /// The line number program is missing the compilation directory.
        MissingCompilationDirectory,
        /// The line number program is missing the compilation file.
        MissingCompilationFile,
        /// Writing this line number instruction is not implemented yet.
        UnsupportedLineInstruction,
        /// Writing this form of line string is not implemented yet.
        UnsupportedLineStringForm,
        /// A `.debug_line` file index is invalid.
        InvalidFileIndex,
        /// A `.debug_line` directory index is invalid.
        InvalidDirectoryIndex,
        /// A `.debug_line` line base is invalid.
        InvalidLineBase,
        /// A `.debug_line` reference is invalid.
        InvalidLineRef,
        /// Invalid relative address in a range list.
        InvalidRangeRelativeAddress,
    }

    impl fmt::Display for ConvertError {
        fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
            use self::ConvertError::*;
            match *self {
                Read(ref e) => e.fmt(f),
                UnsupportedAttributeValue => {
                    write!(f, "Writing of this attribute value is not implemented yet.")
                }
                InvalidAttributeValue => write!(
                    f,
                    "This attribute value is an invalid name/form combination."
                ),
                InvalidDebugInfoOffset => write!(
                    f,
                    "A `.debug_info` reference does not refer to a valid entry."
                ),
                InvalidAddress => write!(f, "An address could not be converted."),
                MissingCompilationDirectory => write!(
                    f,
                    "The line number program is missing the compilation directory."
                ),
                MissingCompilationFile => write!(
                    f,
                    "The line number program is missing the compilation file."
                ),
                UnsupportedLineInstruction => write!(
                    f,
                    "Writing this line number instruction is not implemented yet."
                ),
                UnsupportedLineStringForm => write!(
                    f,
                    "Writing this form of line string is not implemented yet."
                ),
                InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."),
                InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."),
                InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."),
                InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."),
                InvalidRangeRelativeAddress => {
                    write!(f, "Invalid relative address in a range list.")
                }
            }
        }
    }

    impl error::Error for ConvertError {}

    impl From<read::Error> for ConvertError {
        fn from(e: read::Error) -> Self {
            ConvertError::Read(e)
        }
    }

    /// The result of a conversion.
    pub type ConvertResult<T> = result::Result<T, ConvertError>;
}
#[cfg(feature = "read")]
pub use self::convert::*;
<commit_msg>write: add an example<commit_after>//! Write DWARF debugging information.
//!
//! ## API Structure
//!
//! This module works by building up a representation of the debugging information
//! in memory, and then writing it all at once. It supports two major use cases:
//!
//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF
//! for a single compilation unit.
//!
//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple
//! compilation units.
//!
//! The module also supports reading in DWARF debugging information and writing it out
//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html)
//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert
//! it to a writable instance.
//!
//! ## Example Usage
//!
//! Write a compilation unit containing only the top level DIE.
//!
//! ```rust
//! extern crate gimli;
//!
//! use gimli::write::{
//!     Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections,
//! };
//!
//! fn example() -> Result<(), Error> {
//!     // Choose the encoding parameters.
//!     let encoding = gimli::Encoding {
//!         format: gimli::Format::Dwarf32,
//!         version: 5,
//!         address_size: 8,
//!     };
//!     // Create a container for a single compilation unit.
//!     let mut dwarf = DwarfUnit::new(encoding);
//!     // Set a range attribute on the root DIE.
//!     let range_list = RangeList(vec![Range::StartLength {
//!         begin: Address::Absolute(0x100),
//!         length: 42,
//!     }]);
//!     let range_list_id = dwarf.unit.ranges.add(range_list);
//!     let root = dwarf.unit.root();
//!     dwarf.unit.get_mut(root).set(
//!         gimli::DW_AT_ranges,
//!         AttributeValue::RangeListRef(range_list_id),
//!     );
//!     // Create a `Vec` for each DWARF section.
//!     let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian));
//!     // Finally, write the DWARF data to the sections.
//!     dwarf.write(&mut sections)?;
//!     sections.for_each(|id, data| {
//!         // Here you can add the data to the output object file.
//!         Ok(())
//!     })
//! }
//! # fn main() {
//! #     example().unwrap();
//! # }

use std::error;
use std::fmt;
use std::result;

mod endian_vec;
pub use self::endian_vec::*;

mod writer;
pub use self::writer::*;

#[macro_use]
mod section;
pub use self::section::*;

macro_rules! define_id {
    ($name:ident, $docs:expr) => {
        #[doc=$docs]
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        pub struct $name {
            base_id: BaseId,
            index: usize,
        }

        impl $name {
            #[inline]
            fn new(base_id: BaseId, index: usize) -> Self {
                $name { base_id, index }
            }
        }
    };
}

macro_rules! define_offsets {
    ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => {
        #[doc=$off_doc]
        #[derive(Debug)]
        pub struct $offsets {
            base_id: BaseId,
            // We know ids start at 0.
            offsets: Vec<$offset>,
        }

        impl $offsets {
            /// Return an empty list of offsets.
            #[inline]
            pub fn none() -> Self {
                $offsets {
                    base_id: BaseId::default(),
                    offsets: Vec::new(),
                }
            }

            /// Get the offset
            ///
            /// # Panics
            ///
            /// Panics if `id` is invalid.
            #[inline]
            pub fn get(&self, id: $id) -> $offset {
                debug_assert_eq!(self.base_id, id.base_id);
                self.offsets[id.index]
            }

            /// Return the number of offsets.
            #[inline]
            pub fn count(&self) -> usize {
                self.offsets.len()
            }
        }
    };
}

mod dwarf;
pub use self::dwarf::*;

mod abbrev;
pub use self::abbrev::*;

mod line;
pub use self::line::*;

mod str;
pub use self::str::*;

mod unit;
pub use self::unit::*;

mod range;
pub use self::range::*;

/// An error that occurred when writing.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
    /// The given offset is out of bounds.
    OffsetOutOfBounds,
    /// The given length is out of bounds.
    LengthOutOfBounds,
    /// The attribute value is an invalid for writing.
    InvalidAttributeValue,
    /// The value is too large for the encoding form.
    ValueTooLarge,
    /// Unsupported word size.
    UnsupportedWordSize(u8),
    /// Unsupported DWARF version.
    UnsupportedVersion(u16),
    /// The unit length is too large for the requested DWARF format.
    InitialLengthOverflow,
    /// The address is invalid.
    InvalidAddress,
    /// A requested feature requires a different DWARF version.
    NeedVersion(u16),
    /// Strings in line number program have mismatched forms.
    LineStringFormMismatch,
    /// The range is empty or otherwise invalid.
    InvalidRange,
    /// The line number program encoding is incompatible with the unit encoding.
    IncompatibleLineProgramEncoding,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."),
            Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."),
            Error::InvalidAttributeValue => {
                write!(f, "The attribute value is an invalid for writing.")
            }
            Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."),
            Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size),
            Error::UnsupportedVersion(version) => {
                write!(f, "Unsupported DWARF version: {}", version)
            }
            Error::InitialLengthOverflow => write!(
                f,
                "The unit length is too large for the requested DWARF format."
            ),
            Error::InvalidAddress => write!(f, "The address is invalid."),
            Error::NeedVersion(version) => write!(
                f,
                "A requested feature requires a DWARF version {}.",
                version
            ),
            Error::LineStringFormMismatch => {
                write!(f, "Strings in line number program have mismatched forms.")
            }
            Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."),
            Error::IncompatibleLineProgramEncoding => write!(
                f,
                "The line number program encoding is incompatible with the unit encoding."
            ),
        }
    }
}

impl error::Error for Error {}

/// The result of a write.
pub type Result<T> = result::Result<T, Error>;

/// An address.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Address {
    /// An absolute address that does not require relocation.
    Absolute(u64),
    /// An address that is relative to a symbol which may be relocated.
    Relative {
        /// The symbol that the address is relative to.
        ///
        /// The meaning of this value is decided by the writer, but
        /// will typically be an index into a symbol table.
        symbol: usize,
        /// The offset of the address relative to the symbol.
        ///
        /// This will typically be used as the addend in a relocation.
        addend: i64,
    },
}

// This type is only used in debug assertions.
#[cfg(not(debug_assertions))]
type BaseId = ();

#[cfg(debug_assertions)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct BaseId(usize);

#[cfg(debug_assertions)]
impl Default for BaseId {
    fn default() -> Self {
        use std::sync::atomic;
        static BASE_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
        BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed))
    }
}

#[cfg(feature = "read")]
mod convert {
    use super::*;
    use read;

    pub(crate) use super::unit::convert::*;

    /// An error that occurred when converting a read value into a write value.
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum ConvertError {
        /// An error occurred when reading.
        Read(read::Error),
        /// Writing of this attribute value is not implemented yet.
        UnsupportedAttributeValue,
        /// This attribute value is an invalid name/form combination.
        InvalidAttributeValue,
        /// A `.debug_info` reference does not refer to a valid entry.
        InvalidDebugInfoOffset,
        /// An address could not be converted.
        InvalidAddress,
        /// The line number program is missing the compilation directory.
        MissingCompilationDirectory,
        /// The line number program is missing the compilation file.
        MissingCompilationFile,
        /// Writing this line number instruction is not implemented yet.
        UnsupportedLineInstruction,
        /// Writing this form of line string is not implemented yet.
        UnsupportedLineStringForm,
        /// A `.debug_line` file index is invalid.
        InvalidFileIndex,
        /// A `.debug_line` directory index is invalid.
        InvalidDirectoryIndex,
        /// A `.debug_line` line base is invalid.
        InvalidLineBase,
        /// A `.debug_line` reference is invalid.
        InvalidLineRef,
        /// Invalid relative address in a range list.
        InvalidRangeRelativeAddress,
    }

    impl fmt::Display for ConvertError {
        fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
            use self::ConvertError::*;
            match *self {
                Read(ref e) => e.fmt(f),
                UnsupportedAttributeValue => {
                    write!(f, "Writing of this attribute value is not implemented yet.")
                }
                InvalidAttributeValue => write!(
                    f,
                    "This attribute value is an invalid name/form combination."
                ),
                InvalidDebugInfoOffset => write!(
                    f,
                    "A `.debug_info` reference does not refer to a valid entry."
                ),
                InvalidAddress => write!(f, "An address could not be converted."),
                MissingCompilationDirectory => write!(
                    f,
                    "The line number program is missing the compilation directory."
                ),
                MissingCompilationFile => write!(
                    f,
                    "The line number program is missing the compilation file."
                ),
                UnsupportedLineInstruction => write!(
                    f,
                    "Writing this line number instruction is not implemented yet."
                ),
                UnsupportedLineStringForm => write!(
                    f,
                    "Writing this form of line string is not implemented yet."
                ),
                InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."),
                InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."),
                InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."),
                InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."),
                InvalidRangeRelativeAddress => {
                    write!(f, "Invalid relative address in a range list.")
                }
            }
        }
    }

    impl error::Error for ConvertError {}

    impl From<read::Error> for ConvertError {
        fn from(e: read::Error) -> Self {
            ConvertError::Read(e)
        }
    }

    /// The result of a conversion.
    pub type ConvertResult<T> = result::Result<T, ConvertError>;
}
#[cfg(feature = "read")]
pub use self::convert::*;
<|endoftext|>


<commit_before>#[pub]
params -> Params
 = f: filter* "&" o:order_by? "&" g:group_by? "&" e:equation* {
 	Params{
 		filters: f,
 		order_by: match o{Some(o) => o, None => vec![]},
 		group_by: match g{Some(g) => g, None => vec![]},
 		equations: e
 	}
 }

 	/ lf:filter conn_fil:connector_filter* {
		let mut sub_filters = vec![];
		for (conn, fil) in conn_fil{
			let filter = Filter{connector: Some(conn), condition: fil.condition, subfilter: vec![]};
			sub_filters.push(filter);
		}
        Filter {
        	connector: None,
        	condition: lf.condition,
        	subfilter: sub_filters
        }
	}

 	 = f:filter? {
     	Params{
     		filters: match f{
     						Some(f)=> vec![f],
     						None => vec![]
 						},
     		order_by: vec![],
     		group_by: vec![],
     		equations: vec![]
     	}
 	}<commit_msg>before reworking on grouped conditions<commit_after>#[pub]
params -> Params
 = f: filter* "&" o:order_by? "&" g:group_by? "&" e:equation* {
 	Params{
 		filters: f,
 		order_by: match o{Some(o) => o, None => vec![]},
 		group_by: match g{Some(g) => g, None => vec![]},
 		equations: e
 	}
 }

 	/ lf:filter conn_fil:connector_filter* {
		let mut sub_filters = vec![];
		for (conn, fil) in conn_fil{
			let filter = Filter{connector: Some(conn), condition: fil.condition, subfilter: vec![]};
			sub_filters.push(filter);
		}
        Filter {
        	connector: None,
        	condition: lf.condition,
        	subfilter: sub_filters
        }
	}

 	 = f:filter? {
     	Params{
     		filters: match f{
     						Some(f)=> vec![f],
     						None => vec![]
 						},
     		order_by: vec![],
     		group_by: vec![],
     		equations: vec![]
     	}
 	}

 	 	/ "(" c:condition ")" {
			c
	}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_void, c_int};
use libc::{MS_REC, MS_PRIVATE, MS_NOSUID, MS_NODEV, MS_NOEXEC, MNT_DETACH};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, SIGCHLD};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::io::{Read, Write};
use linux::{chdir, mount, umount2, pivot_root};
use linux;
use stack::Stack;

//use std::panic::catch_unwind;
fn catch_unwind<F: FnOnce() -> R, R>(f: F) -> Result<R, ()> {
    println!("my ubuntu rust is too old. Just make sure nothing panics, mkey?");
    //rust does not support conditional compilation based on the compiler version -_-
   Ok(f())
   //panics on Error
}

// a lot copied from man USER_NAMESPACES(7)

#[no_mangle]
extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs<bool>;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    let setup = unsafe { (*args).setup };
    let run = unsafe { (*args).run };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let result = catch_unwind(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            assert_eq!(libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1), 0);
            assert_eq!(libc::close(r_pipe_fd), 0);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        let container_root = Path::new("./mntcont");
        if container_root.exists() {
            assert!(container_root.is_dir());
        } else {
            println!("creating {:?}", container_root.as_os_str());
            fs::create_dir(container_root).expect("mkdir mntcont");
        }

        println!("mounting container root");
        mount(None, Some(container_root), Some("tmpfs"), 0);
        mount(Some("none"), Some("/"), None, MS_REC|MS_PRIVATE);
        {
            let proc_dir = container_root.join("proc");
            println!("setting up {:?}", proc_dir.as_os_str());
            fs::create_dir(proc_dir.as_path()).expect("mkdir proc");
            mount(None, Some(proc_dir.as_path()), Some("proc"), MS_NOSUID|MS_NODEV|MS_NOEXEC);
        }

        // setup: a chance to populate root.
        let setup_result = setup(container_root);

        let old_root_name = "oldroot";
        {
            println!("Entering new root");
            let old_root = container_root.join(old_root_name);
            fs::create_dir(old_root.as_path()).expect("mkdir oldroot");
            pivot_root(container_root, old_root.as_path());
        }

        chdir("/");

        // we moved to the new root
        let container_root = Path::new("/");
        let old_root = container_root.join(old_root_name);
        let old_root = old_root.as_path();

        {
            println!("getting rid of old root");
            umount2(old_root, MNT_DETACH);
            assert!(fs::read_dir(old_root).expect("oldroot dir").next().is_none());
            fs::remove_dir(old_root).expect("rmdir oldroot");
        }

        {
            println!("mountinfo");
            let mut fstatus = File::open("/proc/self/mountinfo").expect("open mountinfo");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                println!("{}", l);
            }
        }

        linux::debug_leaked_fds(0);

        // Bare setup is done.
        // Missing:
        //  * Resource limitations with cgroups
        //  * Capability setup (process has full capabilities in its user namespace!)
        //  * Container is naked:
        //    * Full kernel attack surface, no syscall limitations with seccomp
        //    * No critical things prohibited with AppArmor or SELinux (e.g. container has full
        //      /proc access)
        setup_result
    });

    match result {
        Ok(setup_result) => run(setup_result),
        Err(_) => {
            println!("setup paniced");
            1
        }
    }
}

struct ChildArgs<T> {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
    setup: fn(&Path) -> T, //container_root -> custom_val
    run: fn(T) -> c_int,
}

//write to file with one write call
fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
}

pub fn runcontained(setup: fn(&Path) -> bool, run: fn(bool) -> c_int) {

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1], setup: setup, run: run});
        Box::into_raw(child_args) as *mut c_void
    };

    let child_stack = Stack::new(512);

    println!("cloning");
    let child_pid = unsafe {
        libc::clone(child_func, child_stack.top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //child_stack gets unmapped
}
<commit_msg>net ns<commit_after>extern crate libc;

use libc::{c_void, c_int};
use libc::{MS_REC, MS_PRIVATE, MS_NOSUID, MS_NODEV, MS_NOEXEC, MNT_DETACH};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWNET, SIGCHLD};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::io::{Read, Write};
use linux::{chdir, mount, umount2, pivot_root};
use linux;
use stack::Stack;

//use std::panic::catch_unwind;
fn catch_unwind<F: FnOnce() -> R, R>(f: F) -> Result<R, ()> {
    println!("my ubuntu rust is too old. Just make sure nothing panics, mkey?");
    //rust does not support conditional compilation based on the compiler version -_-
   Ok(f())
   //panics on Error
}

// a lot copied from man USER_NAMESPACES(7)

#[no_mangle]
extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs<bool>;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    let setup = unsafe { (*args).setup };
    let run = unsafe { (*args).run };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let result = catch_unwind(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            assert_eq!(libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1), 0);
            assert_eq!(libc::close(r_pipe_fd), 0);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        let container_root = Path::new("./mntcont");
        if container_root.exists() {
            assert!(container_root.is_dir());
        } else {
            println!("creating {:?}", container_root.as_os_str());
            fs::create_dir(container_root).expect("mkdir mntcont");
        }

        println!("mounting container root");
        mount(None, Some(container_root), Some("tmpfs"), 0);
        mount(Some("none"), Some("/"), None, MS_REC|MS_PRIVATE);
        {
            let proc_dir = container_root.join("proc");
            println!("setting up {:?}", proc_dir.as_os_str());
            fs::create_dir(proc_dir.as_path()).expect("mkdir proc");
            mount(None, Some(proc_dir.as_path()), Some("proc"), MS_NOSUID|MS_NODEV|MS_NOEXEC);
        }

        // setup: a chance to populate root.
        let setup_result = setup(container_root);

        let old_root_name = "oldroot";
        {
            println!("Entering new root");
            let old_root = container_root.join(old_root_name);
            fs::create_dir(old_root.as_path()).expect("mkdir oldroot");
            pivot_root(container_root, old_root.as_path());
        }

        chdir("/");

        // we moved to the new root
        let container_root = Path::new("/");
        let old_root = container_root.join(old_root_name);
        let old_root = old_root.as_path();

        {
            println!("getting rid of old root");
            umount2(old_root, MNT_DETACH);
            assert!(fs::read_dir(old_root).expect("oldroot dir").next().is_none());
            fs::remove_dir(old_root).expect("rmdir oldroot");
        }

        {
            println!("mountinfo");
            let mut fstatus = File::open("/proc/self/mountinfo").expect("open mountinfo");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                println!("{}", l);
            }
        }

        linux::debug_leaked_fds(0);

        // Bare setup is done.
        // Missing:
        //  * Resource limitations with cgroups
        //  * Capability setup (process has full capabilities in its user namespace!)
        //  * Container is naked:
        //    * Full kernel attack surface, no syscall limitations with seccomp
        //    * No critical things prohibited with AppArmor or SELinux (e.g. container has full
        //      /proc access)
        setup_result
    });

    match result {
        Ok(setup_result) => run(setup_result),
        Err(_) => {
            println!("setup paniced");
            1
        }
    }
}

struct ChildArgs<T> {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
    setup: fn(&Path) -> T, //container_root -> custom_val
    run: fn(T) -> c_int,
}

//write to file with one write call
fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
}

pub fn runcontained(setup: fn(&Path) -> bool, run: fn(bool) -> c_int) {

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1], setup: setup, run: run});
        Box::into_raw(child_args) as *mut c_void
    };

    let child_stack = Stack::new(512);

    println!("cloning");
    let child_pid = unsafe {
        libc::clone(child_func, child_stack.top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWNET|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //child_stack gets unmapped
}
<|endoftext|>


<commit_before>use std::ops;

#[derive(Debug)]
pub struct Vector2 {
    x: f32,
    y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {x: x, y: y}
    }

    pub fn UP() -> Vector2 {
        Vector2 {x: 0f32, y: 1f32}
    }

    pub fn DOWN() -> Vector2 {
        Vector2 {x: 0f32, y: -1f32}
    }

    pub fn RIGHT() -> Vector2 {
        Vector2 {x: 1f32, y: 0f32}
    }

    pub fn LEFT() -> Vector2 {
        Vector2 {x: -1f32, y: 0f32}
    }

    pub fn ONE() -> Vector2 {
        Vector2 {x: 1f32, y: 1f32}
    }

    pub fn ZERO() -> Vector2 {
        Vector2 {x: 0f32, y: 0f32}
    }
}

impl ops::Add for Vector2 {
    type Output = Vector2;

    fn add(self, new_vec: Vector2) -> Vector2 {
        Vector2 {x: self.x + new_vec.x, y: self.y + new_vec.y}
    }
}

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

    #[test]
    fn creates_vector2_with_parameters() {
        let actual = Vector2::new(1f32, 1f32);
        let expected = Vector2 {x: 1f32, y: 1f32};
        assert!(expected.x == actual.x &&
            expected.y == actual.y);
    }

    #[test]
    fn creates_vector2UP() {
        let actual = Vector2::UP();
        assert!(actual.x == 0f32 &&
            actual.y == 1f32);
    }

    #[test]
    fn adds_right_and_left_vectors() {
         let actual = Vector2::RIGHT() + Vector2::LEFT();
         assert_eq!(actual.x, 0f32);
    }

    #[test]
    fn adds_right_and_up() {
        let actual = Vector2::RIGHT() + Vector2::UP();
        assert_eq!(actual.x, 1f32);
        assert_eq!(actual.y, 1f32);
    }
}
<commit_msg>scalar multiplication<commit_after>use std::ops;

#[derive(PartialEq, Debug)]
pub struct Vector2 {
    x: f32,
    y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {x: x, y: y}
    }

    pub fn UP() -> Vector2 {
        Vector2 {x: 0f32, y: 1f32}
    }

    pub fn DOWN() -> Vector2 {
        Vector2 {x: 0f32, y: -1f32}
    }

    pub fn RIGHT() -> Vector2 {
        Vector2 {x: 1f32, y: 0f32}
    }

    pub fn LEFT() -> Vector2 {
        Vector2 {x: -1f32, y: 0f32}
    }

    pub fn ONE() -> Vector2 {
        Vector2 {x: 1f32, y: 1f32}
    }

    pub fn ZERO() -> Vector2 {
        Vector2 {x: 0f32, y: 0f32}
    }
}

impl ops::Add for Vector2 {
    type Output = Vector2;

    fn add(self, new_vec: Vector2) -> Vector2 {
        Vector2 {x: self.x + new_vec.x, y: self.y + new_vec.y}
    }
}

impl ops::Mul<f32> for Vector2 {
    type Output = Vector2;

    fn mul(self, value: f32) -> Vector2 {
        Vector2 {x: self.x * value, y: self.y * value}
    }
}

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

    #[test]
    fn creates_vector2_with_parameters() {
        let actual = Vector2::new(1f32, 1f32);
        let expected = Vector2 {x: 1f32, y: 1f32};
        assert!(expected.x == actual.x &&
            expected.y == actual.y);
    }

    #[test]
    fn creates_vector2UP() {
        let actual = Vector2::UP();
        assert!(actual.x == 0f32 &&
            actual.y == 1f32);
    }

    #[test]
    fn adds_right_and_left_vectors() {
         let actual = Vector2::RIGHT() + Vector2::LEFT();
         assert_eq!(actual.x, 0f32);
    }

    #[test]
    fn adds_right_and_up() {
        let actual = Vector2::RIGHT() + Vector2::UP();
        assert_eq!(actual.x, 1f32);
        assert_eq!(actual.y, 1f32);
    }

    #[test]
    fn mult_one_by_3() {
        let actual = Vector2::ONE() * 3f32;
        assert_eq!(actual.x, 3f32);
        assert_eq!(actual.y, 3f32);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Guillaume Pinot <texitoi(a)texitoi.eu>
//
// This work is free. You can redistribute it and/or modify it under
// the terms of the Do What The Fuck You Want To Public License,
// Version 2, as published by Sam Hocevar. See the COPYING file for
// more details.

//! How to `derive(StructOpt)`
//!
//! First, look at an example:
//!
//! ```
//! #[derive(StructOpt)]
//! #[structopt(name = "example", about = "An example of StructOpt usage.")]
//! struct Opt {
//!     #[structopt(short = "d", long = "debug", help = "Activate debug mode")]
//!     debug: bool,
//!     #[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
//!     speed: f64,
//!     #[structopt(help = "Input file")]
//!     input: String,
//!     #[structopt(help = "Output file, stdout if not present")]
//!     output: Option<String>,
//! }
//! ```
//!
//! So, `derive(StructOpt)` do the job, and `structopt` attribute is
//! used for additional parameters.
//!
//! First, define a struct, whatever its name.  This structure will
//! correspond to a `clap::App`.  Every method of `clap::App` in the
//! form of `fn function_name(self, &str)` can be use in the form of
//! attributes.  Our example call for example something like
//! `app.about("An example of StructOpt usage.")`.  There is some
//! special attributes:
//!
//!   - `name`: correspond to the creation of the `App` object. Our
//!     example does `clap::App::new("example")`.  Default to
//!     the crate name given by cargo.
//!   - `version`: default to the crate version given by cargo.
//!   - `author`: default to the crate version given by cargo.
//!   - `about`: default to the crate version given by cargo.
//!
//! Then, each field of the struct correspond to a `clap::Arg`.  As
//! for the struct attributes, every method of `clap::Arg` in the form
//! of `fn function_name(self, &str)` can be use in the form of
//! attributes.  The `name` attribute can be used to customize the
//! `Arg::with_name()` call (default to the field name).
//!
//! The type of the field gives the kind of argument:
//!
//! Type                 | Effect            | Added method call to `clap::Arg`
//! ---------------------|-------------------|--------------------------------------
//! `bool`               | `true` if present | `.takes_value(false).multiple(false)`
//! `u64`                | number of params  | `.takes_value(false).multiple(true)`
//! `Option<T: FromStr>` | optional argument | `.takes_value(true).multiple(false)`
//! `Vec<T: FromStr>`    | list of arguments | `.takes_value(true).multiple(true)`
//! `T: FromStr` | required argument | `.takes_value(true).multiple(false).required(!has_default)`
//!
//! The `FromStr` trait is used to convert the argument to the given
//! type, and the `Arg::validator` method is setted to a method using
//! `FromStr::Error::description()`.
//!
//! Thus, the `speed` argument is generated as:
//!
//! ```
//! clap::Arg::with_name("speed")
//!     .takes_value(true)
//!     .multiple(false)
//!     .required(false)
//!     .validator(parse_validator::<f64>)
//!     .short("s")
//!     .long("debug")
//!     .help("Set speed")
//!     .default_value("42")
//! ```

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::*;

/// Generates the `StructOpt` impl.
#[proc_macro_derive(StructOpt, attributes(structopt))]
pub fn structopt(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = impl_structopt(&ast);
    gen.parse().unwrap()
}

enum Ty {
    Bool,
    U64,
    Vec,
    Option,
    Other,
}

fn ty(t: &syn::Ty) -> Ty {
    if let syn::Ty::Path(None, syn::Path { segments: ref segs, .. }) = *t {
        match segs.last().unwrap().ident.as_ref() {
            "bool" => Ty::Bool,
            "u64" => Ty::U64,
            "Option" => Ty::Option,
            "Vec" => Ty::Vec,
            _ => Ty::Other,
        }
    } else {
        Ty::Other
    }
}

fn sub_type(t: &syn::Ty) -> Option<&syn::Ty> {
    let segs = match *t {
        syn::Ty::Path(None, syn::Path { ref segments, .. }) => segments,
        _ => return None,
    };
    match *segs.last().unwrap() {
        PathSegment {
            parameters: PathParameters::AngleBracketed(
                AngleBracketedParameterData { ref types, .. }),
            ..
        } if !types.is_empty() => Some(&types[0]),
            _ => None,
    }
}

fn extract_attrs<'a>(attrs: &'a [Attribute]) -> Box<Iterator<Item = (&'a Ident, &'a Lit)> + 'a> {
    let iter = attrs.iter()
        .filter_map(|attr| match attr.value {
            MetaItem::List(ref i, ref v) if i.as_ref() == "structopt" => Some(v),
            _ => None,
        }).flat_map(|v| v.iter().filter_map(|mi| match *mi {
            NestedMetaItem::MetaItem(MetaItem::NameValue(ref i, ref l)) => Some((i, l)),
            _ => None,
        }));
    Box::new(iter)
}

fn from_attr_or(attrs: &[(&Ident, &Lit)], key: &str, default: &str) -> Lit {
    attrs.iter()
        .find(|&&(i, _)| i.as_ref() == key)
        .map(|&(_, l)| l.clone())
        .unwrap_or_else(|| Lit::Str(default.into(), StrStyle::Cooked))
}

fn gen_name(field: &Field) -> Ident {
    extract_attrs(&field.attrs)
        .find(|&(i, _)| i.as_ref() == "name")
        .and_then(|(_, l)| match *l {
            Lit::Str(ref s, _) => Some(Ident::new(s.clone())),
            _ => None,
        })
        .unwrap_or(field.ident.as_ref().unwrap().clone())
}

fn gen_from_clap(struct_name: &Ident, s: &[Field]) -> quote::Tokens {
    let fields = s.iter().map(|field| {
        let field_name = field.ident.as_ref().unwrap();
        let name = gen_name(field);
        let convert = match ty(&field.ty) {
            Ty::Bool => quote!(is_present(stringify!(#name))),
            Ty::U64 => quote!(occurrences_of(stringify!(#name))),
            Ty::Option => quote! {
                value_of(stringify!(#name))
                    .as_ref()
                    .map(|s| s.parse().unwrap())
            },
            Ty::Vec => quote! {
                values_of(stringify!(#name))
                    .map(|v| v.map(|s| s.parse().unwrap()).collect())
                    .unwrap_or_else(Vec::new)
            },
            Ty::Other => quote! {
                value_of(stringify!(#name))
                    .as_ref()
                    .unwrap()
                    .parse()
                    .unwrap()
            },
        };
        quote!( #field_name: matches.#convert, )
    });
    quote! {
        fn from_clap(matches: _clap::ArgMatches) -> Self {
            #struct_name {
                #( #fields )*
            }
        }
    }
}

fn gen_clap(ast: &DeriveInput, s: &[Field]) -> quote::Tokens {
    let struct_attrs: Vec<_> = extract_attrs(&ast.attrs).collect();
    let name = from_attr_or(&struct_attrs, "name", env!("CARGO_PKG_NAME"));
    let version = from_attr_or(&struct_attrs, "version", env!("CARGO_PKG_VERSION"));
    let author = from_attr_or(&struct_attrs, "author", env!("CARGO_PKG_AUTHORS"));
    let about = from_attr_or(&struct_attrs, "about", env!("CARGO_PKG_DESCRIPTION"));

    let args = s.iter().map(|field| {
        let name = gen_name(field);
        let cur_type = ty(&field.ty);
        let convert_type = match cur_type {
            Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
            _ => &field.ty,
        };
        let validator = quote! {
            validator(|s| s.parse::<#convert_type>()
                      .map(|_| ())
                      .map_err(|e| e.description().into()))
        };
        let modifier = match cur_type {
            Ty::Bool => quote!( .takes_value(false).multiple(false) ),
            Ty::U64 => quote!( .takes_value(false).multiple(true) ),
            Ty::Option => quote!( .takes_value(true).multiple(false).#validator ),
            Ty::Vec => quote!( .takes_value(true).multiple(true).#validator ),
            Ty::Other => {
                let required = extract_attrs(&field.attrs)
                    .find(|&(i, _)| i.as_ref() == "default_value")
                    .is_none();
                quote!( .takes_value(true).multiple(false).required(#required).#validator )
            },
        };
        let from_attr = extract_attrs(&field.attrs)
            .filter(|&(i, _)| i.as_ref() != "name")
            .map(|(i, l)| quote!(.#i(#l)));
        quote!( .arg(_clap::Arg::with_name(stringify!(#name)) #modifier #(#from_attr)*) )
    });
    quote! {
        fn clap<'a, 'b>() -> _clap::App<'a, 'b> {
            use std::error::Error;
            _clap::App::new(#name)
                .version(#version)
                .author(#author)
                .about(#about)
                #( #args )*
        }
    }
}

fn impl_structopt(ast: &syn::DeriveInput) -> quote::Tokens {
    let struct_name = &ast.ident;
    let s = match ast.body {
        Body::Struct(VariantData::Struct(ref s)) => s,
        _ => panic!("Only struct is supported"),
    };

    let clap = gen_clap(ast, s);
    let from_clap = gen_from_clap(struct_name, s);
    let dummy_const = Ident::new(format!("_IMPL_STRUCTOPT_FOR_{}", struct_name));
    quote! {
        #[allow(non_upper_case_globals, unused_attributes, unused_imports)]
        const #dummy_const: () = {
            extern crate clap as _clap;
            extern crate structopt as _structopt;
            impl _structopt::StructOpt for #struct_name {
                #clap
                #from_clap
            }
        };
    }
}
<commit_msg>desactivate doctest on structopt-derive doc<commit_after>// Copyright (c) 2017 Guillaume Pinot <texitoi(a)texitoi.eu>
//
// This work is free. You can redistribute it and/or modify it under
// the terms of the Do What The Fuck You Want To Public License,
// Version 2, as published by Sam Hocevar. See the COPYING file for
// more details.

//! How to `derive(StructOpt)`
//!
//! First, look at an example:
//!
//! ```ignore
//! #[derive(StructOpt)]
//! #[structopt(name = "example", about = "An example of StructOpt usage.")]
//! struct Opt {
//!     #[structopt(short = "d", long = "debug", help = "Activate debug mode")]
//!     debug: bool,
//!     #[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
//!     speed: f64,
//!     #[structopt(help = "Input file")]
//!     input: String,
//!     #[structopt(help = "Output file, stdout if not present")]
//!     output: Option<String>,
//! }
//! ```
//!
//! So, `derive(StructOpt)` do the job, and `structopt` attribute is
//! used for additional parameters.
//!
//! First, define a struct, whatever its name.  This structure will
//! correspond to a `clap::App`.  Every method of `clap::App` in the
//! form of `fn function_name(self, &str)` can be use in the form of
//! attributes.  Our example call for example something like
//! `app.about("An example of StructOpt usage.")`.  There is some
//! special attributes:
//!
//!   - `name`: correspond to the creation of the `App` object. Our
//!     example does `clap::App::new("example")`.  Default to
//!     the crate name given by cargo.
//!   - `version`: default to the crate version given by cargo.
//!   - `author`: default to the crate version given by cargo.
//!   - `about`: default to the crate version given by cargo.
//!
//! Then, each field of the struct correspond to a `clap::Arg`.  As
//! for the struct attributes, every method of `clap::Arg` in the form
//! of `fn function_name(self, &str)` can be use in the form of
//! attributes.  The `name` attribute can be used to customize the
//! `Arg::with_name()` call (default to the field name).
//!
//! The type of the field gives the kind of argument:
//!
//! Type                 | Effect            | Added method call to `clap::Arg`
//! ---------------------|-------------------|--------------------------------------
//! `bool`               | `true` if present | `.takes_value(false).multiple(false)`
//! `u64`                | number of params  | `.takes_value(false).multiple(true)`
//! `Option<T: FromStr>` | optional argument | `.takes_value(true).multiple(false)`
//! `Vec<T: FromStr>`    | list of arguments | `.takes_value(true).multiple(true)`
//! `T: FromStr` | required argument | `.takes_value(true).multiple(false).required(!has_default)`
//!
//! The `FromStr` trait is used to convert the argument to the given
//! type, and the `Arg::validator` method is setted to a method using
//! `FromStr::Error::description()`.
//!
//! Thus, the `speed` argument is generated as:
//!
//! ```ignore
//! clap::Arg::with_name("speed")
//!     .takes_value(true)
//!     .multiple(false)
//!     .required(false)
//!     .validator(parse_validator::<f64>)
//!     .short("s")
//!     .long("debug")
//!     .help("Set speed")
//!     .default_value("42")
//! ```

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::*;

/// Generates the `StructOpt` impl.
#[proc_macro_derive(StructOpt, attributes(structopt))]
pub fn structopt(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = impl_structopt(&ast);
    gen.parse().unwrap()
}

enum Ty {
    Bool,
    U64,
    Vec,
    Option,
    Other,
}

fn ty(t: &syn::Ty) -> Ty {
    if let syn::Ty::Path(None, syn::Path { segments: ref segs, .. }) = *t {
        match segs.last().unwrap().ident.as_ref() {
            "bool" => Ty::Bool,
            "u64" => Ty::U64,
            "Option" => Ty::Option,
            "Vec" => Ty::Vec,
            _ => Ty::Other,
        }
    } else {
        Ty::Other
    }
}

fn sub_type(t: &syn::Ty) -> Option<&syn::Ty> {
    let segs = match *t {
        syn::Ty::Path(None, syn::Path { ref segments, .. }) => segments,
        _ => return None,
    };
    match *segs.last().unwrap() {
        PathSegment {
            parameters: PathParameters::AngleBracketed(
                AngleBracketedParameterData { ref types, .. }),
            ..
        } if !types.is_empty() => Some(&types[0]),
            _ => None,
    }
}

fn extract_attrs<'a>(attrs: &'a [Attribute]) -> Box<Iterator<Item = (&'a Ident, &'a Lit)> + 'a> {
    let iter = attrs.iter()
        .filter_map(|attr| match attr.value {
            MetaItem::List(ref i, ref v) if i.as_ref() == "structopt" => Some(v),
            _ => None,
        }).flat_map(|v| v.iter().filter_map(|mi| match *mi {
            NestedMetaItem::MetaItem(MetaItem::NameValue(ref i, ref l)) => Some((i, l)),
            _ => None,
        }));
    Box::new(iter)
}

fn from_attr_or(attrs: &[(&Ident, &Lit)], key: &str, default: &str) -> Lit {
    attrs.iter()
        .find(|&&(i, _)| i.as_ref() == key)
        .map(|&(_, l)| l.clone())
        .unwrap_or_else(|| Lit::Str(default.into(), StrStyle::Cooked))
}

fn gen_name(field: &Field) -> Ident {
    extract_attrs(&field.attrs)
        .find(|&(i, _)| i.as_ref() == "name")
        .and_then(|(_, l)| match *l {
            Lit::Str(ref s, _) => Some(Ident::new(s.clone())),
            _ => None,
        })
        .unwrap_or(field.ident.as_ref().unwrap().clone())
}

fn gen_from_clap(struct_name: &Ident, s: &[Field]) -> quote::Tokens {
    let fields = s.iter().map(|field| {
        let field_name = field.ident.as_ref().unwrap();
        let name = gen_name(field);
        let convert = match ty(&field.ty) {
            Ty::Bool => quote!(is_present(stringify!(#name))),
            Ty::U64 => quote!(occurrences_of(stringify!(#name))),
            Ty::Option => quote! {
                value_of(stringify!(#name))
                    .as_ref()
                    .map(|s| s.parse().unwrap())
            },
            Ty::Vec => quote! {
                values_of(stringify!(#name))
                    .map(|v| v.map(|s| s.parse().unwrap()).collect())
                    .unwrap_or_else(Vec::new)
            },
            Ty::Other => quote! {
                value_of(stringify!(#name))
                    .as_ref()
                    .unwrap()
                    .parse()
                    .unwrap()
            },
        };
        quote!( #field_name: matches.#convert, )
    });
    quote! {
        fn from_clap(matches: _clap::ArgMatches) -> Self {
            #struct_name {
                #( #fields )*
            }
        }
    }
}

fn gen_clap(ast: &DeriveInput, s: &[Field]) -> quote::Tokens {
    let struct_attrs: Vec<_> = extract_attrs(&ast.attrs).collect();
    let name = from_attr_or(&struct_attrs, "name", env!("CARGO_PKG_NAME"));
    let version = from_attr_or(&struct_attrs, "version", env!("CARGO_PKG_VERSION"));
    let author = from_attr_or(&struct_attrs, "author", env!("CARGO_PKG_AUTHORS"));
    let about = from_attr_or(&struct_attrs, "about", env!("CARGO_PKG_DESCRIPTION"));

    let args = s.iter().map(|field| {
        let name = gen_name(field);
        let cur_type = ty(&field.ty);
        let convert_type = match cur_type {
            Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
            _ => &field.ty,
        };
        let validator = quote! {
            validator(|s| s.parse::<#convert_type>()
                      .map(|_| ())
                      .map_err(|e| e.description().into()))
        };
        let modifier = match cur_type {
            Ty::Bool => quote!( .takes_value(false).multiple(false) ),
            Ty::U64 => quote!( .takes_value(false).multiple(true) ),
            Ty::Option => quote!( .takes_value(true).multiple(false).#validator ),
            Ty::Vec => quote!( .takes_value(true).multiple(true).#validator ),
            Ty::Other => {
                let required = extract_attrs(&field.attrs)
                    .find(|&(i, _)| i.as_ref() == "default_value")
                    .is_none();
                quote!( .takes_value(true).multiple(false).required(#required).#validator )
            },
        };
        let from_attr = extract_attrs(&field.attrs)
            .filter(|&(i, _)| i.as_ref() != "name")
            .map(|(i, l)| quote!(.#i(#l)));
        quote!( .arg(_clap::Arg::with_name(stringify!(#name)) #modifier #(#from_attr)*) )
    });
    quote! {
        fn clap<'a, 'b>() -> _clap::App<'a, 'b> {
            use std::error::Error;
            _clap::App::new(#name)
                .version(#version)
                .author(#author)
                .about(#about)
                #( #args )*
        }
    }
}

fn impl_structopt(ast: &syn::DeriveInput) -> quote::Tokens {
    let struct_name = &ast.ident;
    let s = match ast.body {
        Body::Struct(VariantData::Struct(ref s)) => s,
        _ => panic!("Only struct is supported"),
    };

    let clap = gen_clap(ast, s);
    let from_clap = gen_from_clap(struct_name, s);
    let dummy_const = Ident::new(format!("_IMPL_STRUCTOPT_FOR_{}", struct_name));
    quote! {
        #[allow(non_upper_case_globals, unused_attributes, unused_imports)]
        const #dummy_const: () = {
            extern crate clap as _clap;
            extern crate structopt as _structopt;
            impl _structopt::StructOpt for #struct_name {
                #clap
                #from_clap
            }
        };
    }
}
<|endoftext|>


<commit_before>//! Main Playform client state code.

use cgmath::Point3;
use std::collections::HashMap;
use std::iter::range_inclusive;
use std::sync::Mutex;

use common::block_position::BlockPosition;
use common::communicate::ClientId;
use common::entity::EntityId;
use common::lod::LODIndex;
use common::surroundings_loader::SurroundingsLoader;
use common::terrain_block;
use common::terrain_block::TerrainBlock;

use terrain_buffers;

/// The distances at which LOD switches.
pub const LOD_THRESHOLDS: [i32; 3] = [1, 8, 32];

/// The main client state.
pub struct Client {
  #[allow(missing_docs)]
  pub id: ClientId,
  #[allow(missing_docs)]
  pub player_id: EntityId,
  #[allow(missing_docs)]
  pub player_position: Mutex<Point3<f32>>,
  #[allow(missing_docs)]
  pub max_load_distance: i32,
  #[allow(missing_docs)]
  pub surroundings_loader: Mutex<SurroundingsLoader>,
  /// A record of all the blocks that have been loaded.
  pub loaded_blocks: Mutex<HashMap<BlockPosition, (TerrainBlock, LODIndex)>>,
}

impl Client {
  #[allow(missing_docs)]
  pub fn new(client_id: ClientId, player_id: EntityId, position: Point3<f32>) -> Client {
    let mut load_distance = load_distance(terrain_buffers::POLYGON_BUDGET as i32);

    // TODO: Remove this once our RAM usage doesn't skyrocket with load distance.
    let max_load_distance = 80;
    if load_distance > max_load_distance {
      info!("load_distance {} capped at {}", load_distance, max_load_distance);
      load_distance = max_load_distance;
    } else {
      info!("load_distance {}", load_distance);
    }

    let surroundings_loader = {
      SurroundingsLoader::new(
        max_load_distance,
        LOD_THRESHOLDS.iter().map(|&x| x).collect(),
      )
    };

    Client {
      id: client_id,
      player_id: player_id,
      player_position: Mutex::new(position),
      max_load_distance: load_distance,
      surroundings_loader: Mutex::new(surroundings_loader),
      loaded_blocks: Mutex::new(HashMap::new()),
    }
  }
}

unsafe impl Sync for Client {}

fn load_distance(mut polygon_budget: i32) -> i32 {
  // TODO: This should try to account for VRAM not used on a per-poly basis.

  let mut load_distance = 0;
  let mut prev_threshold = 0;
  let mut prev_square = 0;
  for (&threshold, &quality) in LOD_THRESHOLDS.iter().zip(terrain_block::EDGE_SAMPLES.iter()) {
    let polygons_per_block = (quality * quality * 4) as i32;
    for i in range_inclusive(prev_threshold, threshold) {
      let i = 2 * i + 1;
      let square = i * i;
      let polygons_in_layer = (square - prev_square) * polygons_per_block;
      polygon_budget -= polygons_in_layer;
      if polygon_budget < 0 {
        break;
      }

      load_distance += 1;
      prev_square = square;
    }
    prev_threshold = threshold + 1;
  }

  let mut width = 2 * prev_threshold + 1;
  loop {
    let square = width * width;
    // The "to infinity and beyond" quality.
    let quality = terrain_block::EDGE_SAMPLES[LOD_THRESHOLDS.len()];
    let polygons_per_block = (quality * quality * 4) as i32;
    let polygons_in_layer = (square - prev_square) * polygons_per_block;
    polygon_budget -= polygons_in_layer;

    if polygon_budget < 0 {
      break;
    }

    width += 2;
    load_distance += 1;
    prev_square = square;
  }

  load_distance
}
<commit_msg>Further LOD boundaries<commit_after>//! Main Playform client state code.

use cgmath::Point3;
use std::collections::HashMap;
use std::iter::range_inclusive;
use std::sync::Mutex;

use common::block_position::BlockPosition;
use common::communicate::ClientId;
use common::entity::EntityId;
use common::lod::LODIndex;
use common::surroundings_loader::SurroundingsLoader;
use common::terrain_block;
use common::terrain_block::TerrainBlock;

use terrain_buffers;

/// The distances at which LOD switches.
pub const LOD_THRESHOLDS: [i32; 3] = [2, 16, 32];

/// The main client state.
pub struct Client {
  #[allow(missing_docs)]
  pub id: ClientId,
  #[allow(missing_docs)]
  pub player_id: EntityId,
  #[allow(missing_docs)]
  pub player_position: Mutex<Point3<f32>>,
  #[allow(missing_docs)]
  pub max_load_distance: i32,
  #[allow(missing_docs)]
  pub surroundings_loader: Mutex<SurroundingsLoader>,
  /// A record of all the blocks that have been loaded.
  pub loaded_blocks: Mutex<HashMap<BlockPosition, (TerrainBlock, LODIndex)>>,
}

impl Client {
  #[allow(missing_docs)]
  pub fn new(client_id: ClientId, player_id: EntityId, position: Point3<f32>) -> Client {
    let mut load_distance = load_distance(terrain_buffers::POLYGON_BUDGET as i32);

    // TODO: Remove this once our RAM usage doesn't skyrocket with load distance.
    let max_load_distance = 80;
    if load_distance > max_load_distance {
      info!("load_distance {} capped at {}", load_distance, max_load_distance);
      load_distance = max_load_distance;
    } else {
      info!("load_distance {}", load_distance);
    }

    let surroundings_loader = {
      SurroundingsLoader::new(
        max_load_distance,
        LOD_THRESHOLDS.iter().map(|&x| x).collect(),
      )
    };

    Client {
      id: client_id,
      player_id: player_id,
      player_position: Mutex::new(position),
      max_load_distance: load_distance,
      surroundings_loader: Mutex::new(surroundings_loader),
      loaded_blocks: Mutex::new(HashMap::new()),
    }
  }
}

unsafe impl Sync for Client {}

fn load_distance(mut polygon_budget: i32) -> i32 {
  // TODO: This should try to account for VRAM not used on a per-poly basis.

  let mut load_distance = 0;
  let mut prev_threshold = 0;
  let mut prev_square = 0;
  for (&threshold, &quality) in LOD_THRESHOLDS.iter().zip(terrain_block::EDGE_SAMPLES.iter()) {
    let polygons_per_block = (quality * quality * 4) as i32;
    for i in range_inclusive(prev_threshold, threshold) {
      let i = 2 * i + 1;
      let square = i * i;
      let polygons_in_layer = (square - prev_square) * polygons_per_block;
      polygon_budget -= polygons_in_layer;
      if polygon_budget < 0 {
        break;
      }

      load_distance += 1;
      prev_square = square;
    }
    prev_threshold = threshold + 1;
  }

  let mut width = 2 * prev_threshold + 1;
  loop {
    let square = width * width;
    // The "to infinity and beyond" quality.
    let quality = terrain_block::EDGE_SAMPLES[LOD_THRESHOLDS.len()];
    let polygons_per_block = (quality * quality * 4) as i32;
    let polygons_in_layer = (square - prev_square) * polygons_per_block;
    polygon_budget -= polygons_in_layer;

    if polygon_budget < 0 {
      break;
    }

    width += 2;
    load_distance += 1;
    prev_square = square;
  }

  load_distance
}
<|endoftext|>