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

/*!

Synchronous Timers

This module exposes the functionality to create timers, block the current task,
and create receivers which will receive notifications after a period of time.

*/

use comm::{Receiver, Sender, channel};
use io::{IoResult, IoError};
use kinds::Send;
use owned::Box;
use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};

/// A synchronous timer object
///
/// Values of this type can be used to put the current task to sleep for a
/// period of time. Handles to this timer can also be created in the form of
/// receivers which will receive notifications over time.
///
/// # Example
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(10); // block the task for awhile
///
/// let timeout = timer.oneshot(10);
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(10);
/// loop {
///     periodic.recv();
///     // this loop is only executed once every 10ms
/// }
/// # }
/// ```
///
/// If only sleeping is necessary, then a convenience API is provided through
/// the `io::timer` module.
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(5000);
/// # }
/// ```
pub struct Timer {
    obj: Box<RtioTimer:Send>,
}

struct TimerCallback { tx: Sender<()> }

/// Sleep the current task for `msecs` milliseconds.
pub fn sleep(msecs: u64) {
    let timer = Timer::new();
    let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");

    timer.sleep(msecs)
}

impl Timer {
    /// Creates a new timer which can be used to put the current task to sleep
    /// for a number of milliseconds, or to possibly create channels which will
    /// get notified after an amount of time has passed.
    pub fn new() -> IoResult<Timer> {
        LocalIo::maybe_raise(|io| {
            io.timer_init().map(|t| Timer { obj: t })
        }).map_err(IoError::from_rtio_error)
    }

    /// Blocks the current task for `msecs` milliseconds.
    ///
    /// Note that this function will cause any other receivers for this timer to
    /// be invalidated (the other end will be closed).
    pub fn sleep(&mut self, msecs: u64) {
        self.obj.sleep(msecs);
    }

    /// Creates a oneshot receiver which will have a notification sent when
    /// `msecs` milliseconds has elapsed. This does *not* block the current
    /// task, but instead returns immediately.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope).
    pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.oneshot(msecs, box TimerCallback { tx: tx });
        return rx
    }

    /// Creates a receiver which will have a continuous stream of notifications
    /// being sent every `msecs` milliseconds. This does *not* block the
    /// current task, but instead returns immediately. The first notification
    /// will not be received immediately, but rather after `msec` milliseconds
    /// have passed.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope).
    pub fn periodic(&mut self, msecs: u64) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.period(msecs, box TimerCallback { tx: tx });
        return rx
    }
}

impl Callback for TimerCallback {
    fn call(&mut self) {
        let _ = self.tx.send_opt(());
    }
}

#[cfg(test)]
mod test {
    iotest!(fn test_io_timer_sleep_simple() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(1);
    })

    iotest!(fn test_io_timer_sleep_oneshot() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(1).recv();
    })

    iotest!(fn test_io_timer_sleep_oneshot_forget() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(100000000000);
    })

    iotest!(fn oneshot_twice() {
        let mut timer = Timer::new().unwrap();
        let rx1 = timer.oneshot(10000);
        let rx = timer.oneshot(1);
        rx.recv();
        assert_eq!(rx1.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_oneshot_then_sleep() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.oneshot(100000000000);
        timer.sleep(1); // this should inalidate rx

        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_sleep_periodic() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(1);
        rx.recv();
        rx.recv();
        rx.recv();
    })

    iotest!(fn test_io_timer_sleep_periodic_forget() {
        let mut timer = Timer::new().unwrap();
        timer.periodic(100000000000);
    })

    iotest!(fn test_io_timer_sleep_standalone() {
        sleep(1)
    })

    iotest!(fn oneshot() {
        let mut timer = Timer::new().unwrap();

        let rx = timer.oneshot(1);
        rx.recv();
        assert!(rx.recv_opt().is_err());

        let rx = timer.oneshot(1);
        rx.recv();
        assert!(rx.recv_opt().is_err());
    })

    iotest!(fn override() {
        let mut timer = Timer::new().unwrap();
        let orx = timer.oneshot(100);
        let prx = timer.periodic(100);
        timer.sleep(1);
        assert_eq!(orx.recv_opt(), Err(()));
        assert_eq!(prx.recv_opt(), Err(()));
        timer.oneshot(1).recv();
    })

    iotest!(fn period() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(1);
        rx.recv();
        rx.recv();
        let rx2 = timer.periodic(1);
        rx2.recv();
        rx2.recv();
    })

    iotest!(fn sleep() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(1);
        timer.sleep(1);
    })

    iotest!(fn oneshot_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.oneshot(1);
        fail!();
    } #[should_fail])

    iotest!(fn period_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.periodic(1);
        fail!();
    } #[should_fail])

    iotest!(fn normal_fail() {
        let _timer = Timer::new().unwrap();
        fail!();
    } #[should_fail])

    iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
        // see issue #10375
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        // when we drop the TimerWatcher we're going to destroy the channel,
        // which must wake up the task on the other end
    })

    iotest!(fn reset_doesnt_switch_tasks() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.oneshot(1);
    })

    iotest!(fn reset_doesnt_switch_tasks2() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.sleep(1);
    })

    iotest!(fn sender_goes_away_oneshot() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.oneshot(1000)
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn sender_goes_away_period() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.periodic(1000)
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn receiver_goes_away_oneshot() {
        let mut timer1 = Timer::new().unwrap();
        timer1.oneshot(1);
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the prevous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(2);
    })

    iotest!(fn receiver_goes_away_period() {
        let mut timer1 = Timer::new().unwrap();
        timer1.periodic(1);
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the prevous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(2);
    })
}
<commit_msg>auto merge of #14745 : huonw/rust/timer-doc, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Synchronous Timers

This module exposes the functionality to create timers, block the current task,
and create receivers which will receive notifications after a period of time.

*/

use comm::{Receiver, Sender, channel};
use io::{IoResult, IoError};
use kinds::Send;
use owned::Box;
use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};

/// A synchronous timer object
///
/// Values of this type can be used to put the current task to sleep for a
/// period of time. Handles to this timer can also be created in the form of
/// receivers which will receive notifications over time.
///
/// # Example
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(10); // block the task for awhile
///
/// let timeout = timer.oneshot(10);
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(10);
/// loop {
///     periodic.recv();
///     // this loop is only executed once every 10ms
/// }
/// # }
/// ```
///
/// If only sleeping is necessary, then a convenience API is provided through
/// the `io::timer` module.
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(5000);
/// # }
/// ```
pub struct Timer {
    obj: Box<RtioTimer:Send>,
}

struct TimerCallback { tx: Sender<()> }

/// Sleep the current task for `msecs` milliseconds.
pub fn sleep(msecs: u64) {
    let timer = Timer::new();
    let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");

    timer.sleep(msecs)
}

impl Timer {
    /// Creates a new timer which can be used to put the current task to sleep
    /// for a number of milliseconds, or to possibly create channels which will
    /// get notified after an amount of time has passed.
    pub fn new() -> IoResult<Timer> {
        LocalIo::maybe_raise(|io| {
            io.timer_init().map(|t| Timer { obj: t })
        }).map_err(IoError::from_rtio_error)
    }

    /// Blocks the current task for `msecs` milliseconds.
    ///
    /// Note that this function will cause any other receivers for this timer to
    /// be invalidated (the other end will be closed).
    pub fn sleep(&mut self, msecs: u64) {
        self.obj.sleep(msecs);
    }

    /// Creates a oneshot receiver which will have a notification sent when
    /// `msecs` milliseconds has elapsed.
    ///
    /// This does *not* block the current task, but instead returns immediately.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::io::timer::Timer;
    ///
    /// let mut timer = Timer::new().unwrap();
    /// let ten_milliseconds = timer.oneshot(10);
    ///
    /// for _ in range(0, 100) { /* do work */ }
    ///
    /// // blocks until 10 ms after the `oneshot` call
    /// ten_milliseconds.recv();
    /// ```
    ///
    /// ```rust
    /// use std::io::timer::Timer;
    ///
    /// // Incorrect, method chaining-style:
    /// let mut five_ms = Timer::new().unwrap().oneshot(5);
    /// // The timer object was destroyed, so this will always fail:
    /// // five_ms.recv()
    /// ```
    pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.oneshot(msecs, box TimerCallback { tx: tx });
        return rx
    }

    /// Creates a receiver which will have a continuous stream of notifications
    /// being sent every `msecs` milliseconds.
    ///
    /// This does *not* block the current task, but instead returns
    /// immediately. The first notification will not be received immediately,
    /// but rather after `msec` milliseconds have passed.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::io::timer::Timer;
    ///
    /// let mut timer = Timer::new().unwrap();
    /// let ten_milliseconds = timer.periodic(10);
    ///
    /// for _ in range(0, 100) { /* do work */ }
    ///
    /// // blocks until 10 ms after the `periodic` call
    /// ten_milliseconds.recv();
    ///
    /// for _ in range(0, 100) { /* do work */ }
    ///
    /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
    /// // previous `recv`)
    /// ten_milliseconds.recv();
    /// ```
    ///
    /// ```rust
    /// use std::io::timer::Timer;
    ///
    /// // Incorrect, method chaining-style.
    /// let mut five_ms = Timer::new().unwrap().periodic(5);
    /// // The timer object was destroyed, so this will always fail:
    /// // five_ms.recv()
    /// ```
    pub fn periodic(&mut self, msecs: u64) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.period(msecs, box TimerCallback { tx: tx });
        return rx
    }
}

impl Callback for TimerCallback {
    fn call(&mut self) {
        let _ = self.tx.send_opt(());
    }
}

#[cfg(test)]
mod test {
    iotest!(fn test_io_timer_sleep_simple() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(1);
    })

    iotest!(fn test_io_timer_sleep_oneshot() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(1).recv();
    })

    iotest!(fn test_io_timer_sleep_oneshot_forget() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(100000000000);
    })

    iotest!(fn oneshot_twice() {
        let mut timer = Timer::new().unwrap();
        let rx1 = timer.oneshot(10000);
        let rx = timer.oneshot(1);
        rx.recv();
        assert_eq!(rx1.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_oneshot_then_sleep() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.oneshot(100000000000);
        timer.sleep(1); // this should inalidate rx

        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_sleep_periodic() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(1);
        rx.recv();
        rx.recv();
        rx.recv();
    })

    iotest!(fn test_io_timer_sleep_periodic_forget() {
        let mut timer = Timer::new().unwrap();
        timer.periodic(100000000000);
    })

    iotest!(fn test_io_timer_sleep_standalone() {
        sleep(1)
    })

    iotest!(fn oneshot() {
        let mut timer = Timer::new().unwrap();

        let rx = timer.oneshot(1);
        rx.recv();
        assert!(rx.recv_opt().is_err());

        let rx = timer.oneshot(1);
        rx.recv();
        assert!(rx.recv_opt().is_err());
    })

    iotest!(fn override() {
        let mut timer = Timer::new().unwrap();
        let orx = timer.oneshot(100);
        let prx = timer.periodic(100);
        timer.sleep(1);
        assert_eq!(orx.recv_opt(), Err(()));
        assert_eq!(prx.recv_opt(), Err(()));
        timer.oneshot(1).recv();
    })

    iotest!(fn period() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(1);
        rx.recv();
        rx.recv();
        let rx2 = timer.periodic(1);
        rx2.recv();
        rx2.recv();
    })

    iotest!(fn sleep() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(1);
        timer.sleep(1);
    })

    iotest!(fn oneshot_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.oneshot(1);
        fail!();
    } #[should_fail])

    iotest!(fn period_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.periodic(1);
        fail!();
    } #[should_fail])

    iotest!(fn normal_fail() {
        let _timer = Timer::new().unwrap();
        fail!();
    } #[should_fail])

    iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
        // see issue #10375
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        // when we drop the TimerWatcher we're going to destroy the channel,
        // which must wake up the task on the other end
    })

    iotest!(fn reset_doesnt_switch_tasks() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.oneshot(1);
    })

    iotest!(fn reset_doesnt_switch_tasks2() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(1000);

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.sleep(1);
    })

    iotest!(fn sender_goes_away_oneshot() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.oneshot(1000)
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn sender_goes_away_period() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.periodic(1000)
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn receiver_goes_away_oneshot() {
        let mut timer1 = Timer::new().unwrap();
        timer1.oneshot(1);
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the prevous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(2);
    })

    iotest!(fn receiver_goes_away_period() {
        let mut timer1 = Timer::new().unwrap();
        timer1.periodic(1);
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the prevous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(2);
    })
}
<|endoftext|>


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

/*!

Synchronous Timers

This module exposes the functionality to create timers, block the current task,
and create receivers which will receive notifications after a period of time.

*/

use comm::{Receiver, Sender, channel};
use time::Duration;
use io::{IoResult, IoError};
use kinds::Send;
use boxed::Box;
use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};

/// A synchronous timer object
///
/// Values of this type can be used to put the current task to sleep for a
/// period of time. Handles to this timer can also be created in the form of
/// receivers which will receive notifications over time.
///
/// # Example
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(10); // block the task for awhile
///
/// let timeout = timer.oneshot(10);
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(10);
/// loop {
///     periodic.recv();
///     // this loop is only executed once every 10ms
/// }
/// # }
/// ```
///
/// If only sleeping is necessary, then a convenience API is provided through
/// the `io::timer` module.
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(5000);
/// # }
/// ```
pub struct Timer {
    obj: Box<RtioTimer + Send>,
}

struct TimerCallback { tx: Sender<()> }

fn in_ms(d: Duration) -> u64 {
    // FIXME: Do we really want to fail on negative duration?
    let ms = d.num_milliseconds();
    if ms < 0 { fail!("negative duration") }
    return ms as u64;
}

/// Sleep the current task for the specified duration.
pub fn sleep(duration: Duration) {
    let timer = Timer::new();
    let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");

    timer.sleep(duration)
}

impl Timer {
    /// Creates a new timer which can be used to put the current task to sleep
    /// for a number of milliseconds, or to possibly create channels which will
    /// get notified after an amount of time has passed.
    pub fn new() -> IoResult<Timer> {
        LocalIo::maybe_raise(|io| {
            io.timer_init().map(|t| Timer { obj: t })
        }).map_err(IoError::from_rtio_error)
    }

    /// Blocks the current task for the specified duration.
    ///
    /// Note that this function will cause any other receivers for this timer to
    /// be invalidated (the other end will be closed).
    pub fn sleep(&mut self, duration: Duration) {
        self.obj.sleep(in_ms(duration));
    }

    /// Creates a oneshot receiver which will have a notification sent when
    /// the specified duration has elapsed.
    ///
    /// This does *not* block the current task, but instead returns immediately.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx });
        return rx
    }

    /// Creates a receiver which will have a continuous stream of notifications
    /// being sent each time the specified duration has elapsed.
    ///
    /// This does *not* block the current task, but instead returns
    /// immediately. The first notification will not be received immediately,
    /// but rather after the first duration.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.period(in_ms(duration), box TimerCallback { tx: tx });
        return rx
    }
}

impl Callback for TimerCallback {
    fn call(&mut self) {
        let _ = self.tx.send_opt(());
    }
}

#[cfg(test)]
mod test {
    use time::Duration;

    iotest!(fn test_io_timer_sleep_simple() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn test_io_timer_sleep_oneshot() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(Duration::milliseconds(1)).recv();
    })

    iotest!(fn test_io_timer_sleep_oneshot_forget() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(Duration::milliseconds(100000000000));
    })

    iotest!(fn oneshot_twice() {
        let mut timer = Timer::new().unwrap();
        let rx1 = timer.oneshot(Duration::milliseconds(10000));
        let rx = timer.oneshot(1);
        rx.recv();
        assert_eq!(rx1.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_oneshot_then_sleep() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.oneshot(Duration::milliseconds(100000000000));
        timer.sleep(Duration::milliseconds(1)); // this should invalidate rx

        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_sleep_periodic() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(Duration::milliseconds(1));
        rx.recv();
        rx.recv();
        rx.recv();
    })

    iotest!(fn test_io_timer_sleep_periodic_forget() {
        let mut timer = Timer::new().unwrap();
        timer.periodic(Duration::milliseconds(100000000000));
    })

    iotest!(fn test_io_timer_sleep_standalone() {
        sleep(Duration::milliseconds(1))
    })

    iotest!(fn oneshot() {
        let mut timer = Timer::new().unwrap();

        let rx = timer.oneshot(Duration::milliseconds(1));
        rx.recv();
        assert!(rx.recv_opt().is_err());

        let rx = timer.oneshot(Duration::milliseconds(1));
        rx.recv();
        assert!(rx.recv_opt().is_err());
    })

    iotest!(fn override() {
        let mut timer = Timer::new().unwrap();
        let orx = timer.oneshot(Duration::milliseconds(100));
        let prx = timer.periodic(Duration::milliseconds(100));
        timer.sleep(Duration::milliseconds(1));
        assert_eq!(orx.recv_opt(), Err(()));
        assert_eq!(prx.recv_opt(), Err(()));
        timer.oneshot(Duration::milliseconds(1)).recv();
    })

    iotest!(fn period() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(Duration::milliseconds(1));
        rx.recv();
        rx.recv();
        let rx2 = timer.periodic(Durtion::milliseconds(1));
        rx2.recv();
        rx2.recv();
    })

    iotest!(fn sleep() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(1));
        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn oneshot_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.oneshot(Duration::milliseconds(1));
        fail!();
    } #[should_fail])

    iotest!(fn period_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.periodic(Duration::milliseconds(1));
        fail!();
    } #[should_fail])

    iotest!(fn normal_fail() {
        let _timer = Timer::new().unwrap();
        fail!();
    } #[should_fail])

    iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
        // see issue #10375
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        // when we drop the TimerWatcher we're going to destroy the channel,
        // which must wake up the task on the other end
    })

    iotest!(fn reset_doesnt_switch_tasks() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.oneshot(Duration::milliseconds(1));
    })

    iotest!(fn reset_doesnt_switch_tasks2() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn sender_goes_away_oneshot() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.oneshot(Duration::milliseconds(1000))
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn sender_goes_away_period() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.periodic(Duration::milliseconds(1000))
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn receiver_goes_away_oneshot() {
        let mut timer1 = Timer::new().unwrap();
        timer1.oneshot(Duration::milliseconds(1));
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the previous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(Duration::milliseconds(2));
    })

    iotest!(fn receiver_goes_away_period() {
        let mut timer1 = Timer::new().unwrap();
        timer1.periodic(Duration::milliseconds(1));
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the previous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(Duration::milliseconds(2));
    })
}
<commit_msg>std: Restore missing timer examples<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Synchronous Timers

This module exposes the functionality to create timers, block the current task,
and create receivers which will receive notifications after a period of time.

*/

use comm::{Receiver, Sender, channel};
use time::Duration;
use io::{IoResult, IoError};
use kinds::Send;
use boxed::Box;
use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};

/// A synchronous timer object
///
/// Values of this type can be used to put the current task to sleep for a
/// period of time. Handles to this timer can also be created in the form of
/// receivers which will receive notifications over time.
///
/// # Example
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(10); // block the task for awhile
///
/// let timeout = timer.oneshot(10);
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(10);
/// loop {
///     periodic.recv();
///     // this loop is only executed once every 10ms
/// }
/// # }
/// ```
///
/// If only sleeping is necessary, then a convenience API is provided through
/// the `io::timer` module.
///
/// ```
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(5000);
/// # }
/// ```
pub struct Timer {
    obj: Box<RtioTimer + Send>,
}

struct TimerCallback { tx: Sender<()> }

fn in_ms(d: Duration) -> u64 {
    // FIXME: Do we really want to fail on negative duration?
    let ms = d.num_milliseconds();
    if ms < 0 { fail!("negative duration") }
    return ms as u64;
}

/// Sleep the current task for the specified duration.
pub fn sleep(duration: Duration) {
    let timer = Timer::new();
    let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");

    timer.sleep(duration)
}

impl Timer {
    /// Creates a new timer which can be used to put the current task to sleep
    /// for a number of milliseconds, or to possibly create channels which will
    /// get notified after an amount of time has passed.
    pub fn new() -> IoResult<Timer> {
        LocalIo::maybe_raise(|io| {
            io.timer_init().map(|t| Timer { obj: t })
        }).map_err(IoError::from_rtio_error)
    }

    /// Blocks the current task for the specified duration.
    ///
    /// Note that this function will cause any other receivers for this timer to
    /// be invalidated (the other end will be closed).
    pub fn sleep(&mut self, duration: Duration) {
        self.obj.sleep(in_ms(duration));
    }

    /// Creates a oneshot receiver which will have a notification sent when
    /// the specified duration has elapsed.
    ///
    /// This does *not* block the current task, but instead returns immediately.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::io::Timer;
    ///
    /// let mut timer = Timer::new().unwrap();
    /// let ten_milliseconds = timer.oneshot(10);
    ///
    /// for _ in range(0u, 100) { /* do work */ }
    ///
    /// // blocks until 10 ms after the `oneshot` call
    /// ten_milliseconds.recv();
    /// ```
    ///
    /// ```rust
    /// use std::io::Timer;
    ///
    /// // Incorrect, method chaining-style:
    /// let mut five_ms = Timer::new().unwrap().oneshot(5);
    /// // The timer object was destroyed, so this will always fail:
    /// // five_ms.recv()
    /// ```
    pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx });
        return rx
    }

    /// Creates a receiver which will have a continuous stream of notifications
    /// being sent each time the specified duration has elapsed.
    ///
    /// This does *not* block the current task, but instead returns
    /// immediately. The first notification will not be received immediately,
    /// but rather after the first duration.
    ///
    /// Note that this invalidates any previous receiver which has been created
    /// by this timer, and that the returned receiver will be invalidated once
    /// the timer is destroyed (when it falls out of scope). In particular, if
    /// this is called in method-chaining style, the receiver will be
    /// invalidated at the end of that statement, and all `recv` calls will
    /// fail.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::io::Timer;
    ///
    /// let mut timer = Timer::new().unwrap();
    /// let ten_milliseconds = timer.periodic(10);
    ///
    /// for _ in range(0u, 100) { /* do work */ }
    ///
    /// // blocks until 10 ms after the `periodic` call
    /// ten_milliseconds.recv();
    ///
    /// for _ in range(0u, 100) { /* do work */ }
    ///
    /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
    /// // previous `recv`)
    /// ten_milliseconds.recv();
    /// ```
    ///
    /// ```rust
    /// use std::io::Timer;
    ///
    /// // Incorrect, method chaining-style.
    /// let mut five_ms = Timer::new().unwrap().periodic(5);
    /// // The timer object was destroyed, so this will always fail:
    /// // five_ms.recv()
    /// ```
    pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
        let (tx, rx) = channel();
        self.obj.period(in_ms(duration), box TimerCallback { tx: tx });
        return rx
    }
}

impl Callback for TimerCallback {
    fn call(&mut self) {
        let _ = self.tx.send_opt(());
    }
}

#[cfg(test)]
mod test {
    use time::Duration;

    iotest!(fn test_io_timer_sleep_simple() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn test_io_timer_sleep_oneshot() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(Duration::milliseconds(1)).recv();
    })

    iotest!(fn test_io_timer_sleep_oneshot_forget() {
        let mut timer = Timer::new().unwrap();
        timer.oneshot(Duration::milliseconds(100000000000));
    })

    iotest!(fn oneshot_twice() {
        let mut timer = Timer::new().unwrap();
        let rx1 = timer.oneshot(Duration::milliseconds(10000));
        let rx = timer.oneshot(1);
        rx.recv();
        assert_eq!(rx1.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_oneshot_then_sleep() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.oneshot(Duration::milliseconds(100000000000));
        timer.sleep(Duration::milliseconds(1)); // this should invalidate rx

        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn test_io_timer_sleep_periodic() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(Duration::milliseconds(1));
        rx.recv();
        rx.recv();
        rx.recv();
    })

    iotest!(fn test_io_timer_sleep_periodic_forget() {
        let mut timer = Timer::new().unwrap();
        timer.periodic(Duration::milliseconds(100000000000));
    })

    iotest!(fn test_io_timer_sleep_standalone() {
        sleep(Duration::milliseconds(1))
    })

    iotest!(fn oneshot() {
        let mut timer = Timer::new().unwrap();

        let rx = timer.oneshot(Duration::milliseconds(1));
        rx.recv();
        assert!(rx.recv_opt().is_err());

        let rx = timer.oneshot(Duration::milliseconds(1));
        rx.recv();
        assert!(rx.recv_opt().is_err());
    })

    iotest!(fn override() {
        let mut timer = Timer::new().unwrap();
        let orx = timer.oneshot(Duration::milliseconds(100));
        let prx = timer.periodic(Duration::milliseconds(100));
        timer.sleep(Duration::milliseconds(1));
        assert_eq!(orx.recv_opt(), Err(()));
        assert_eq!(prx.recv_opt(), Err(()));
        timer.oneshot(Duration::milliseconds(1)).recv();
    })

    iotest!(fn period() {
        let mut timer = Timer::new().unwrap();
        let rx = timer.periodic(Duration::milliseconds(1));
        rx.recv();
        rx.recv();
        let rx2 = timer.periodic(Durtion::milliseconds(1));
        rx2.recv();
        rx2.recv();
    })

    iotest!(fn sleep() {
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(1));
        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn oneshot_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.oneshot(Duration::milliseconds(1));
        fail!();
    } #[should_fail])

    iotest!(fn period_fail() {
        let mut timer = Timer::new().unwrap();
        let _rx = timer.periodic(Duration::milliseconds(1));
        fail!();
    } #[should_fail])

    iotest!(fn normal_fail() {
        let _timer = Timer::new().unwrap();
        fail!();
    } #[should_fail])

    iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
        // see issue #10375
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        // when we drop the TimerWatcher we're going to destroy the channel,
        // which must wake up the task on the other end
    })

    iotest!(fn reset_doesnt_switch_tasks() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.oneshot(Duration::milliseconds(1));
    })

    iotest!(fn reset_doesnt_switch_tasks2() {
        // similar test to the one above.
        let mut timer = Timer::new().unwrap();
        let timer_rx = timer.periodic(Duration::milliseconds(1000));

        spawn(proc() {
            let _ = timer_rx.recv_opt();
        });

        timer.sleep(Duration::milliseconds(1));
    })

    iotest!(fn sender_goes_away_oneshot() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.oneshot(Duration::milliseconds(1000))
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn sender_goes_away_period() {
        let rx = {
            let mut timer = Timer::new().unwrap();
            timer.periodic(Duration::milliseconds(1000))
        };
        assert_eq!(rx.recv_opt(), Err(()));
    })

    iotest!(fn receiver_goes_away_oneshot() {
        let mut timer1 = Timer::new().unwrap();
        timer1.oneshot(Duration::milliseconds(1));
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the previous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(Duration::milliseconds(2));
    })

    iotest!(fn receiver_goes_away_period() {
        let mut timer1 = Timer::new().unwrap();
        timer1.periodic(Duration::milliseconds(1));
        let mut timer2 = Timer::new().unwrap();
        // while sleeping, the previous timer should fire and not have its
        // callback do something terrible.
        timer2.sleep(Duration::milliseconds(2));
    })
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{CryptoKVStorage, Error, GetResponse, KVStorage, Value};

/// This provides a light wrapper around KV storages to support a namespace. That namespace is
/// effectively prefixing all keys with then namespace value and "/" so a namespace of foo and a
/// key of bar becomes "foo/bar". Without a namespace, the key would just be "bar". This matches
/// how this library implements namespaces for Vault.
pub struct NamespacedStorage<T> {
    namespace: String,
    inner: T,
}

impl<T: KVStorage> KVStorage for NamespacedStorage<T> {
    fn available(&self) -> Result<(), Error> {
        self.inner.available()
    }

    fn get(&self, key: &str) -> Result<GetResponse, Error> {
        self.inner.get(&self.ns_name(key))
    }

    fn set(&mut self, key: &str, value: Value) -> Result<(), Error> {
        self.inner.set(&self.ns_name(key), value)
    }

    /// Note: This is not a namespace function
    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        self.inner.reset_and_clear()
    }
}

impl<T> NamespacedStorage<T> {
    pub fn new(storage: T, namespace: String) -> Self {
        NamespacedStorage {
            namespace,
            inner: storage,
        }
    }

    fn ns_name(&self, key: &str) -> String {
        format!("{}/{}", self.namespace, key)
    }

    pub fn namespace(&self) -> &str {
        &self.namespace
    }
}

impl<T: KVStorage> CryptoKVStorage for NamespacedStorage<T> {}

#[cfg(test)]
mod test {
    use super::*;
    use crate::OnDiskStorage;
    use libra_temppath::TempPath;

    #[test]
    fn test_different_namespaces() {
        let ns0 = "ns0";
        let ns1 = "ns1";
        let key = "key";

        let path_buf = TempPath::new().path().to_path_buf();

        let mut default = OnDiskStorage::new(path_buf.clone());

        let storage = OnDiskStorage::new(path_buf.clone());
        let mut nss0 = NamespacedStorage::new(storage, ns0.into());

        let storage = OnDiskStorage::new(path_buf);
        let mut nss1 = NamespacedStorage::new(storage, ns1.into());

        default.set(key, Value::U64(0)).unwrap();
        nss0.set(key, Value::U64(1)).unwrap();
        nss1.set(key, Value::U64(2)).unwrap();

        assert_eq!(default.get(key).unwrap().value, Value::U64(0));
        assert_eq!(nss0.get(key).unwrap().value, Value::U64(1));
        assert_eq!(nss1.get(key).unwrap().value, Value::U64(2));
    }

    #[test]
    fn test_shared_namespace() {
        let ns = "ns";
        let key = "key";

        let path_buf = TempPath::new().path().to_path_buf();

        let default = OnDiskStorage::new(path_buf.clone());

        let storage = OnDiskStorage::new(path_buf.clone());
        let mut nss = NamespacedStorage::new(storage, ns.into());

        let storage = OnDiskStorage::new(path_buf);
        let another_nss = NamespacedStorage::new(storage, ns.into());

        nss.set(key, Value::U64(1)).unwrap();
        default.get(key).unwrap_err();
        assert_eq!(nss.get(key).unwrap().value, Value::U64(1));
        assert_eq!(another_nss.get(key).unwrap().value, Value::U64(1));
    }
}
<commit_msg>Removing namespace from secure/storage/src/namespaced_storage.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{CryptoKVStorage, Error, GetResponse, KVStorage, Value};

/// This provides a light wrapper around KV storages to support a namespace. That namespace is
/// effectively prefixing all keys with then namespace value and "/" so a namespace of foo and a
/// key of bar becomes "foo/bar". Without a namespace, the key would just be "bar". This matches
/// how this library implements namespaces for Vault.
pub struct NamespacedStorage<T> {
    namespace: String,
    inner: T,
}

impl<T: KVStorage> KVStorage for NamespacedStorage<T> {
    fn available(&self) -> Result<(), Error> {
        self.inner.available()
    }

    fn get(&self, key: &str) -> Result<GetResponse, Error> {
        self.inner.get(&self.ns_name(key))
    }

    fn set(&mut self, key: &str, value: Value) -> Result<(), Error> {
        self.inner.set(&self.ns_name(key), value)
    }

    /// Note: This is not a namespace function
    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        self.inner.reset_and_clear()
    }
}

impl<T> NamespacedStorage<T> {
    pub fn new(storage: T, namespace: String) -> Self {
        NamespacedStorage {
            namespace,
            inner: storage,
        }
    }

    fn ns_name(&self, key: &str) -> String {
        format!("{}/{}", self.namespace, key)
    }
}

impl<T: KVStorage> CryptoKVStorage for NamespacedStorage<T> {}

#[cfg(test)]
mod test {
    use super::*;
    use crate::OnDiskStorage;
    use libra_temppath::TempPath;

    #[test]
    fn test_different_namespaces() {
        let ns0 = "ns0";
        let ns1 = "ns1";
        let key = "key";

        let path_buf = TempPath::new().path().to_path_buf();

        let mut default = OnDiskStorage::new(path_buf.clone());

        let storage = OnDiskStorage::new(path_buf.clone());
        let mut nss0 = NamespacedStorage::new(storage, ns0.into());

        let storage = OnDiskStorage::new(path_buf);
        let mut nss1 = NamespacedStorage::new(storage, ns1.into());

        default.set(key, Value::U64(0)).unwrap();
        nss0.set(key, Value::U64(1)).unwrap();
        nss1.set(key, Value::U64(2)).unwrap();

        assert_eq!(default.get(key).unwrap().value, Value::U64(0));
        assert_eq!(nss0.get(key).unwrap().value, Value::U64(1));
        assert_eq!(nss1.get(key).unwrap().value, Value::U64(2));
    }

    #[test]
    fn test_shared_namespace() {
        let ns = "ns";
        let key = "key";

        let path_buf = TempPath::new().path().to_path_buf();

        let default = OnDiskStorage::new(path_buf.clone());

        let storage = OnDiskStorage::new(path_buf.clone());
        let mut nss = NamespacedStorage::new(storage, ns.into());

        let storage = OnDiskStorage::new(path_buf);
        let another_nss = NamespacedStorage::new(storage, ns.into());

        nss.set(key, Value::U64(1)).unwrap();
        default.get(key).unwrap_err();
        assert_eq!(nss.get(key).unwrap().value, Value::U64(1));
        assert_eq!(another_nss.get(key).unwrap().value, Value::U64(1));
    }
}
<|endoftext|>


<commit_before>use crate::base::ModuleData;
use rustc_ast::ptr::P;
use rustc_ast::{token, Attribute, Item};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;

use std::path::{self, Path, PathBuf};

#[derive(Copy, Clone)]
pub enum DirOwnership {
    Owned {
        // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`.
        relative: Option<Ident>,
    },
    UnownedViaBlock,
}

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub file_path: PathBuf,
    pub dir_ownership: DirOwnership,
}

crate struct ParsedExternalMod {
    pub items: Vec<P<Item>>,
    pub inner_span: Span,
    pub file_path: PathBuf,
    pub dir_path: PathBuf,
    pub dir_ownership: DirOwnership,
}

crate fn parse_external_mod(
    sess: &Session,
    ident: Ident,
    span: Span, // The span to blame on errors.
    module: &ModuleData,
    mut dir_ownership: DirOwnership,
    attrs: &mut Vec<Attribute>,
) -> ParsedExternalMod {
    // We bail on the first error, but that error does not cause a fatal error... (1)
    let result: PResult<'_, _> = try {
        // Extract the file path and the new ownership.
        let mp = mod_file_path(sess, ident, span, &attrs, &module.dir_path, dir_ownership)?;
        dir_ownership = mp.dir_ownership;

        // Ensure file paths are acyclic.
        error_on_circular_module(&sess.parse_sess, span, &mp.file_path, &module.file_path_stack)?;

        // Actually parse the external file as a module.
        let mut parser = new_parser_from_file(&sess.parse_sess, &mp.file_path, Some(span));
        let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
        attrs.append(&mut inner_attrs);
        (items, inner_span, mp.file_path)
    };
    // (1) ...instead, we return a dummy module.
    let (items, inner_span, file_path) = result.map_err(|mut err| err.emit()).unwrap_or_default();

    // Extract the directory path for submodules of the module.
    let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();

    ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership }
}

fn error_on_circular_module<'a>(
    sess: &'a ParseSess,
    span: Span,
    file_path: &Path,
    file_path_stack: &[PathBuf],
) -> PResult<'a, ()> {
    if let Some(i) = file_path_stack.iter().position(|p| *p == file_path) {
        let mut err = String::from("circular modules: ");
        for p in &file_path_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&file_path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(span, &err[..]));
    }
    Ok(())
}

crate fn mod_dir_path(
    sess: &Session,
    ident: Ident,
    attrs: &[Attribute],
    module: &ModuleData,
    mut dir_ownership: DirOwnership,
) -> (PathBuf, DirOwnership) {
    let mut dir_path = module.dir_path.clone();
    if let Some(file_path) = sess.first_attr_value_str_by_name(attrs, sym::path) {
        dir_path.push(&*file_path.as_str());
        dir_ownership = DirOwnership::Owned { relative: None };
    } else {
        // We have to push on the current module name in the case of relative
        // paths in order to ensure that any additional module paths from inline
        // `mod x { ... }` come after the relative extension.
        //
        // For example, a `mod z { ... }` inside `x/y.rs` should set the current
        // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
        if let DirOwnership::Owned { relative } = &mut dir_ownership {
            if let Some(ident) = relative.take() {
                // Remove the relative offset.
                dir_path.push(&*ident.as_str());
            }
        }
        dir_path.push(&*ident.as_str());
    }

    (dir_path, dir_ownership)
}

fn mod_file_path<'a>(
    sess: &'a Session,
    ident: Ident,
    span: Span,
    attrs: &[Attribute],
    dir_path: &Path,
    dir_ownership: DirOwnership,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(file_path) = mod_file_path_from_attr(sess, attrs, dir_path) {
        // All `#[path]` files are treated as though they are a `mod.rs` file.
        // This means that `mod foo;` declarations inside `#[path]`-included
        // files are siblings,
        //
        // Note that this will produce weirdness when a file named `foo.rs` is
        // `#[path]` included and contains a `mod foo;` declaration.
        // If you encounter this, it's your own darn fault :P
        let dir_ownership = DirOwnership::Owned { relative: None };
        return Ok(ModulePathSuccess { file_path, dir_ownership });
    }

    let relative = match dir_ownership {
        DirOwnership::Owned { relative } => relative,
        DirOwnership::UnownedViaBlock => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(&sess.parse_sess, ident, span, relative, dir_path);
    match dir_ownership {
        DirOwnership::Owned { .. } => Ok(result?),
        DirOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(span, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(span, &msg);
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
fn mod_file_path_from_attr(
    sess: &Session,
    attrs: &[Attribute],
    dir_path: &Path,
) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?;
    let path_string = path_string.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    ident: Ident,
    span: Span,
    relative: Option<Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<ident>.rs` and `./foo/<ident>/mod.rs` rather than
    // `./<ident>.rs` and `./<ident>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = ident.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            file_path: default_path,
            dir_ownership: DirOwnership::Owned { relative: Some(ident) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            file_path: secondary_path,
            dir_ownership: DirOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0761,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<commit_msg>expand: Share some code between inline and out-of-line module treatment<commit_after>use crate::base::ModuleData;
use rustc_ast::ptr::P;
use rustc_ast::{token, Attribute, Item};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;

use std::path::{self, Path, PathBuf};

#[derive(Copy, Clone)]
pub enum DirOwnership {
    Owned {
        // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`.
        relative: Option<Ident>,
    },
    UnownedViaBlock,
}

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath<'a> {
    name: String,
    path_exists: bool,
    pub result: PResult<'a, ModulePathSuccess>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub file_path: PathBuf,
    pub dir_ownership: DirOwnership,
}

crate struct ParsedExternalMod {
    pub items: Vec<P<Item>>,
    pub inner_span: Span,
    pub file_path: PathBuf,
    pub dir_path: PathBuf,
    pub dir_ownership: DirOwnership,
}

crate fn parse_external_mod(
    sess: &Session,
    ident: Ident,
    span: Span, // The span to blame on errors.
    module: &ModuleData,
    mut dir_ownership: DirOwnership,
    attrs: &mut Vec<Attribute>,
) -> ParsedExternalMod {
    // We bail on the first error, but that error does not cause a fatal error... (1)
    let result: PResult<'_, _> = try {
        // Extract the file path and the new ownership.
        let mp = mod_file_path(sess, ident, span, &attrs, &module.dir_path, dir_ownership)?;
        dir_ownership = mp.dir_ownership;

        // Ensure file paths are acyclic.
        error_on_circular_module(&sess.parse_sess, span, &mp.file_path, &module.file_path_stack)?;

        // Actually parse the external file as a module.
        let mut parser = new_parser_from_file(&sess.parse_sess, &mp.file_path, Some(span));
        let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
        attrs.append(&mut inner_attrs);
        (items, inner_span, mp.file_path)
    };
    // (1) ...instead, we return a dummy module.
    let (items, inner_span, file_path) = result.map_err(|mut err| err.emit()).unwrap_or_default();

    // Extract the directory path for submodules of the module.
    let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();

    ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership }
}

fn error_on_circular_module<'a>(
    sess: &'a ParseSess,
    span: Span,
    file_path: &Path,
    file_path_stack: &[PathBuf],
) -> PResult<'a, ()> {
    if let Some(i) = file_path_stack.iter().position(|p| *p == file_path) {
        let mut err = String::from("circular modules: ");
        for p in &file_path_stack[i..] {
            err.push_str(&p.to_string_lossy());
            err.push_str(" -> ");
        }
        err.push_str(&file_path.to_string_lossy());
        return Err(sess.span_diagnostic.struct_span_err(span, &err[..]));
    }
    Ok(())
}

crate fn mod_dir_path(
    sess: &Session,
    ident: Ident,
    attrs: &[Attribute],
    module: &ModuleData,
    mut dir_ownership: DirOwnership,
) -> (PathBuf, DirOwnership) {
    if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
        // For inline modules file path from `#[path]` is actually the directory path
        // for historical reasons, so we don't pop the last segment here.
        return (file_path, DirOwnership::Owned { relative: None });
    }

    // We have to push on the current module name in the case of relative
    // paths in order to ensure that any additional module paths from inline
    // `mod x { ... }` come after the relative extension.
    //
    // For example, a `mod z { ... }` inside `x/y.rs` should set the current
    // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
    let mut dir_path = module.dir_path.clone();
    if let DirOwnership::Owned { relative } = &mut dir_ownership {
        if let Some(ident) = relative.take() {
            // Remove the relative offset.
            dir_path.push(&*ident.as_str());
        }
    }
    dir_path.push(&*ident.as_str());

    (dir_path, dir_ownership)
}

fn mod_file_path<'a>(
    sess: &'a Session,
    ident: Ident,
    span: Span,
    attrs: &[Attribute],
    dir_path: &Path,
    dir_ownership: DirOwnership,
) -> PResult<'a, ModulePathSuccess> {
    if let Some(file_path) = mod_file_path_from_attr(sess, attrs, dir_path) {
        // All `#[path]` files are treated as though they are a `mod.rs` file.
        // This means that `mod foo;` declarations inside `#[path]`-included
        // files are siblings,
        //
        // Note that this will produce weirdness when a file named `foo.rs` is
        // `#[path]` included and contains a `mod foo;` declaration.
        // If you encounter this, it's your own darn fault :P
        let dir_ownership = DirOwnership::Owned { relative: None };
        return Ok(ModulePathSuccess { file_path, dir_ownership });
    }

    let relative = match dir_ownership {
        DirOwnership::Owned { relative } => relative,
        DirOwnership::UnownedViaBlock => None,
    };
    let ModulePath { path_exists, name, result } =
        default_submod_path(&sess.parse_sess, ident, span, relative, dir_path);
    match dir_ownership {
        DirOwnership::Owned { .. } => Ok(result?),
        DirOwnership::UnownedViaBlock => {
            let _ = result.map_err(|mut err| err.cancel());
            error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
        }
    }
}

fn error_decl_mod_in_block<'a, T>(
    sess: &'a ParseSess,
    span: Span,
    path_exists: bool,
    name: &str,
) -> PResult<'a, T> {
    let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute";
    let mut err = sess.span_diagnostic.struct_span_err(span, msg);
    if path_exists {
        let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name);
        err.span_note(span, &msg);
    }
    Err(err)
}

/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
fn mod_file_path_from_attr(
    sess: &Session,
    attrs: &[Attribute],
    dir_path: &Path,
) -> Option<PathBuf> {
    // Extract path string from first `#[path = "path_string"]` attribute.
    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str();

    // On windows, the base path might have the form
    // `\\?\foo\bar` in which case it does not tolerate
    // mixed `/` and `\` separators, so canonicalize
    // `/` to `\`.
    #[cfg(windows)]
    let path_string = path_string.replace("/", "\\");

    Some(dir_path.join(&*path_string))
}

/// Returns a path to a module.
// Public for rustfmt usage.
pub fn default_submod_path<'a>(
    sess: &'a ParseSess,
    ident: Ident,
    span: Span,
    relative: Option<Ident>,
    dir_path: &Path,
) -> ModulePath<'a> {
    // If we're in a foo.rs file instead of a mod.rs file,
    // we need to look for submodules in
    // `./foo/<ident>.rs` and `./foo/<ident>/mod.rs` rather than
    // `./<ident>.rs` and `./<ident>/mod.rs`.
    let relative_prefix_string;
    let relative_prefix = if let Some(ident) = relative {
        relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
        &relative_prefix_string
    } else {
        ""
    };

    let mod_name = ident.name.to_string();
    let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
    let secondary_path_str =
        format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
    let default_path = dir_path.join(&default_path_str);
    let secondary_path = dir_path.join(&secondary_path_str);
    let default_exists = sess.source_map().file_exists(&default_path);
    let secondary_exists = sess.source_map().file_exists(&secondary_path);

    let result = match (default_exists, secondary_exists) {
        (true, false) => Ok(ModulePathSuccess {
            file_path: default_path,
            dir_ownership: DirOwnership::Owned { relative: Some(ident) },
        }),
        (false, true) => Ok(ModulePathSuccess {
            file_path: secondary_path,
            dir_ownership: DirOwnership::Owned { relative: None },
        }),
        (false, false) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0583,
                "file not found for module `{}`",
                mod_name,
            );
            err.help(&format!(
                "to create the module `{}`, create file \"{}\"",
                mod_name,
                default_path.display(),
            ));
            Err(err)
        }
        (true, true) => {
            let mut err = struct_span_err!(
                sess.span_diagnostic,
                span,
                E0761,
                "file for module `{}` found at both {} and {}",
                mod_name,
                default_path_str,
                secondary_path_str,
            );
            err.help("delete or rename one of them to remove the ambiguity");
            Err(err)
        }
    };

    ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
}
<|endoftext|>


<commit_before>use devices::{NodeId, ServiceId, ServiceKind};
use util::Exactly;
use values;

use serde::ser::Serializer;
use serde::de::Deserializer;

use std::cmp;

fn merge<T>(mut a: Vec<T>, mut b: Vec<T>) -> Vec<T> where T: Ord {
    a.append(&mut b);
    a.sort();
    a.dedup();
    a
}

/// A request for one or more nodes.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = NodeRequest::new()
///   .with_tags(vec!["entrance".to_owned()])
///   .with_inputs(vec![InputRequest::new() /* can be more restrictive */]);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeRequest {
    /// If `Exactly(id)`, return only the node with the corresponding id.
    #[serde(default)]
    pub id: Exactly<NodeId>,

    ///  Restrict results to nodes that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// Restrict results to nodes that have all the inputs in `inputs`.
    #[serde(default)]
    pub inputs: Vec<InputRequest>,

    /// Restrict results to nodes that have all the outputs in `outputs`.
    #[serde(default)]
    pub outputs: Vec<OutputRequest>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl NodeRequest {
    /// Create a new request that accepts all nodes.
    pub fn new() -> Self {
        Self::default()
    }

    /// Request for a node with a specific id.
    pub fn with_id(self, id: NodeId) -> Self {
        NodeRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    ///  Restrict results to nodes that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        NodeRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict results to nodes that have all the inputs in `inputs`.
    pub fn with_inputs(mut self, mut inputs: Vec<InputRequest>) -> Self {
        NodeRequest {
            inputs: {self.inputs.append(&mut inputs); self.inputs},
            .. self
        }
    }

    /// Restrict results to nodes that have all the outputs in `outputs`.
    pub fn with_outputs(mut self, mut outputs: Vec<OutputRequest>) -> Self {
        NodeRequest {
            outputs: {self.outputs.append(&mut outputs); self.outputs},
            .. self
        }
    }

    /// Restrict results to nodes that are accepted by two requests.
    pub fn and(mut self, mut other: NodeRequest) -> Self {
        NodeRequest {
            id: self.id.and(other.id),
            tags: merge(self.tags, other.tags),
            inputs: {self.inputs.append(&mut other.inputs); self.inputs},
            outputs: {self.outputs.append(&mut other.outputs); self.outputs},
            private: (),
        }
    }
}

/// A request for one or more input services.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = InputRequest::new()
///   .with_parent(NodeId::new("foxbox".to_owned()))
///   .with_kind(ServiceKind::CurrentTimeOfDay);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct InputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Eactly(id)`, return only services that are children of
    /// node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exatly(k)`, restrict results to services that produce values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support polling
    /// with the acceptable period.
    #[serde(default)]
    pub poll: Option<Period>,

    /// If `Some(r)`, restrict results to services that support trigger
    /// with the acceptable period.
    #[serde(default)]
    pub trigger: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl InputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        Self::default()
    }

    /// Restrict to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        InputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        InputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        InputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        InputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support polling with the acceptable
    /// period
    pub fn with_poll(self, period: Period) -> Self {
        InputRequest {
            poll: Period::and_option(self.poll, Some(period)),
            .. self
        }
    }

    /// Restrict to services that support trigger with the acceptable
    /// period
    pub fn with_trigger(self, period: Period) -> Self {
        InputRequest {
            trigger: Period::and_option(self.trigger, Some(period)),
            .. self
        }
    }

    /// Restrict to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        InputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            poll: Period::and_option(self.poll, other.poll),
            trigger: Period::and_option(self.trigger, other.trigger),
            private: (),
        }
    }
}

/// A request for one or more output services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct OutputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Exactly(id)`, return only services that are immediate children
    /// of node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exactly(k)`, restrict results to services that accept values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support pushing
    /// with the acceptable period.
    #[serde(default)]
    pub push: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl OutputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        OutputRequest::default()
    }

    /// Request to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        OutputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        OutputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        OutputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        OutputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support push with the acceptable
    /// period
    pub fn with_push(self, period: Period) -> Self {
        OutputRequest {
            push: Period::and_option(self.push, Some(period)),
            .. self
        }
    }

    /// Restrict results to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        OutputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            push: Period::and_option(self.push, other.push),
            private: (),
        }
    }
}

/// An acceptable interval of time.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Period {
    #[serde(default)]
    pub min: Option<values::ValDuration>,
    #[serde(default)]
    pub max: Option<values::ValDuration>,
}
impl Period {
    pub fn and(self, other: Self) -> Self {
        let min = match (self.min, other.min) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(min1), Some(min2)) => Some(cmp::max(min1, min2))
        };
        let max = match (self.max, other.max) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(max1), Some(max2)) => Some(cmp::min(max1, max2))
        };
        Period {
            min: min,
            max: max
        }
    }

    pub fn and_option(a: Option<Self>, b: Option<Self>) -> Option<Self> {
        match (a, b) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(a), Some(b)) => Some(a.and(b))
        }
    }

    pub fn matches(&self, duration: &values::ValDuration) -> bool {
        if let Some(ref min) = self.min {
            if min > duration {
                return false;
            }
        }
        if let Some(ref max) = self.max {
            if max < duration {
                return false;
            }
        }
        return true;
    }
}
<commit_msg>[fxbox/taxonomy] Period::match_option<commit_after>use devices::{NodeId, ServiceId, ServiceKind};
use util::Exactly;
use values;

use serde::ser::Serializer;
use serde::de::Deserializer;

use std::cmp;

fn merge<T>(mut a: Vec<T>, mut b: Vec<T>) -> Vec<T> where T: Ord {
    a.append(&mut b);
    a.sort();
    a.dedup();
    a
}

/// A request for one or more nodes.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = NodeRequest::new()
///   .with_tags(vec!["entrance".to_owned()])
///   .with_inputs(vec![InputRequest::new() /* can be more restrictive */]);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeRequest {
    /// If `Exactly(id)`, return only the node with the corresponding id.
    #[serde(default)]
    pub id: Exactly<NodeId>,

    ///  Restrict results to nodes that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// Restrict results to nodes that have all the inputs in `inputs`.
    #[serde(default)]
    pub inputs: Vec<InputRequest>,

    /// Restrict results to nodes that have all the outputs in `outputs`.
    #[serde(default)]
    pub outputs: Vec<OutputRequest>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl NodeRequest {
    /// Create a new request that accepts all nodes.
    pub fn new() -> Self {
        Self::default()
    }

    /// Request for a node with a specific id.
    pub fn with_id(self, id: NodeId) -> Self {
        NodeRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    ///  Restrict results to nodes that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        NodeRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict results to nodes that have all the inputs in `inputs`.
    pub fn with_inputs(mut self, mut inputs: Vec<InputRequest>) -> Self {
        NodeRequest {
            inputs: {self.inputs.append(&mut inputs); self.inputs},
            .. self
        }
    }

    /// Restrict results to nodes that have all the outputs in `outputs`.
    pub fn with_outputs(mut self, mut outputs: Vec<OutputRequest>) -> Self {
        NodeRequest {
            outputs: {self.outputs.append(&mut outputs); self.outputs},
            .. self
        }
    }

    /// Restrict results to nodes that are accepted by two requests.
    pub fn and(mut self, mut other: NodeRequest) -> Self {
        NodeRequest {
            id: self.id.and(other.id),
            tags: merge(self.tags, other.tags),
            inputs: {self.inputs.append(&mut other.inputs); self.inputs},
            outputs: {self.outputs.append(&mut other.outputs); self.outputs},
            private: (),
        }
    }
}

/// A request for one or more input services.
///
///
/// # Example
///
/// ```
/// use fxbox_taxonomy::requests::*;
/// use fxbox_taxonomy::devices::*;
///
/// let request = InputRequest::new()
///   .with_parent(NodeId::new("foxbox".to_owned()))
///   .with_kind(ServiceKind::CurrentTimeOfDay);
/// ```
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct InputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Eactly(id)`, return only services that are children of
    /// node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exatly(k)`, restrict results to services that produce values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support polling
    /// with the acceptable period.
    #[serde(default)]
    pub poll: Option<Period>,

    /// If `Some(r)`, restrict results to services that support trigger
    /// with the acceptable period.
    #[serde(default)]
    pub trigger: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl InputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        Self::default()
    }

    /// Restrict to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        InputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        InputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Restrict to a service with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        InputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        InputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support polling with the acceptable
    /// period
    pub fn with_poll(self, period: Period) -> Self {
        InputRequest {
            poll: Period::and_option(self.poll, Some(period)),
            .. self
        }
    }

    /// Restrict to services that support trigger with the acceptable
    /// period
    pub fn with_trigger(self, period: Period) -> Self {
        InputRequest {
            trigger: Period::and_option(self.trigger, Some(period)),
            .. self
        }
    }

    /// Restrict to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        InputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            poll: Period::and_option(self.poll, other.poll),
            trigger: Period::and_option(self.trigger, other.trigger),
            private: (),
        }
    }
}

/// A request for one or more output services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct OutputRequest {
    /// If `Exactly(id)`, return only the service with the corresponding id.
    #[serde(default)]
    pub id: Exactly<ServiceId>,

    /// If `Exactly(id)`, return only services that are immediate children
    /// of node `id`.
    #[serde(default)]
    pub parent: Exactly<NodeId>,

    ///  Restrict results to services that have all the tags in `tags`.
    #[serde(default)]
    pub tags: Vec<String>,

    /// If `Exactly(k)`, restrict results to services that accept values
    /// of kind `k`.
    #[serde(default)]
    pub kind: Exactly<ServiceKind>,

    /// If `Some(r)`, restrict results to services that support pushing
    /// with the acceptable period.
    #[serde(default)]
    pub push: Option<Period>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl OutputRequest {
    /// Create a new request that accepts all input services.
    pub fn new() -> Self {
        OutputRequest::default()
    }

    /// Request to a service with a specific id.
    pub fn with_id(self, id: ServiceId) -> Self {
        OutputRequest {
            id: self.id.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific parent.
    pub fn with_parent(self, id: NodeId) -> Self {
        OutputRequest {
            parent: self.parent.and(Exactly::Exactly(id)),
            .. self
        }
    }

    /// Request to services with a specific kind.
    pub fn with_kind(self, kind: ServiceKind) -> Self {
        OutputRequest {
            kind: self.kind.and(Exactly::Exactly(kind)),
            .. self
        }
    }

    ///  Restrict to services that have all the tags in `tags`.
    pub fn with_tags(self, tags: Vec<String>) -> Self {
        OutputRequest {
            tags: merge(self.tags, tags),
            .. self
        }
    }

    /// Restrict to services that support push with the acceptable
    /// period
    pub fn with_push(self, period: Period) -> Self {
        OutputRequest {
            push: Period::and_option(self.push, Some(period)),
            .. self
        }
    }

    /// Restrict results to services that are accepted by two requests.
    pub fn and(self, other: Self) -> Self {
        OutputRequest {
            id: self.id.and(other.id),
            parent: self.parent.and(other.parent),
            tags: merge(self.tags, other.tags),
            kind: self.kind.and(other.kind),
            push: Period::and_option(self.push, other.push),
            private: (),
        }
    }
}

/// An acceptable interval of time.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Period {
    #[serde(default)]
    pub min: Option<values::ValDuration>,
    #[serde(default)]
    pub max: Option<values::ValDuration>,
}
impl Period {
    pub fn and(self, other: Self) -> Self {
        let min = match (self.min, other.min) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(min1), Some(min2)) => Some(cmp::max(min1, min2))
        };
        let max = match (self.max, other.max) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(max1), Some(max2)) => Some(cmp::min(max1, max2))
        };
        Period {
            min: min,
            max: max
        }
    }

    pub fn and_option(a: Option<Self>, b: Option<Self>) -> Option<Self> {
        match (a, b) {
            (None, x@_) => x,
            (x@_, None) => x,
            (Some(a), Some(b)) => Some(a.and(b))
        }
    }

    pub fn matches(&self, duration: &values::ValDuration) -> bool {
        if let Some(ref min) = self.min {
            if min > duration {
                return false;
            }
        }
        if let Some(ref max) = self.max {
            if max < duration {
                return false;
            }
        }
        return true;
    }

    pub fn matches_option(period: &Option<Self>, duration: &Option<values::ValDuration>) -> bool {
        match (period, duration) {
            (&Some(ref period), &Some(ref duration))
                if !period.matches(duration) =>
                return false,
            (&None, &Some(_)) => return false,
            _ => return true
        }
    }
}
<|endoftext|>