<commit_before>// TODO: deny missing docs
#![allow(missing_docs)]

use lookup::{Response, Result as LookupResult, Error as LookupError};

use itertools::Itertools;
use std::collections::HashMap;
use trust_dns::rr::{RData, Record};

#[derive(Debug)]
pub struct Statistics<'a> {
    pub num_of_samples: usize,
    pub num_of_ok_samples: usize,
    pub num_of_err_samples: usize,
    pub min_num_of_records: usize,
    pub max_num_of_records: usize,
    pub record_counts: HashMap<String, (&'a Record, u16)>,
    pub failures: Vec<&'a LookupError>,
    pub alerts: Vec<Alert>
}

impl<'a> Statistics<'a> {
    pub fn from(responses: &'a [LookupResult<Response>]) -> Self {
        let num_of_samples = responses.len();

        let (responses, failures): (Vec<_>, Vec<_>) =
            responses.into_iter().partition(|x| x.is_ok());
        let responses: Vec<&Response> =
            responses.into_iter().map(|x| x.as_ref().unwrap()).collect();
        let failures: Vec<&LookupError> = failures
            .into_iter()
            .map(|x| x.as_ref().unwrap_err())
            .collect();

        let num_of_ok_samples = responses.len();
        let num_of_err_samples = failures.len();

        let (min_num_of_records, max_num_of_records) = responses
            .iter()
            .map(|x| x.answers.len())
            .fold((::std::usize::MAX, 0), |(mut min, mut max), x| {
                if min > x {
                    min = x
                };
                if max < x {
                    max = x
                };
                (min, max)
            });

        let mut record_counts = HashMap::new();
        for response in &responses {
            for rr in &response.answers {
                let key = format!("{:?}-{:?}", rr.rr_type(), rr.rdata());
                let value = record_counts.entry(key).or_insert((rr, 0u16));
                value.1 += 1
            }
        }

        let alerts = alerts(responses.as_slice());

        Statistics {
            num_of_samples,
            num_of_ok_samples,
            num_of_err_samples,
            min_num_of_records,
            max_num_of_records,
            record_counts,
            failures,
            alerts
        }
    }
}

#[derive(Debug)]
pub enum Alert {
    SoaSnDiverge(HashMap<u32, u32>),
}

// TODO: &[&T] is totally weird
fn alerts(responses: &[&Response]) -> Vec<Alert> {
    let mut alerts = Vec::new();
    if let Some(serials) = check_soa_serial_numbers(responses) {
        alerts.push(serials)
    }

    alerts
}

// TODO: &[&T] is totally weird
fn check_soa_serial_numbers(responses: &[&Response]) -> Option<Alert> {
    let mut serial_counts = HashMap::new();
    responses
        .iter()
        .map(|r| r.answers
            .iter()
            .map(|a| match *a.rdata() {
                RData::SOA(ref soa) => Some(soa.serial()),
                _ => None
            })
        )
        .flatten()
        .filter_map(|x| x)
        .for_each(|key| {
            let value = serial_counts.entry(key).or_insert(0);
            *value += 1;
        });

    if !serial_counts.is_empty() {
        Some(Alert::SoaSnDiverge(serial_counts))
    } else {
        None
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use lookup::ErrorKind as LookupErrorKind;
    use std::net::IpAddr;
    use std::str::FromStr;
    use trust_dns::rr::{domain, RecordType};
    use trust_dns::rr::rdata::SOA;

    #[test]
    fn simple_statistics() {
        let records_1: Vec<Record> = vec![
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::A,
                100
            ),
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::MX,
                99
            ),
        ];
        let response_1 = Response {
            server: IpAddr::from([127, 0, 0, 1]),
            answers: records_1,
        };
        let records_2: Vec<Record> = vec![
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::A,
                98
            ),
        ];
        let response_2 = Response {
            server: IpAddr::from([127, 0, 0, 2]),
            answers: records_2,
        };
        let responses: Vec<LookupResult<Response>> =
            vec![
                Ok(response_1),
                Ok(response_2),
                Err(
                    LookupErrorKind::QueryError(1, RecordType::AAAA, IpAddr::from([127, 0, 0, 3]))
                        .into()
                ),
            ];

        let statistics = Statistics::from(&responses);

        assert_eq!(statistics.num_of_samples, 3);
        assert_eq!(statistics.num_of_ok_samples, 2);
        assert_eq!(statistics.num_of_err_samples, 1);
        assert_eq!(statistics.min_num_of_records, 1);
        assert_eq!(statistics.max_num_of_records, 2);
        assert_eq!(statistics.record_counts.len(), 2);

        let mut record_counts: Vec<_> = statistics
            .record_counts
            .values()
            .map(|&(_, count)| count)
            .collect();
        record_counts.sort();
        assert_eq!(record_counts, vec![1, 2]);

        assert_eq!(statistics.failures.len(), 1);
    }

    #[test]
    fn test_alert_for_diverging_soa_serials() {
        let records_1: Vec<Record> = vec![
            Record::from_rdata(
                domain::Name::from_str("www.example.com").unwrap(),
                99,
                RecordType::SOA,
                RData::SOA(
                    SOA::new(
                        domain::Name::from_str("sns.dns.icann.org.").unwrap(),
                        domain::Name::from_str("noc.dns.icann.org.").unwrap(),
                        100,
                        7200,
                        3600,
                        1209600,
                        3600
                    )
                )
            )
        ];
        let response_1 = Response {
            server: IpAddr::from([127, 0, 0, 1]),
            answers: records_1,
        };
        let records_2: Vec<Record> = vec![
            Record::from_rdata(
                domain::Name::from_str("www.example.com").unwrap(),
                99,
                RecordType::SOA,
                RData::SOA(
                    SOA::new(
                        domain::Name::from_str("sns.dns.icann.org.").unwrap(),
                        domain::Name::from_str("noc.dns.icann.org.").unwrap(),
                        200,
                        7200,
                        3600,
                        1209600,
                        3600
                    )
                )
            )];
        let response_2 = Response {
            server: IpAddr::from([127, 0, 0, 2]),
            answers: records_2,
        };
        let responses: Vec<Response> = vec![response_1, response_2, ];

        let alerts = alerts(&responses.iter().collect::<Vec<_>>());

        assert_eq!(alerts.len(), 1);
        let &Alert::SoaSnDiverge(ref soa_serials) = alerts.first().unwrap();
        let mut serials = soa_serials.keys().collect::<Vec<_>>();
        serials.sort();
        assert_eq!(serials, vec![&100, &200]);
        let mut counts = soa_serials.values().collect::<Vec<_>>();
        counts.sort();
        assert_eq!(counts, vec![&1, &1]);
    }
}
<commit_msg>Minor fix for alerts check<commit_after>// TODO: deny missing docs
#![allow(missing_docs)]

use lookup::{Response, Result as LookupResult, Error as LookupError};

use itertools::Itertools;
use std::collections::HashMap;
use trust_dns::rr::{RData, Record};

#[derive(Debug)]
pub struct Statistics<'a> {
    pub num_of_samples: usize,
    pub num_of_ok_samples: usize,
    pub num_of_err_samples: usize,
    pub min_num_of_records: usize,
    pub max_num_of_records: usize,
    pub record_counts: HashMap<String, (&'a Record, u16)>,
    pub failures: Vec<&'a LookupError>,
    pub alerts: Vec<Alert>
}

impl<'a> Statistics<'a> {
    pub fn from(responses: &'a [LookupResult<Response>]) -> Self {
        let num_of_samples = responses.len();

        let (responses, failures): (Vec<_>, Vec<_>) =
            responses.into_iter().partition(|x| x.is_ok());
        let responses: Vec<&Response> =
            responses.into_iter().map(|x| x.as_ref().unwrap()).collect();
        let failures: Vec<&LookupError> = failures
            .into_iter()
            .map(|x| x.as_ref().unwrap_err())
            .collect();

        let num_of_ok_samples = responses.len();
        let num_of_err_samples = failures.len();

        let (min_num_of_records, max_num_of_records) = responses
            .iter()
            .map(|x| x.answers.len())
            .fold((::std::usize::MAX, 0), |(mut min, mut max), x| {
                if min > x {
                    min = x
                };
                if max < x {
                    max = x
                };
                (min, max)
            });

        let mut record_counts = HashMap::new();
        for response in &responses {
            for rr in &response.answers {
                let key = format!("{:?}-{:?}", rr.rr_type(), rr.rdata());
                let value = record_counts.entry(key).or_insert((rr, 0u16));
                value.1 += 1
            }
        }

        let alerts = alerts(responses.as_slice());

        Statistics {
            num_of_samples,
            num_of_ok_samples,
            num_of_err_samples,
            min_num_of_records,
            max_num_of_records,
            record_counts,
            failures,
            alerts
        }
    }
}

#[derive(Debug)]
pub enum Alert {
    SoaSnDiverge(HashMap<u32, u32>),
}

// TODO: &[&T] is totally weird
fn alerts(responses: &[&Response]) -> Vec<Alert> {
    let mut alerts = Vec::new();
    if let Some(serials) = check_soa_serial_numbers(responses) {
        alerts.push(serials)
    }

    alerts
}

// TODO: &[&T] is totally weird
fn check_soa_serial_numbers(responses: &[&Response]) -> Option<Alert> {
    let mut serial_counts = HashMap::new();
    responses
        .iter()
        .map(|r| r.answers
            .iter()
            .map(|a| match *a.rdata() {
                RData::SOA(ref soa) => Some(soa.serial()),
                _ => None
            })
        )
        .flatten()
        .filter_map(|x| x)
        .for_each(|key| {
            let value = serial_counts.entry(key).or_insert(0);
            *value += 1;
        });

    if serial_counts.len() > 1 {
        Some(Alert::SoaSnDiverge(serial_counts))
    } else {
        None
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use lookup::ErrorKind as LookupErrorKind;
    use std::net::IpAddr;
    use std::str::FromStr;
    use trust_dns::rr::{domain, RecordType};
    use trust_dns::rr::rdata::SOA;

    #[test]
    fn simple_statistics() {
        let records_1: Vec<Record> = vec![
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::A,
                100
            ),
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::MX,
                99
            ),
        ];
        let response_1 = Response {
            server: IpAddr::from([127, 0, 0, 1]),
            answers: records_1,
        };
        let records_2: Vec<Record> = vec![
            Record::with(
                domain::Name::from_str("www.example.com").unwrap(),
                RecordType::A,
                98
            ),
        ];
        let response_2 = Response {
            server: IpAddr::from([127, 0, 0, 2]),
            answers: records_2,
        };
        let responses: Vec<LookupResult<Response>> =
            vec![
                Ok(response_1),
                Ok(response_2),
                Err(
                    LookupErrorKind::QueryError(1, RecordType::AAAA, IpAddr::from([127, 0, 0, 3]))
                        .into()
                ),
            ];

        let statistics = Statistics::from(&responses);

        assert_eq!(statistics.num_of_samples, 3);
        assert_eq!(statistics.num_of_ok_samples, 2);
        assert_eq!(statistics.num_of_err_samples, 1);
        assert_eq!(statistics.min_num_of_records, 1);
        assert_eq!(statistics.max_num_of_records, 2);
        assert_eq!(statistics.record_counts.len(), 2);

        let mut record_counts: Vec<_> = statistics
            .record_counts
            .values()
            .map(|&(_, count)| count)
            .collect();
        record_counts.sort();
        assert_eq!(record_counts, vec![1, 2]);

        assert_eq!(statistics.failures.len(), 1);
    }

    #[test]
    fn test_alert_for_diverging_soa_serials() {
        let records_1: Vec<Record> = vec![
            Record::from_rdata(
                domain::Name::from_str("www.example.com").unwrap(),
                99,
                RecordType::SOA,
                RData::SOA(
                    SOA::new(
                        domain::Name::from_str("sns.dns.icann.org.").unwrap(),
                        domain::Name::from_str("noc.dns.icann.org.").unwrap(),
                        100,
                        7200,
                        3600,
                        1209600,
                        3600
                    )
                )
            )
        ];
        let response_1 = Response {
            server: IpAddr::from([127, 0, 0, 1]),
            answers: records_1,
        };
        let records_2: Vec<Record> = vec![
            Record::from_rdata(
                domain::Name::from_str("www.example.com").unwrap(),
                99,
                RecordType::SOA,
                RData::SOA(
                    SOA::new(
                        domain::Name::from_str("sns.dns.icann.org.").unwrap(),
                        domain::Name::from_str("noc.dns.icann.org.").unwrap(),
                        200,
                        7200,
                        3600,
                        1209600,
                        3600
                    )
                )
            )];
        let response_2 = Response {
            server: IpAddr::from([127, 0, 0, 2]),
            answers: records_2,
        };
        let responses: Vec<Response> = vec![response_1, response_2, ];

        let alerts = alerts(&responses.iter().collect::<Vec<_>>());

        assert_eq!(alerts.len(), 1);
        let &Alert::SoaSnDiverge(ref soa_serials) = alerts.first().unwrap();
        let mut serials = soa_serials.keys().collect::<Vec<_>>();
        serials.sort();
        assert_eq!(serials, vec![&100, &200]);
        let mut counts = soa_serials.values().collect::<Vec<_>>();
        counts.sort();
        assert_eq!(counts, vec![&1, &1]);
    }
}
<|endoftext|>


<commit_before>use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
use std::os::unix::io::RawFd;
use std::ptr::{null, null_mut};
use libc::{self, c_int};
use Result;
use errno::Errno;
use sys::signal::SigSet;
use sys::time::{TimeSpec, TimeVal};

pub use libc::FD_SETSIZE;

#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);

impl FdSet {
    pub fn new() -> FdSet {
        let mut fdset = mem::MaybeUninit::uninit();
        unsafe {
            libc::FD_ZERO(fdset.as_mut_ptr());
            FdSet(fdset.assume_init())
        }
    }

    pub fn insert(&mut self, fd: RawFd) {
        unsafe { libc::FD_SET(fd, &mut self.0) };
    }

    pub fn remove(&mut self, fd: RawFd) {
        unsafe { libc::FD_CLR(fd, &mut self.0) };
    }

    pub fn contains(&self, fd: RawFd) -> bool {
        let mut copy = self.0;
        unsafe { libc::FD_ISSET(fd, &mut copy) }
    }

    pub fn clear(&mut self) {
        unsafe { libc::FD_ZERO(&mut self.0) };
    }

    /// Finds the highest file descriptor in the set.
    ///
    /// Returns `None` if the set is empty.
    ///
    /// This can be used to calculate the `nfds` parameter of the [`select`] function.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # fn main() {
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// assert_eq!(set.highest(), Some(9));
    /// # }
    /// ```
    ///
    /// [`select`]: fn.select.html
    pub fn highest(&self) -> Option<RawFd> {
        self.fds().next_back()
    }

    /// Returns an iterator over the file descriptors in the set.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # use std::os::unix::io::RawFd;
    /// # fn main() {
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// let fds: Vec<RawFd> = set.fds().collect();
    /// assert_eq!(fds, vec![4, 9]);
    /// # }
    /// ```
    #[inline]
    pub fn fds(&self) -> Fds {
        Fds {
            set: self,
            range: 0..FD_SETSIZE,
        }
    }
}

impl Default for FdSet {
    fn default() -> Self {
        Self::new()
    }
}

/// Iterator over `FdSet`.
#[derive(Clone, Debug)]
pub struct Fds<'a> {
    set: &'a FdSet,
    range: Range<usize>,
}

impl<'a> Iterator for Fds<'a> {
    type Item = RawFd;

    fn next(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.range.size_hint();
        (0, upper)
    }
}

impl<'a> DoubleEndedIterator for Fds<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next_back() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }
}

impl<'a> FusedIterator for Fds<'a> {}

/// Monitors file descriptors for readiness
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, `timeout` has an implementation-defined value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for being ready to read.
/// * `writefds`: File descriptors to check for being ready to write.
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
///
/// # References
///
/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn select<'a, N, R, W, E, T>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
                                 timeout: T) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a mut TimeVal>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
        .unwrap_or(null_mut());

    let res = unsafe {
        libc::select(nfds, readfds, writefds, errorfds, timeout)
    };

    Errno::result(res)
}

/// Monitors file descriptors for readiness with an altered signal mask.
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, the original signal mask is restored.
///
/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for read readiness
/// * `writefds`: File descriptors to check for write readiness
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
///    ready (`None` to set no alternative signal mask).
///
/// # References
///
/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
///
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
    timeout: T,
                                     sigmask: S) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a TimeSpec>>,
    S: Into<Option<&'a SigSet>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let sigmask = sigmask.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
    let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());

    let res = unsafe {
        libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
    };

    Errno::result(res)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::unix::io::RawFd;
    use sys::time::{TimeVal, TimeValLike};
    use unistd::{write, pipe};

    #[test]
    fn fdset_insert() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);

        assert!(fd_set.contains(7));
    }

    #[test]
    fn fdset_remove() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);
        fd_set.remove(7);

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_clear() {
        let mut fd_set = FdSet::new();
        fd_set.insert(1);
        fd_set.insert((FD_SETSIZE / 2) as RawFd);
        fd_set.insert((FD_SETSIZE - 1) as RawFd);

        fd_set.clear();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_highest() {
        let mut set = FdSet::new();
        assert_eq!(set.highest(), None);
        set.insert(0);
        assert_eq!(set.highest(), Some(0));
        set.insert(90);
        assert_eq!(set.highest(), Some(90));
        set.remove(0);
        assert_eq!(set.highest(), Some(90));
        set.remove(90);
        assert_eq!(set.highest(), None);

        set.insert(4);
        set.insert(5);
        set.insert(7);
        assert_eq!(set.highest(), Some(7));
    }

    #[test]
    fn test_select() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(None,
                             &mut fd_set,
                             None,
                             None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds2() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }
}
<commit_msg>Remove unnecessary fn main wrapper in example<commit_after>use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
use std::os::unix::io::RawFd;
use std::ptr::{null, null_mut};
use libc::{self, c_int};
use Result;
use errno::Errno;
use sys::signal::SigSet;
use sys::time::{TimeSpec, TimeVal};

pub use libc::FD_SETSIZE;

#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);

impl FdSet {
    pub fn new() -> FdSet {
        let mut fdset = mem::MaybeUninit::uninit();
        unsafe {
            libc::FD_ZERO(fdset.as_mut_ptr());
            FdSet(fdset.assume_init())
        }
    }

    pub fn insert(&mut self, fd: RawFd) {
        unsafe { libc::FD_SET(fd, &mut self.0) };
    }

    pub fn remove(&mut self, fd: RawFd) {
        unsafe { libc::FD_CLR(fd, &mut self.0) };
    }

    pub fn contains(&self, fd: RawFd) -> bool {
        let mut copy = self.0;
        unsafe { libc::FD_ISSET(fd, &mut copy) }
    }

    pub fn clear(&mut self) {
        unsafe { libc::FD_ZERO(&mut self.0) };
    }

    /// Finds the highest file descriptor in the set.
    ///
    /// Returns `None` if the set is empty.
    ///
    /// This can be used to calculate the `nfds` parameter of the [`select`] function.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # fn main() {
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// assert_eq!(set.highest(), Some(9));
    /// # }
    /// ```
    ///
    /// [`select`]: fn.select.html
    pub fn highest(&self) -> Option<RawFd> {
        self.fds().next_back()
    }

    /// Returns an iterator over the file descriptors in the set.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # use std::os::unix::io::RawFd;
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// let fds: Vec<RawFd> = set.fds().collect();
    /// assert_eq!(fds, vec![4, 9]);
    /// ```
    #[inline]
    pub fn fds(&self) -> Fds {
        Fds {
            set: self,
            range: 0..FD_SETSIZE,
        }
    }
}

impl Default for FdSet {
    fn default() -> Self {
        Self::new()
    }
}

/// Iterator over `FdSet`.
#[derive(Clone, Debug)]
pub struct Fds<'a> {
    set: &'a FdSet,
    range: Range<usize>,
}

impl<'a> Iterator for Fds<'a> {
    type Item = RawFd;

    fn next(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.range.size_hint();
        (0, upper)
    }
}

impl<'a> DoubleEndedIterator for Fds<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next_back() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }
}

impl<'a> FusedIterator for Fds<'a> {}

/// Monitors file descriptors for readiness
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, `timeout` has an implementation-defined value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for being ready to read.
/// * `writefds`: File descriptors to check for being ready to write.
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
///
/// # References
///
/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn select<'a, N, R, W, E, T>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
                                 timeout: T) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a mut TimeVal>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
        .unwrap_or(null_mut());

    let res = unsafe {
        libc::select(nfds, readfds, writefds, errorfds, timeout)
    };

    Errno::result(res)
}

/// Monitors file descriptors for readiness with an altered signal mask.
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, the original signal mask is restored.
///
/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for read readiness
/// * `writefds`: File descriptors to check for write readiness
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
///    ready (`None` to set no alternative signal mask).
///
/// # References
///
/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
///
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
    timeout: T,
                                     sigmask: S) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a TimeSpec>>,
    S: Into<Option<&'a SigSet>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let sigmask = sigmask.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
    let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());

    let res = unsafe {
        libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
    };

    Errno::result(res)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::unix::io::RawFd;
    use sys::time::{TimeVal, TimeValLike};
    use unistd::{write, pipe};

    #[test]
    fn fdset_insert() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);

        assert!(fd_set.contains(7));
    }

    #[test]
    fn fdset_remove() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);
        fd_set.remove(7);

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_clear() {
        let mut fd_set = FdSet::new();
        fd_set.insert(1);
        fd_set.insert((FD_SETSIZE / 2) as RawFd);
        fd_set.insert((FD_SETSIZE - 1) as RawFd);

        fd_set.clear();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_highest() {
        let mut set = FdSet::new();
        assert_eq!(set.highest(), None);
        set.insert(0);
        assert_eq!(set.highest(), Some(0));
        set.insert(90);
        assert_eq!(set.highest(), Some(90));
        set.remove(0);
        assert_eq!(set.highest(), Some(90));
        set.remove(90);
        assert_eq!(set.highest(), None);

        set.insert(4);
        set.insert(5);
        set.insert(7);
        assert_eq!(set.highest(), Some(7));
    }

    #[test]
    fn test_select() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(None,
                             &mut fd_set,
                             None,
                             None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds2() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }
}
<|endoftext|>


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

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, EntropyRng};
use prng::hc128::Hc128Core;
use {Distribution, Uniform, Rng, Error};
use reseeding::ReseedingRng;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory. Cloning this handle just produces a new
/// reference to the same thread-local generator.
///
/// [`thread_rng`]: fn.thread_rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `thread_rng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: struct.Hc128Rng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(bytes) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

/// DEPRECATED: use `thread_rng().gen()` instead.
///
/// Generates a random value using the thread-local random number generator.
///
/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for
/// documentation of the entropy source and [`Rand`] for documentation of
/// distributions and type-specific generation.
///
/// # Examples
///
/// ```
/// let x = rand::random::<u8>();
/// println!("{}", x);
///
/// let y = rand::random::<f64>();
/// println!("{}", y);
///
/// if rand::random() { // generates a boolean
///     println!("Better lucky than good!");
/// }
/// ```
///
/// If you're calling `random()` in a loop, caching the generator as in the
/// following example can increase performance.
///
/// ```
/// use rand::Rng;
///
/// let mut v = vec![1, 2, 3];
///
/// for x in v.iter_mut() {
///     *x = rand::random()
/// }
///
/// // can be made faster by caching thread_rng
///
/// let mut rng = rand::thread_rng();
///
/// for x in v.iter_mut() {
///     *x = rng.gen();
/// }
/// ```
///
/// [`thread_rng`]: fn.thread_rng.html
/// [`Rand`]: trait.Rand.html
#[deprecated(since="0.5.0", note="removed in favor of thread_rng().gen()")]
#[inline]
pub fn random<T>() -> T where Uniform: Distribution<T> {
    thread_rng().gen()
}

#[cfg(test)]
mod test {
    use Rng;

    #[test]
    #[cfg(feature="std")]
    #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
    fn test_thread_rng() {
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }

    #[test]
    #[allow(deprecated)]
    fn test_random() {
        use super::random;
        // not sure how to test this aside from just getting some values
        let _n : usize = random();
        let _f : f32 = random();
        let _o : Option<Option<i8>> = random();
        let _many : ((),
                     (usize,
                      isize,
                      Option<(u32, (bool,))>),
                     (u8, i8, u16, i16, u32, i32, u64, i64),
                     (f32, (f64, (f64,)))) = random();
    }
}
<commit_msg>Fix unused import warning with WASM<commit_after>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, EntropyRng};
use prng::hc128::Hc128Core;
use {Distribution, Uniform, Rng, Error};
use reseeding::ReseedingRng;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory. Cloning this handle just produces a new
/// reference to the same thread-local generator.
///
/// [`thread_rng`]: fn.thread_rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `thread_rng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: struct.Hc128Rng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(bytes) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

/// DEPRECATED: use `thread_rng().gen()` instead.
///
/// Generates a random value using the thread-local random number generator.
///
/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for
/// documentation of the entropy source and [`Rand`] for documentation of
/// distributions and type-specific generation.
///
/// # Examples
///
/// ```
/// let x = rand::random::<u8>();
/// println!("{}", x);
///
/// let y = rand::random::<f64>();
/// println!("{}", y);
///
/// if rand::random() { // generates a boolean
///     println!("Better lucky than good!");
/// }
/// ```
///
/// If you're calling `random()` in a loop, caching the generator as in the
/// following example can increase performance.
///
/// ```
/// use rand::Rng;
///
/// let mut v = vec![1, 2, 3];
///
/// for x in v.iter_mut() {
///     *x = rand::random()
/// }
///
/// // can be made faster by caching thread_rng
///
/// let mut rng = rand::thread_rng();
///
/// for x in v.iter_mut() {
///     *x = rng.gen();
/// }
/// ```
///
/// [`thread_rng`]: fn.thread_rng.html
/// [`Rand`]: trait.Rand.html
#[deprecated(since="0.5.0", note="removed in favor of thread_rng().gen()")]
#[inline]
pub fn random<T>() -> T where Uniform: Distribution<T> {
    thread_rng().gen()
}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }

    #[test]
    #[allow(deprecated)]
    fn test_random() {
        use super::random;
        // not sure how to test this aside from just getting some values
        let _n : usize = random();
        let _f : f32 = random();
        let _o : Option<Option<i8>> = random();
        let _many : ((),
                     (usize,
                      isize,
                      Option<(u32, (bool,))>),
                     (u8, i8, u16, i16, u32, i32, u64, i64),
                     (f32, (f64, (f64,)))) = random();
    }
}
<|endoftext|>


<commit_before>//! Eligibility trace types
use std::ops::{Deref, DerefMut};

pub trait Trace<G: crate::linalg::MatrixLike>: Deref<Target = G> + DerefMut {
    fn update(&mut self, grad: &G);

    fn scale(&mut self, factor: f64) { self.map_inplace(|g| g * factor); }

    fn scaled_update(&mut self, factor: f64, grad: &G) {
        self.scale(factor);
        self.update(grad);
    }

    fn reset(&mut self) { self.scale(0.0) }
}

import_all!(accumulating);
import_all!(dutch);
import_all!(replacing);
<commit_msg>docs(traces): add full-stop to module doc<commit_after>//! Eligibility trace types.
use std::ops::{Deref, DerefMut};

pub trait Trace<G: crate::linalg::MatrixLike>: Deref<Target = G> + DerefMut {
    fn update(&mut self, grad: &G);

    fn scale(&mut self, factor: f64) { self.map_inplace(|g| g * factor); }

    fn scaled_update(&mut self, factor: f64, grad: &G) {
        self.scale(factor);
        self.update(grad);
    }

    fn reset(&mut self) { self.scale(0.0) }
}

import_all!(accumulating);
import_all!(dutch);
import_all!(replacing);
<|endoftext|>


<commit_before>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

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

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}
macro_rules! ignore_ident{
    ($id:ident, $($t:tt)*) => {$($t)*};
}
macro_rules! rev_for_each_ident{
    ($m:ident, ) => {};
    ($m:ident, $i0:ident, $($i:ident,)*) => {
        rev_for_each_ident!($m, $($i,)*);
        $m!($i0);
    };
}

macro_rules! impl_tuple_collect {
    ($($Y:ident),*) => (
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, mut item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                macro_rules! replace_item{($i:ident) => {
                    item = replace($i, item);
                }};
                rev_for_each_ident!(replace_item, $($Y,)*);
                drop(item);
            }
        }
    )
}

impl_tuple_collect!(a);
impl_tuple_collect!(a, b);
impl_tuple_collect!(a, b, c);
impl_tuple_collect!(a, b, c, d);
impl_tuple_collect!(a, b, c, d, e);
impl_tuple_collect!(a, b, c, d, e, f);
impl_tuple_collect!(a, b, c, d, e, f, g);
impl_tuple_collect!(a, b, c, d, e, f, g, h);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j, k);
impl_tuple_collect!(a, b, c, d, e, f, g, h, i, j, k, l);
<commit_msg>More macro cleverness (5) loop over suffixes via macro<commit_after>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.is_empty() {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or_else(|| buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

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

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! count_ident{
    () => {0};
    ($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
}
macro_rules! ignore_ident{
    ($id:ident, $($t:tt)*) => {$($t)*};
}
macro_rules! rev_for_each_ident{
    ($m:ident, ) => {};
    ($m:ident, $i0:ident, $($i:ident,)*) => {
        rev_for_each_ident!($m, $($i,)*);
        $m!($i0);
    };
}

macro_rules! impl_tuple_collect {
    ($dummy:ident,) => {}; // stop
    ($dummy:ident, $($Y:ident,)*) => (
        impl_tuple_collect!($($Y,)*);
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
            type Item = A;
            type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = A>
            {
                let mut iter = iter.into_iter();

                Some(($(
                    { let $Y = iter.next()?; $Y },
                )*))
            }

            fn num_items() -> usize {
                count_ident!($($Y,)*)
            }

            fn left_shift_push(&mut self, mut item: A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                macro_rules! replace_item{($i:ident) => {
                    item = replace($i, item);
                }};
                rev_for_each_ident!(replace_item, $($Y,)*);
                drop(item);
            }
        }
    )
}
impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::Deref;
use std::sync::Arc;

pub struct AView<T: 'static> {
    /// This is actually the Arc
    ptr: *const u8,
    val: &'static T,
}

impl<T> AView<T> {
    pub fn new<'a, U: 'static, F: FnOnce(&'a U) -> &'a T>(arc: &'a Arc<U>, f: F) -> AView<T> {
        let val_ptr = f(&*arc) as *const T;
        let val = unsafe { val_ptr.as_ref().unwrap() };
        let ptr = Arc::into_raw(arc.clone()) as *const u8;
        AView { val, ptr }
    }

    pub fn value(v: T) -> AView<T> {
        let a = Arc::new(v);
        AView::new(&a, |r| r)
    }
}

impl<T> AsRef<T> for AView<T> {
    fn as_ref(&self) -> &T {
        self.val
    }
}

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

    fn deref(&self) -> &T {
        self.val
    }
}

impl<T: fmt::Debug> fmt::Debug for AView<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "AView: {:?}", self.as_ref())
    }
}

impl<T> Clone for AView<T> {
    fn clone(&self) -> AView<T> {
        unsafe {
            let a = Arc::from_raw(self.ptr);
            let c = AView {
                ptr: Arc::into_raw(a.clone()),
                val: self.val,
            };
            Arc::into_raw(a);
            c
        }
    }
}

unsafe impl<T: Send> Send for AView<T> {}
unsafe impl<T: Send + Sync> Sync for AView<T> {}

impl<T> Drop for AView<T> {
    fn drop(&mut self) {
        unsafe {
            drop(Arc::from_raw(self.ptr));
        }
    }
}
<commit_msg>Require T: Send + Sync for AView's Send impl<commit_after>use std::fmt;
use std::ops::Deref;
use std::sync::Arc;

pub struct AView<T: 'static> {
    /// This is actually the Arc
    ptr: *const u8,
    val: &'static T,
}

impl<T> AView<T> {
    pub fn new<'a, U: 'static, F: FnOnce(&'a U) -> &'a T>(arc: &'a Arc<U>, f: F) -> AView<T> {
        let val_ptr = f(&*arc) as *const T;
        let val = unsafe { val_ptr.as_ref().unwrap() };
        let ptr = Arc::into_raw(arc.clone()) as *const u8;
        AView { val, ptr }
    }

    pub fn value(v: T) -> AView<T> {
        let a = Arc::new(v);
        AView::new(&a, |r| r)
    }
}

impl<T> AsRef<T> for AView<T> {
    fn as_ref(&self) -> &T {
        self.val
    }
}

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

    fn deref(&self) -> &T {
        self.val
    }
}

impl<T: fmt::Debug> fmt::Debug for AView<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "AView: {:?}", self.as_ref())
    }
}

impl<T> Clone for AView<T> {
    fn clone(&self) -> AView<T> {
        unsafe {
            let a = Arc::from_raw(self.ptr);
            let c = AView {
                ptr: Arc::into_raw(a.clone()),
                val: self.val,
            };
            Arc::into_raw(a);
            c
        }
    }
}

unsafe impl<T: Send + Sync> Send for AView<T> {}
unsafe impl<T: Send + Sync> Sync for AView<T> {}

impl<T> Drop for AView<T> {
    fn drop(&mut self) {
        unsafe {
            drop(Arc::from_raw(self.ptr));
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsString;
use std::io::Result;
use std::os::unix::prelude::OsStringExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};

fn git_command(path: impl AsRef<Path>, subcommand: &[&str]) -> Result<Output> {
    let git_path = path
        .as_ref()
        .to_str()
        .expect("Repository path must be a valid UTF-8 string");

    let mut args = vec!["-C", git_path];
    args.extend(subcommand);

    Command::new("git").args(&args).output()
}

pub fn repo_hash(path: impl AsRef<Path>) -> Option<String> {
    let output = git_command(path.as_ref(), &["rev-parse", "--short", "HEAD"]).ok()?;
    if !output.status.success() {
        return None;
    }
    let hash = String::from_utf8(output.stdout).ok()?;
    let hash = hash.trim_end_matches('\n');

    if dirty(path) {
        Some(format!("{}+", hash))
    } else {
        Some(hash.into())
    }
}

fn dirty(path: impl AsRef<Path>) -> bool {
    match git_command(path.as_ref(), &["ls-files", "-m"]) {
        Ok(modified_files) => !modified_files.stdout.is_empty(),
        Err(_) => false,
    }
}

fn gitmodules_config(subcommand: &[&str]) -> Option<String> {
    let mut args = vec!["config", "-f", ".gitmodules", "-z"];
    args.extend(subcommand);
    let output = git_command(Path::new("."), &args).ok()?;

    if !output.status.success() {
        return None;
    }

    let mut result = String::from_utf8(output.stdout).ok()?;
    assert_eq!(result.pop(), Some('\0'));
    Some(result)
}

fn path_command(path: impl AsRef<Path>, subcommand: &[&str]) -> Option<PathBuf> {
    let mut output = git_command(path, subcommand).ok()?;

    if !output.status.success() {
        return None;
    }

    assert_eq!(
        output
            .stdout
            .pop()
            .map(|c| c as u32)
            .and_then(std::char::from_u32),
        Some('\n')
    );
    let toplevel = OsString::from_vec(output.stdout);
    Some(toplevel.into())
}

pub fn toplevel(path: impl AsRef<Path>) -> Option<PathBuf> {
    path_command(path, &["rev-parse", "--show-toplevel"])
}

// Only build.rs uses this
#[allow(dead_code)]
pub fn git_dir(path: impl AsRef<Path>) -> Option<PathBuf> {
    path_command(path, &["rev-parse", "--git-dir"])
}

pub(crate) fn repo_remote_url(path: impl AsRef<Path>) -> Option<String> {
    // Find the subsection that defines the module for the given path:
    let key_for_path = gitmodules_config(&[
        "--name-only",
        "--get-regexp",
        r"submodule\..+\.path",
        &format!("^{}$", path.as_ref().display()),
    ])?;

    let subsection = key_for_path
        .strip_suffix(".path")
        .expect("submodule.<subsection>.path should end with '.path'");

    gitmodules_config(&["--get", &format!("{}.url", subsection)])
}
<commit_msg>Always output git short revisions with 12 characters<commit_after>use std::ffi::OsString;
use std::io::Result;
use std::os::unix::prelude::OsStringExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};

fn git_command(path: impl AsRef<Path>, subcommand: &[&str]) -> Result<Output> {
    let git_path = path
        .as_ref()
        .to_str()
        .expect("Repository path must be a valid UTF-8 string");

    let mut args = vec!["-C", git_path];
    args.extend(subcommand);

    Command::new("git").args(&args).output()
}

pub fn repo_hash(path: impl AsRef<Path>) -> Option<String> {
    let output = git_command(path.as_ref(), &["rev-parse", "--short=12", "HEAD"]).ok()?;
    if !output.status.success() {
        return None;
    }
    let hash = String::from_utf8(output.stdout).ok()?;
    let hash = hash.trim_end_matches('\n');

    if dirty(path) {
        Some(format!("{}+", hash))
    } else {
        Some(hash.into())
    }
}

fn dirty(path: impl AsRef<Path>) -> bool {
    match git_command(path.as_ref(), &["ls-files", "-m"]) {
        Ok(modified_files) => !modified_files.stdout.is_empty(),
        Err(_) => false,
    }
}

fn gitmodules_config(subcommand: &[&str]) -> Option<String> {
    let mut args = vec!["config", "-f", ".gitmodules", "-z"];
    args.extend(subcommand);
    let output = git_command(Path::new("."), &args).ok()?;

    if !output.status.success() {
        return None;
    }

    let mut result = String::from_utf8(output.stdout).ok()?;
    assert_eq!(result.pop(), Some('\0'));
    Some(result)
}

fn path_command(path: impl AsRef<Path>, subcommand: &[&str]) -> Option<PathBuf> {
    let mut output = git_command(path, subcommand).ok()?;

    if !output.status.success() {
        return None;
    }

    assert_eq!(
        output
            .stdout
            .pop()
            .map(|c| c as u32)
            .and_then(std::char::from_u32),
        Some('\n')
    );
    let toplevel = OsString::from_vec(output.stdout);
    Some(toplevel.into())
}

pub fn toplevel(path: impl AsRef<Path>) -> Option<PathBuf> {
    path_command(path, &["rev-parse", "--show-toplevel"])
}

// Only build.rs uses this
#[allow(dead_code)]
pub fn git_dir(path: impl AsRef<Path>) -> Option<PathBuf> {
    path_command(path, &["rev-parse", "--git-dir"])
}

pub(crate) fn repo_remote_url(path: impl AsRef<Path>) -> Option<String> {
    // Find the subsection that defines the module for the given path:
    let key_for_path = gitmodules_config(&[
        "--name-only",
        "--get-regexp",
        r"submodule\..+\.path",
        &format!("^{}$", path.as_ref().display()),
    ])?;

    let subsection = key_for_path
        .strip_suffix(".path")
        .expect("submodule.<subsection>.path should end with '.path'");

    gitmodules_config(&["--get", &format!("{}.url", subsection)])
}
<|endoftext|>