<commit_before>//! `coresimd`

#[macro_use]
mod macros;

#[macro_use]
mod ppsv;

/// Platform independent SIMD vector types and operations.
///
/// This is an **unstable** module for portable SIMD operations. This module
/// has not yet gone through an RFC and is likely to change, but feedback is
/// always welcome!
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod simd {
    pub use coresimd::ppsv::*;
}

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "wasm32")]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "powerpc64")]
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
mod arm;
#[cfg(target_arch = "wasm32")]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
mod powerpc64;

mod nvptx;
<commit_msg>tag private modules with doc(cfg)<commit_after>//! `coresimd`

#[macro_use]
mod macros;

#[macro_use]
mod ppsv;

/// Platform independent SIMD vector types and operations.
///
/// This is an **unstable** module for portable SIMD operations. This module
/// has not yet gone through an RFC and is likely to change, but feedback is
/// always welcome!
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod simd {
    pub use coresimd::ppsv::*;
}

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "wasm32")]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "powerpc64")]
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;
#[cfg(target_arch = "wasm32")]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

mod nvptx;
<|endoftext|>


<commit_before>//! The server is the top-level API that one uses.

use std::io::net::ip::IpAddr;
use std::io::net::ip::SocketAddr;
use std::io::{TcpListener, TcpStream, Listener, Acceptor, IoResult};
use std::io::net::tcp::TcpAcceptor;

use state::State;
use transport::Transport;
use connection::Connection;
use uuid::Uuid;
use result::GossipResult;
use addr::Addr;

/// A server/node within a single gossip cluster.
pub struct Server<'a, T> {
    pub id: Uuid,
    pub addr: Addr,
    state: State,
    transport: T,
    peers: Vec<Server<'a, T>>
}

impl<'a, T: Transport> Server<'a, T> {
    /// Create a new server given an address (ipv4 or ipv6) and a port.
    /// This function will **not** do any connection initializations. This
    /// is handled by further methods.
    pub fn new(transport: T) -> GossipResult<Server<'a, T>> {
        Ok(Server {
            id: Uuid::new_v4(),
            addr: transport.addr(),
            state: State::new(),
            transport: transport,
            peers: Vec::new()
        })
    }

    // Try and join a specific cluster given a peer node.
    pub fn join(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        try!(self.transport.join(ip, port, &*self))
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::net::ip::Ipv4Addr;
    use std::io::net::tcp::TcpStream;
    use tcp::transport::TcpTransport;
    use transport::Transport;

    #[test]
    fn new_server() {
        //let tcp = TcpTransport::listen("127.0.0.1", 5666).unwrap();
        //let server = Server::new("127.0.0.1", 4989, tcp).unwrap();

        //assert_eq!(server.ip, "127.0.0.1");
        //assert_eq!(server.port, 4989);
    }

}
<commit_msg>more tests<commit_after>//! The server is the top-level API that one uses.

use std::io::net::ip::IpAddr;
use std::io::net::ip::SocketAddr;
use std::io::{TcpListener, TcpStream, Listener, Acceptor, IoResult};
use std::io::net::tcp::TcpAcceptor;

use state::State;
use transport::Transport;
use connection::Connection;
use uuid::Uuid;
use result::GossipResult;
use addr::Addr;

/// A server/node within a single gossip cluster.
pub struct Server<'a, T> {
    pub id: Uuid,
    pub addr: Addr,
    state: State,
    transport: T,
    peers: Vec<Server<'a, T>>
}

impl<'a, T: Transport> Server<'a, T> {
    /// Create a new server given an address (ipv4 or ipv6) and a port.
    /// This function will **not** do any connection initializations. This
    /// is handled by further methods.
    pub fn new(transport: T) -> GossipResult<Server<'a, T>> {
        Ok(Server {
            id: Uuid::new_v4(),
            addr: transport.addr(),
            state: State::new(),
            transport: transport,
            peers: Vec::new()
        })
    }

    // Try and join a specific cluster given a peer node.
    pub fn join(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        try!(self.transport.join(ip, port, &*self))
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::net::ip::Ipv4Addr;
    use std::io::net::tcp::TcpStream;
    use tcp::transport::TcpTransport;
    use transport::Transport;

    #[test]
    fn new_server() {
        let tcp = TcpTransport::listen("127.0.0.1", 5666).unwrap();
        let server = Server::new(tcp).unwrap();

        assert_eq!(server.addr.ip.as_slice(), "127.0.0.1");
        assert_eq!(server.addr.port, 5666);
    }

    #[test]
    fn empty_peers() {
        let tcp = TcpTransport::listen("127.0.0.1", 5665).unwrap();
        let server = Server::new(tcp).unwrap();

        assert_eq!(server.peers.len(), 0);
    }
}
<|endoftext|>


<commit_before>use context::timeout;
use device::pic;
use device::serial::{COM1, COM2};
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use time;
use context;

//resets to 0 in context::switch()
pub static PIT_TICKS: AtomicUsize = ATOMIC_USIZE_INIT;

unsafe fn trigger(irq: u8) {
    extern {
        fn irq_trigger(irq: u8);
    }

    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_set(irq - 8);
            pic::MASTER.ack();
            pic::SLAVE.ack();
        } else {
            pic::MASTER.mask_set(irq);
            pic::MASTER.ack();
        }
    }

    irq_trigger(irq);
}

pub unsafe fn acknowledge(irq: usize) {
    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_clear(irq as u8 - 8);
        } else {
            pic::MASTER.mask_clear(irq as u8);
        }
    }
}

interrupt!(pit, {
    // Saves CPU time by not sending IRQ event irq_trigger(0);

    const PIT_RATE: u64 = 2250286;

    {
        let mut offset = time::OFFSET.lock();
        let sum = offset.1 + PIT_RATE;
        offset.1 = sum % 1000000000;
        offset.0 += sum / 1000000000;
    }

    pic::MASTER.ack();

    if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
        context::switch();
    }

    // Any better way of doing this?
    timeout::trigger();
});

interrupt!(keyboard, {
    trigger(1);
});

interrupt!(cascade, {
    // No need to do any operations on cascade
    pic::MASTER.ack();
});

interrupt!(com2, {
    COM2.lock().receive();
    pic::MASTER.ack();
});

interrupt!(com1, {
    COM1.lock().receive();
    pic::MASTER.ack();
});

interrupt!(lpt2, {
    trigger(5);
});

interrupt!(floppy, {
    trigger(6);
});

interrupt!(lpt1, {
    trigger(7);
});

interrupt!(rtc, {
    trigger(8);
});

interrupt!(pci1, {
    trigger(9);
});

interrupt!(pci2, {
    trigger(10);
});

interrupt!(pci3, {
    trigger(11);
});

interrupt!(mouse, {
    trigger(12);
});

interrupt!(fpu, {
    trigger(13);
});

interrupt!(ata1, {
    trigger(14);
});

interrupt!(ata2, {
    trigger(15);
});
<commit_msg>Disable preemption until paging bug is fixed<commit_after>use context::timeout;
use device::pic;
use device::serial::{COM1, COM2};
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use time;
use context;

//resets to 0 in context::switch()
pub static PIT_TICKS: AtomicUsize = ATOMIC_USIZE_INIT;

unsafe fn trigger(irq: u8) {
    extern {
        fn irq_trigger(irq: u8);
    }

    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_set(irq - 8);
            pic::MASTER.ack();
            pic::SLAVE.ack();
        } else {
            pic::MASTER.mask_set(irq);
            pic::MASTER.ack();
        }
    }

    irq_trigger(irq);
}

pub unsafe fn acknowledge(irq: usize) {
    if irq < 16 {
        if irq >= 8 {
            pic::SLAVE.mask_clear(irq as u8 - 8);
        } else {
            pic::MASTER.mask_clear(irq as u8);
        }
    }
}

interrupt!(pit, {
    // Saves CPU time by not sending IRQ event irq_trigger(0);

    const PIT_RATE: u64 = 2250286;

    {
        let mut offset = time::OFFSET.lock();
        let sum = offset.1 + PIT_RATE;
        offset.1 = sum % 1000000000;
        offset.0 += sum / 1000000000;
    }

    pic::MASTER.ack();

    /*
    if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
        context::switch();
    }
    */

    // Any better way of doing this?
    timeout::trigger();
});

interrupt!(keyboard, {
    trigger(1);
});

interrupt!(cascade, {
    // No need to do any operations on cascade
    pic::MASTER.ack();
});

interrupt!(com2, {
    COM2.lock().receive();
    pic::MASTER.ack();
});

interrupt!(com1, {
    COM1.lock().receive();
    pic::MASTER.ack();
});

interrupt!(lpt2, {
    trigger(5);
});

interrupt!(floppy, {
    trigger(6);
});

interrupt!(lpt1, {
    trigger(7);
});

interrupt!(rtc, {
    trigger(8);
});

interrupt!(pci1, {
    trigger(9);
});

interrupt!(pci2, {
    trigger(10);
});

interrupt!(pci3, {
    trigger(11);
});

interrupt!(mouse, {
    trigger(12);
});

interrupt!(fpu, {
    trigger(13);
});

interrupt!(ata1, {
    trigger(14);
});

interrupt!(ata2, {
    trigger(15);
});
<|endoftext|>


<commit_before>use super::plumbing::*;
use super::*;

use std::fmt::{self, Debug};

/// The `split` function takes arbitrary data and a closure that knows how to
/// split it, and turns this into a `ParallelIterator`.
pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    Split {
        data: data,
        splitter: splitter,
    }
}

/// `Split` is a parallel iterator using arbitrary data and a splitting function.
/// This struct is created by the [`split()`] function.
///
/// [`split()`]: fn.split.html
#[derive(Clone)]
pub struct Split<D, S> {
    data: D,
    splitter: S,
}

impl<D: Debug, S> Debug for Split<D, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Split")
            .field("data", &self.data)
            .finish()
    }
}

impl<D, S> ParallelIterator for Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync + Send
{
    type Item = D;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer {
            data: self.data,
            splitter: &self.splitter,
        };
        bridge_unindexed(producer, consumer)
    }
}

struct SplitProducer<'a, D, S: 'a> {
    data: D,
    splitter: &'a S,
}

impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    type Item = D;

    fn split(mut self) -> (Self, Option<Self>) {
        let splitter = self.splitter;
        let (left, right) = splitter(self.data);
        self.data = left;
        (self,
         right.map(|data| {
                       SplitProducer {
                           data: data,
                           splitter: splitter,
                       }
                   }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume(self.data)
    }
}
<commit_msg>Add example of split() usage<commit_after>use super::plumbing::*;
use super::*;

use std::fmt::{self, Debug};

/// The `split` function takes arbitrary data and a closure that knows how to
/// split it, and turns this into a `ParallelIterator`.
///
/// # Examples
///
/// ```
/// // This is a range of bi-dimensional indices
/// #[derive(Debug)]
/// struct Range2D {
///     // Horizontal range of indices
///     pub rx: Range<usize>,
///
///     // Vertical range of indices
///     pub ry: Range<usize>,
/// }
///
/// // We want to recursively split it by the largest dimension until we have
/// // enough sub-ranges to feed our mighty multi-core CPU. This function
/// // carries out one such split.
/// fn split_range(r2: Range2D) -> (Range2D, Option<Range2D>) {
///     // Decide on which axis (horizontal/vertical) the range should be split
///     let width = r2.rx.end - r2.rx.start;
///     let height = r2.ry.end - r2.ry.start;
///     if width >= height {
///         // We are mathematically unable to split the range if there is only
///         // one point inside of it, but we could stop splitting before that.
///         if width <= 1 { return (r2, None); }
///
///         // Here, our range is considered large enough to be splittable on
///         // the horizontal axis
///         let midpoint = r2.rx.start + (r2.rx.end - r2.rx.start) / 2;
///         let out1 = Range2D {
///             rx: Range {
///                 start: r2.rx.start,
///                 end: midpoint,
///             },
///             ry: r2.ry.clone(),
///         };
///         let out2 = Range2D {
///             rx: Range {
///                 start: midpoint,
///                 end: r2.rx.end,
///             },
///             ry: r2.ry,
///         };
///         (out1, Some(out2))
///     } else {
///         // This is essentially the same work as above, but vertically
///         if height <= 1 { return (r2, None); }
///         let midpoint = r2.ry.start + (r2.ry.end - r2.ry.start) / 2;
///         let out1 = Range2D {
///             rx: r2.rx.clone(),
///             ry: Range {
///                 start: r2.ry.start,
///                 end: midpoint,
///             },
///         };
///         let out2 = Range2D {
///             rx: r2.rx,
///             ry: Range {
///                 start: midpoint,
///                 end: r2.ry.end,
///             },
///         };
///         (out1, Some(out2))
///     }
/// }
///
/// // By using iter::split, Rayon will gladly do the recursive splitting for us
/// let range = Range2D { rx: 0..800, ry: 0..600 };
/// iter::split(range, split_range).for_each(|sub_range| {
///     // If the sub-ranges were indeed split by the largest dimension, then
///     // if no dimension was twice larger than the other initially, this
///     // property will remain true in the final sub-ranges.
///     let width = sub_range.rx.end - sub_range.rx.start;
///     let height = sub_range.ry.end - sub_range.ry.start;
///     assert!((width < 2 * height) && (height < 2 * width));
/// });
/// ```
///
pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    Split {
        data: data,
        splitter: splitter,
    }
}

/// `Split` is a parallel iterator using arbitrary data and a splitting function.
/// This struct is created by the [`split()`] function.
///
/// [`split()`]: fn.split.html
#[derive(Clone)]
pub struct Split<D, S> {
    data: D,
    splitter: S,
}

impl<D: Debug, S> Debug for Split<D, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Split")
            .field("data", &self.data)
            .finish()
    }
}

impl<D, S> ParallelIterator for Split<D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync + Send
{
    type Item = D;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer {
            data: self.data,
            splitter: &self.splitter,
        };
        bridge_unindexed(producer, consumer)
    }
}

struct SplitProducer<'a, D, S: 'a> {
    data: D,
    splitter: &'a S,
}

impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
    where D: Send,
          S: Fn(D) -> (D, Option<D>) + Sync
{
    type Item = D;

    fn split(mut self) -> (Self, Option<Self>) {
        let splitter = self.splitter;
        let (left, right) = splitter(self.data);
        self.data = left;
        (self,
         right.map(|data| {
                       SplitProducer {
                           data: data,
                           splitter: splitter,
                       }
                   }))
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume(self.data)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::cast;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args>:'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        #[cfg(not(target_word_size = "32"))]
        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            ::std::local_data::set(CALLBACK_KEY, box f as Box<Object<Args>:'static>);
            ($ext_set)(Some(callback));
        }
        // FIXME: workaround for mozilla/rust#11040
        #[cfg(target_word_size = "32")]
        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            ::std::local_data::set(CALLBACK_KEY, box f as Box<Object<Args>:'static>);
            ($ext_set)(callback);
        }

        #[cfg(not(target_word_size = "32"))]
        pub fn unset() {
            ::std::local_data::pop(CALLBACK_KEY);
            ($ext_set)(None);
        }
        // FIXME: workaround for mozilla/rust#11040
        #[cfg(target_word_size = "32")]
        pub fn unset() {
            ::std::local_data::pop(CALLBACK_KEY);
            ($ext_set)(unsafe { cast::transmute(::std::ptr::null::<::libc::c_void>()) });
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            ::std::local_data::get(CALLBACK_KEY, |data| {
                match data {
                    Some(cb) => unsafe { cb.call($call) },
                    _ => {}
                }
            });
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::cast;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: ~str);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *c_char) {
            (cast::transmute(error), str::raw::from_c_str(description))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::cast;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoShare,
            };
            (monitor, cast::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    cast::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(cast::transmute(button), cast::transmute(action), Modifiers::from_bits(mods)))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(cast::transmute(key), scancode, cast::transmute(action), Modifiers::from_bits(mods)))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<commit_msg>Bring code up to date with local_data API changes<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::cast;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args>:'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        #[cfg(not(target_word_size = "32"))]
        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args>:'static>));
            ($ext_set)(Some(callback));
        }
        // FIXME: workaround for mozilla/rust#11040
        #[cfg(target_word_size = "32")]
        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args>:'static>));
            ($ext_set)(callback);
        }

        #[cfg(not(target_word_size = "32"))]
        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(None);
        }
        // FIXME: workaround for mozilla/rust#11040
        #[cfg(target_word_size = "32")]
        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(unsafe { cast::transmute(::std::ptr::null::<::libc::c_void>()) });
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            match CALLBACK_KEY.get() {
                Some(cb) => unsafe { cb.call($call) },
                _ => {}
            }
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::cast;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: ~str);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *c_char) {
            (cast::transmute(error), str::raw::from_c_str(description))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::cast;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoShare,
            };
            (monitor, cast::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    cast::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(cast::transmute(button), cast::transmute(action), Modifiers::from_bits(mods)))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(cast::transmute(key), scancode, cast::transmute(action), Modifiers::from_bits(mods)))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<|endoftext|>


<commit_before>use core::ops::Range;

use mem::{Frame, FrameAllocator};
use multiboot2::{MemoryArea, MemoryAreaIter};

pub struct AreaFrameAllocator {
    area: Option<&'static MemoryArea>,
    areas: MemoryAreaIter,
    next_frame: Frame,
    kernel: Range<Frame>,
    multiboot: Range<Frame>,
}

impl AreaFrameAllocator {
    pub fn new(kernel_start: usize, kernel_end: usize,
               multiboot_start: usize, multiboot_end: usize,
               memory_areas: MemoryAreaIter) -> AreaFrameAllocator
    {
        let mut allocator = AreaFrameAllocator {
            area: None,
            areas: memory_areas,
            next_frame: Frame::containing(0),
            kernel: Range {
                start: Frame::containing(kernel_start),
                end: Frame::containing(kernel_end)
            },
            multiboot: Range {
                start: Frame::containing(multiboot_start),
                end: Frame::containing(multiboot_end)
            },
        };
        allocator.select_next_area();
        allocator
    }

    fn select_next_area(&mut self) {
        self.area =
            self.areas.clone()
                .filter(|area| {
                    let last_address = area.base_addr + area.length - 1;
                    let frame = Frame::containing(last_address as usize);

                    frame >= self.next_frame
                    && !(self.kernel.start.number..(self.kernel.end.number)).contains(frame.number)
                    && !(self.multiboot.start.number..(self.multiboot.end.number)).contains(frame.number)
                })
                .min_by_key(|area| area.base_addr);

        if let Some(area) = self.area {
            let first_frame = Frame::containing(area.base_addr as usize);
            if self.next_frame < first_frame {
                self.next_frame = first_frame;
            }
        }
    }
}

impl FrameAllocator for AreaFrameAllocator {
    fn alloc(&mut self) -> Option<Frame> {
        if let Some(area) = self.area {
            let frame = Frame { number: self.next_frame.number };

            let last_frame = {
                let last_address = area.base_addr + area.length - 1;
                Frame::containing(last_address as usize)
            };

            if frame > last_frame {
                self.select_next_area();
                return self.alloc();
            } else {
                self.next_frame.number += 1;
                return Some(frame);
            }
        }
        None
    }

    fn free(&mut self, _frame: Frame) {
        unimplemented!()
    }
}
<commit_msg>minor rename and code shuffle<commit_after>use core::ops::Range;

use mem::{Frame, FrameAllocator};
use multiboot2::{MemoryArea, MemoryAreaIter};

pub struct AreaFrameAllocator {
    area: Option<&'static MemoryArea>,
    areas: MemoryAreaIter,
    next: Frame,
    kernel: Range<Frame>,
    multiboot: Range<Frame>,
}

impl FrameAllocator for AreaFrameAllocator {
    fn alloc(&mut self) -> Option<Frame> {
        if let Some(area) = self.area {
            let frame = Frame { number: self.next.number };

            let last_frame = {
                let last_address = area.base_addr + area.length - 1;
                Frame::containing(last_address as usize)
            };

            if frame > last_frame {
                self.select_next_area();
                return self.alloc();
            } else {
                self.next.number += 1;
                return Some(frame);
            }
        }
        None
    }

    fn free(&mut self, _frame: Frame) {
        unimplemented!()
    }
}

impl AreaFrameAllocator {
    pub fn new(kernel_start: usize, kernel_end: usize,
               multiboot_start: usize, multiboot_end: usize,
               memory_areas: MemoryAreaIter) -> AreaFrameAllocator
    {
        let mut allocator = AreaFrameAllocator {
            area: None,
            areas: memory_areas,
            next: Frame::containing(0),
            kernel: Range {
                start: Frame::containing(kernel_start),
                end: Frame::containing(kernel_end)
            },
            multiboot: Range {
                start: Frame::containing(multiboot_start),
                end: Frame::containing(multiboot_end)
            },
        };
        allocator.select_next_area();
        allocator
    }

    fn select_next_area(&mut self) {
        self.area =
            self.areas.clone()
                .filter(|area| {
                    let last_address = area.base_addr + area.length - 1;
                    let frame = Frame::containing(last_address as usize);

                    frame >= self.next
                    && !(self.kernel.start.number..(self.kernel.end.number)).contains(frame.number)
                    && !(self.multiboot.start.number..(self.multiboot.end.number)).contains(frame.number)
                })
                .min_by_key(|area| area.base_addr);

        if let Some(area) = self.area {
            let first_frame = Frame::containing(area.base_addr as usize);
            if self.next < first_frame {
                self.next = first_frame;
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::schemas;
use derivative::Derivative;
use eyre::Result;
use petgraph::{graph::NodeIndex, stable_graph::StableGraph};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use strum::{Display, EnumString};

/// A resource in a dependency graph (the nodes of the graph)
#[derive(Debug, Clone, PartialEq, Eq, Hash, EnumString, JsonSchema, Serialize)]
#[serde(tag = "type")]
pub enum Resource {
    /// A symbol within code, within a project file
    Symbol(resources::Symbol),

    /// A node within a project file
    Node(resources::Node),

    /// A file within the project
    File(resources::File),

    /// A declared project `Source`
    Source(resources::Source),

    /// A programming language module, usually part of an external package
    Module(resources::Module),

    /// A URL to a remote resource
    Url(resources::Url),
}

pub mod resources {
    use super::*;
    #[derive(Debug, Clone, Default, Derivative, JsonSchema, Serialize)]
    #[derivative(PartialEq, Eq, Hash)]
    #[schemars(deny_unknown_fields)]
    pub struct Symbol {
        /// The path of the file that the symbol is defined in
        pub path: String,

        /// The name/identifier of the symbol
        pub name: String,

        /// The kind of the object that the symbol refers to
        ///
        /// Should be used as a hint only, and as such is excluded from
        /// equality and hash functions.
        #[derivative(PartialEq = "ignore")]
        #[derivative(Hash = "ignore")]
        pub kind: String,
    }

    impl Symbol {
        pub fn label(&self) -> String {
            [&self.path, "@", &self.name].concat()
        }
    }

    /// Create a new `Symbol` resource
    pub fn symbol(path: &str, name: &str, kind: &str) -> Resource {
        Resource::Symbol(Symbol {
            path: path.into(),
            name: name.into(),
            kind: kind.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Node {
        /// The path of the file that the node is defined in
        pub path: String,

        /// The address of the node
        pub address: String,

        /// The type of node e.g. "CodeChunk"
        pub kind: String,
    }

    impl Node {
        pub fn label(&self) -> String {
            [&self.path, "&", &self.address].concat()
        }
    }

    /// Create a new `Symbol` resource
    pub fn node(path: &str, address: &str, kind: &str) -> Resource {
        Resource::Node(Node {
            path: path.into(),
            address: address.into(),
            kind: kind.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct File {
        /// The path of the file
        pub path: String,
    }

    impl File {
        pub fn label(&self) -> String {
            self.path.clone()
        }
    }

    /// Create a new `File` resource
    pub fn file(path: &str) -> Resource {
        Resource::File(File { path: path.into() })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Source {
        /// The name of the project source
        pub name: String,
    }

    impl Source {
        pub fn label(&self) -> String {
            self.name.clone()
        }
    }

    /// Create a new `Source` resource
    pub fn source(name: &str) -> Resource {
        Resource::Source(Source { name: name.into() })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Module {
        /// The programming language of the module
        pub language: String,

        /// The name of the module
        pub name: String,
    }

    impl Module {
        pub fn label(&self) -> String {
            [&self.language, ":", &self.name].concat()
        }
    }

    /// Create a new `Module` resource
    pub fn module(language: &str, name: &str) -> Resource {
        Resource::Module(Module {
            language: language.into(),
            name: name.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Url {
        /// The URL of the external resource
        pub url: String,
    }

    impl Url {
        pub fn label(&self) -> String {
            self.url.clone()
        }
    }

    /// Create a new `Url` resource
    pub fn url(url: &str) -> Resource {
        Resource::Url(Url { url: url.into() })
    }
}

/// The relation between two resources in a dependency graph (the edges of the graph)
#[derive(
    Debug, Display, Clone, PartialEq, Eq, Hash, EnumString, JsonSchema, Serialize, Deserialize,
)]
#[serde(rename_all = "camelCase")]
pub enum Relation {
    Assigns,
    Embeds,
    Imports,
    Includes,
    Links,
    Reads,
    Uses,
    Writes,
}

/// The direction to represent the flow of information from subject to object.
pub enum Direction {
    From,
    To,
}

/// Get the the `Direction` for a `Relation`
pub fn direction(relation: &Relation) -> Direction {
    match relation {
        Relation::Assigns => Direction::To,
        Relation::Embeds => Direction::From,
        Relation::Imports => Direction::From,
        Relation::Includes => Direction::From,
        Relation::Links => Direction::To,
        Relation::Reads => Direction::From,
        Relation::Uses => Direction::From,
        Relation::Writes => Direction::To,
    }
}

/// A subject-relation-object triple
pub type Triple = (Resource, Relation, Resource);

/// A project dependency graph
#[derive(Debug, Default, Clone, Serialize)]
pub struct Graph {
    /// The graph itself
    ///
    /// Use a `petgraph::StableGraph` so that nodes can be added and removed
    /// without changing node indices.
    #[serde(flatten)]
    graph: StableGraph<Resource, Relation>,

    /// Indices of the nodes in the tree
    ///
    /// This is necessary to keep track of which resources
    /// are already in the graph and re-use their index if they are.
    #[serde(skip)]
    indices: HashMap<Resource, NodeIndex>,
}

impl Graph {
    /// Create a new graph
    pub fn new() -> Graph {
        Graph {
            indices: HashMap::new(),
            graph: StableGraph::new(),
        }
    }

    /// Add a triple to the graph
    pub fn add_triple(&mut self, (subject, relation, object): Triple) {
        let subject = if let Some(index) = self.indices.get(&subject) {
            *index
        } else {
            let index = self.graph.add_node(subject.clone());
            self.indices.insert(subject, index);
            index
        };

        let object = if let Some(index) = self.indices.get(&object) {
            *index
        } else {
            let index = self.graph.add_node(object.clone());
            self.indices.insert(object, index);
            index
        };

        let (from, to) = match direction(&relation) {
            Direction::From => (object, subject),
            Direction::To => (subject, object),
        };

        self.graph.add_edge(from, to, relation);
    }

    /// Convert the graph to a visualization nodes and edges
    pub fn to_dot(&self) -> String {
        let nodes = self
            .indices
            .iter()
            .map(|(resource, node)| {
                let (shape, fill_color, label) = match resource {
                    Resource::Symbol(resource) => ("diamond", "#efb8b8", resource.label()),
                    Resource::Node(resource) => ("house", "#efe0b8", resource.label()),
                    Resource::File(resource) => ("note", "#d1efb8", resource.label()),
                    Resource::Source(resource) => ("ellipse", "#efb8d4", resource.label()),
                    Resource::Module(resource) => ("invhouse", "#b8efed", resource.label()),
                    Resource::Url(resource) => ("box", "#cab8ef", resource.label()),
                };

                format!(
                    r#"  n{id} [shape="{shape}" fillcolor="{fill_color}" label="{label}"]"#,
                    id = node.index(),
                    shape = shape,
                    fill_color = fill_color,
                    label = label.replace('\"', "\\\"")
                )
            })
            .collect::<Vec<String>>()
            .join("\n");

        let edges = self
            .graph
            .edge_indices()
            .filter_map(|edge| {
                if let (Some((from, to)), Some(relation)) = (
                    self.graph.edge_endpoints(edge),
                    self.graph.edge_weight(edge),
                ) {
                    Some(format!(
                        r#"  n{from} -> n{to} [label="{label}"]"#,
                        from = from.index(),
                        to = to.index(),
                        label = relation.to_string().replace('\"', "\\\"")
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        format!(
            r#"digraph {{
  node [style="filled" fontname=Helvetica fontsize=11]
  edge [fontname=Helvetica fontsize=10]

{nodes}

{edges}
}}
"#,
            nodes = nodes,
            edges = edges
        )
    }
}

/// Get JSON Schemas for this modules
pub fn schemas() -> Result<serde_json::Value> {
    let schemas = serde_json::Value::Array(vec![
        schemas::generate::<Resource>()?,
        schemas::generate::<Relation>()?,
        serde_json::json!({
            "$id": "Triple",
            "title": "Triple",
            "description": "A subject-relation-object triple",
            "type" : "array",
            "items": [
                {
                    "tsType": "Resource"
                },
                {
                    "tsType": "Relation"
                },
                {
                    "tsType": "Resource"
                }
            ],
            "minItems": 3,
            "maxItems": 3
        }),
        serde_json::json!({
            "$id": "Graph",
            "title": "Graph",
            "description": "A project dependency graph",
            "type" : "object",
            "required": ["nodes", "edges"],
            "properties": {
                "nodes": {
                    "description": "The resources in the graph",
                    "type": "array",
                    "items": {
                        "tsType": "Resource",
                        "isRequired": true
                    }
                },
                "edges": {
                    "description": "The relations between resources in the graph",
                    "type": "array",
                    "items": {
                        "type": "array",
                        "items": [
                            {
                                "type": "integer"
                            },
                            {
                                "type": "integer"
                            },
                            {
                                "tsType": "Relation"
                            }
                        ],
                        "minItems": 3,
                        "maxItems": 3
                    }
                }
            },
            "additionalProperties": false
        }),
    ]);
    Ok(schemas)
}
<commit_msg>fix(Project graphs): Improve DOT visualizations<commit_after>use crate::utils::schemas;
use derivative::Derivative;
use eyre::Result;
use petgraph::{graph::NodeIndex, stable_graph::StableGraph};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use strum::{Display, EnumString};

/// A resource in a dependency graph (the nodes of the graph)
#[derive(Debug, Clone, PartialEq, Eq, Hash, EnumString, JsonSchema, Serialize)]
#[serde(tag = "type")]
pub enum Resource {
    /// A symbol within code, within a project file
    Symbol(resources::Symbol),

    /// A node within a project file
    Node(resources::Node),

    /// A file within the project
    File(resources::File),

    /// A declared project `Source`
    Source(resources::Source),

    /// A programming language module, usually part of an external package
    Module(resources::Module),

    /// A URL to a remote resource
    Url(resources::Url),
}

pub mod resources {
    use super::*;
    #[derive(Debug, Clone, Default, Derivative, JsonSchema, Serialize)]
    #[derivative(PartialEq, Eq, Hash)]
    #[schemars(deny_unknown_fields)]
    pub struct Symbol {
        /// The path of the file that the symbol is defined in
        pub path: String,

        /// The name/identifier of the symbol
        pub name: String,

        /// The kind of the object that the symbol refers to
        ///
        /// Should be used as a hint only, and as such is excluded from
        /// equality and hash functions.
        #[derivative(PartialEq = "ignore")]
        #[derivative(Hash = "ignore")]
        pub kind: String,
    }

    /// Create a new `Symbol` resource
    pub fn symbol(path: &str, name: &str, kind: &str) -> Resource {
        Resource::Symbol(Symbol {
            path: path.into(),
            name: name.into(),
            kind: kind.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Node {
        /// The path of the file that the node is defined in
        pub path: String,

        /// The address of the node
        pub address: String,

        /// The type of node e.g. "CodeChunk"
        pub kind: String,
    }

    /// Create a new `Symbol` resource
    pub fn node(path: &str, address: &str, kind: &str) -> Resource {
        Resource::Node(Node {
            path: path.into(),
            address: address.into(),
            kind: kind.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct File {
        /// The path of the file
        pub path: String,
    }

    /// Create a new `File` resource
    pub fn file(path: &str) -> Resource {
        Resource::File(File { path: path.into() })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Source {
        /// The name of the project source
        pub name: String,
    }

    /// Create a new `Source` resource
    pub fn source(name: &str) -> Resource {
        Resource::Source(Source { name: name.into() })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Module {
        /// The programming language of the module
        pub language: String,

        /// The name of the module
        pub name: String,
    }

    /// Create a new `Module` resource
    pub fn module(language: &str, name: &str) -> Resource {
        Resource::Module(Module {
            language: language.into(),
            name: name.into(),
        })
    }

    #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, JsonSchema, Serialize)]
    #[schemars(deny_unknown_fields)]
    pub struct Url {
        /// The URL of the external resource
        pub url: String,
    }

    /// Create a new `Url` resource
    pub fn url(url: &str) -> Resource {
        Resource::Url(Url { url: url.into() })
    }
}

/// The relation between two resources in a dependency graph (the edges of the graph)
#[derive(
    Debug, Display, Clone, PartialEq, Eq, Hash, EnumString, JsonSchema, Serialize, Deserialize,
)]
#[serde(rename_all = "camelCase")]
pub enum Relation {
    Assigns,
    Embeds,
    Imports,
    Includes,
    Links,
    Reads,
    Uses,
    Writes,
}

/// The direction to represent the flow of information from subject to object.
pub enum Direction {
    From,
    To,
}

/// Get the the `Direction` for a `Relation`
pub fn direction(relation: &Relation) -> Direction {
    match relation {
        Relation::Assigns => Direction::To,
        Relation::Embeds => Direction::From,
        Relation::Imports => Direction::From,
        Relation::Includes => Direction::From,
        Relation::Links => Direction::To,
        Relation::Reads => Direction::From,
        Relation::Uses => Direction::From,
        Relation::Writes => Direction::To,
    }
}

/// A subject-relation-object triple
pub type Triple = (Resource, Relation, Resource);

/// A project dependency graph
#[derive(Debug, Default, Clone, Serialize)]
pub struct Graph {
    /// The graph itself
    ///
    /// Use a `petgraph::StableGraph` so that nodes can be added and removed
    /// without changing node indices.
    #[serde(flatten)]
    graph: StableGraph<Resource, Relation>,

    /// Indices of the nodes in the tree
    ///
    /// This is necessary to keep track of which resources
    /// are already in the graph and re-use their index if they are.
    #[serde(skip)]
    indices: HashMap<Resource, NodeIndex>,
}

impl Graph {
    /// Create a new graph
    pub fn new() -> Graph {
        Graph {
            indices: HashMap::new(),
            graph: StableGraph::new(),
        }
    }

    /// Add a triple to the graph
    pub fn add_triple(&mut self, (subject, relation, object): Triple) {
        let subject = if let Some(index) = self.indices.get(&subject) {
            *index
        } else {
            let index = self.graph.add_node(subject.clone());
            self.indices.insert(subject, index);
            index
        };

        let object = if let Some(index) = self.indices.get(&object) {
            *index
        } else {
            let index = self.graph.add_node(object.clone());
            self.indices.insert(object, index);
            index
        };

        let (from, to) = match direction(&relation) {
            Direction::From => (object, subject),
            Direction::To => (subject, object),
        };

        self.graph.add_edge(from, to, relation);
    }

    /// Convert the graph to a visualization nodes and edges
    pub fn to_dot(&self) -> String {
        let nodes = self
            .indices
            .iter()
            .map(|(resource, node)| {
                let index = node.index();

                let (shape, fill_color, label) = match resource {
                    Resource::Symbol(symbol) => ("diamond", "#efb8b8", symbol.name.clone()),
                    Resource::Node(node) => (
                        "box",
                        "#efe0b8",
                        format!("{}\\n{}", node.kind, node.address),
                    ),
                    Resource::File(file) => ("note", "#d1efb8", file.path.clone()),
                    Resource::Source(source) => ("house", "#efb8d4", source.name.clone()),
                    Resource::Module(module) => ("invhouse", "#b8efed", module.name.clone()),
                    Resource::Url(url) => ("box", "#cab8ef", url.url.clone()),
                };

                let node = match resource {
                    Resource::File(..) => {
                        format!(r#"  n{index} [style=invis]"#, index = index,)
                    }
                    _ => format!(
                        r#"  n{index} [shape="{shape}" fillcolor="{fill_color}" label="{label}"]"#,
                        index = index,
                        shape = shape,
                        fill_color = fill_color,
                        label = label.replace('\"', "\\\"")
                    ),
                };

                let path = match resource {
                    Resource::Symbol(symbol) => symbol.path.clone(),
                    Resource::Node(node) => node.path.clone(),
                    Resource::File(file) => file.path.clone(),
                    _ => "".to_string(),
                };

                (path, node)
            })
            .collect::<Vec<(String, String)>>();

        let mut clusters: HashMap<String, Vec<String>> = HashMap::new();
        for (path, node) in nodes {
            clusters.entry(path).or_default().push(node)
        }

        let path_to_cluster = |path: &str| clusters.keys().position(|key| key == path).unwrap_or(0);

        let subgraphs = clusters
            .iter()
            .enumerate()
            .map(|(index, (label, nodes))| {
                if label.is_empty() {
                    nodes.join("\n")
                } else {
                    [
                        &format!("  subgraph cluster{} {{\n", index),
                        &format!("    label=\"{}\" fillcolor=\"#d1efb8\"\n  ", label),
                        &nodes.join("\n  "),
                        "\n  }",
                    ]
                    .concat()
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        let edges = self
            .graph
            .edge_indices()
            .filter_map(|edge| {
                if let (Some((from, to)), Some(relation)) = (
                    self.graph.edge_endpoints(edge),
                    self.graph.edge_weight(edge),
                ) {
                    let ltail = if let Some(Resource::File(file)) = self.graph.node_weight(from) {
                        format!(" ltail=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    let lhead = if let Some(Resource::File(file)) = self.graph.node_weight(to) {
                        format!(" lhead=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    Some(format!(
                        r#"  n{from} -> n{to} [label="{label}"{ltail}{lhead}]"#,
                        from = from.index(),
                        to = to.index(),
                        ltail = ltail,
                        lhead = lhead,
                        label = relation.to_string(),
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        format!(
            r#"digraph {{
  graph [rankdir=LR compound=true fontname=Helvetica fontsize=12 labeljust=l color=gray]
  node [style=filled fontname=Helvetica fontsize=11]
  edge [fontname=Helvetica fontsize=10]

{subgraphs}

{edges}
}}
"#,
            subgraphs = subgraphs,
            edges = edges
        )
    }
}

/// Get JSON Schemas for this modules
pub fn schemas() -> Result<serde_json::Value> {
    let schemas = serde_json::Value::Array(vec![
        schemas::generate::<Resource>()?,
        schemas::generate::<Relation>()?,
        serde_json::json!({
            "$id": "Triple",
            "title": "Triple",
            "description": "A subject-relation-object triple",
            "type" : "array",
            "items": [
                {
                    "tsType": "Resource"
                },
                {
                    "tsType": "Relation"
                },
                {
                    "tsType": "Resource"
                }
            ],
            "minItems": 3,
            "maxItems": 3
        }),
        serde_json::json!({
            "$id": "Graph",
            "title": "Graph",
            "description": "A project dependency graph",
            "type" : "object",
            "required": ["nodes", "edges"],
            "properties": {
                "nodes": {
                    "description": "The resources in the graph",
                    "type": "array",
                    "items": {
                        "tsType": "Resource",
                        "isRequired": true
                    }
                },
                "edges": {
                    "description": "The relations between resources in the graph",
                    "type": "array",
                    "items": {
                        "type": "array",
                        "items": [
                            {
                                "type": "integer"
                            },
                            {
                                "type": "integer"
                            },
                            {
                                "tsType": "Relation"
                            }
                        ],
                        "minItems": 3,
                        "maxItems": 3
                    }
                }
            },
            "additionalProperties": false
        }),
    ]);
    Ok(schemas)
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use std::process;
use std::cmp::Ordering;
use rand::Rng;

#[derive(Debug)]
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value }
    }

    // Getter
    pub fn value(&self) -> i32 {
        self.value
    }

    pub fn comparison(&self, secret_number: &i32) -> i32 {
        match self.value.cmp(secret_number) {
            Ordering::Less => {
                println!("Too small!");
                return -1;
            },
            Ordering::Greater => {
                println!("Too big!");
                return 1;
            },
            Ordering::Equal => {
                println!("You win!");
                return 0;
            }
        }
    }
}

fn sample(guess: &str) -> String {
    return guess.to_string();
}

fn main() {
    let secret_number = rand::thread_rng().gen_range(1, 101);

    println!("The secret number is: {}", secret_number);

    loop {
        println!("Input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        guess = sample(&guess);

        // Allow potentially negative numbers
        let guess: Guess = match guess.trim().parse() {
            Ok(num) => Guess::new(num),
            Err(_) => continue,
        };

        println!("You guessed: {:?}", guess);

        let result = guess.comparison(&secret_number);
        if result == 0 { process::exit(1); }
    }
}

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

    #[test]
    fn test_sample() {
        let actual_guess: &str = "1";
        let expected_response: String = "1".to_string();
        assert_eq!(sample(&actual_guess), expected_response);
    }

    #[test]
    fn test_guess() {
        let actual_guess_number: i32 = 99;
        let actual_guess_instance: Guess = Guess::new(actual_guess_number);
        let expected_guess_instance_value: i32 = actual_guess_instance.value();
        assert_eq!(99, expected_guess_instance_value);
    }

    #[test]
    fn test_comparison() {
        let actual_guess_number: i32 = 50;
        let actual_guess_instance: Guess = Guess::new(actual_guess_number);
        let actual_secret_number: i32 = 50;
        let actual_comparison_result: i32 = actual_guess_instance.comparison(&actual_secret_number);
        let expected_comparison_result: i32 = 0;
        assert_eq!(actual_comparison_result, expected_comparison_result);
    }
}<commit_msg>attempt to use unsigned secret number in tests<commit_after>extern crate rand;

use std::io;
use std::process;
use std::cmp::Ordering;
use rand::Rng;

#[derive(Debug)]
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value }
    }

    // Getter
    pub fn value(&self) -> i32 {
        self.value
    }

    pub fn comparison(&self, secret_number: &u32) -> i32 {
        match self.value.cmp(&(*secret_number as &i32)) {
            Ordering::Less => {
                println!("Too small!");
                return -1;
            },
            Ordering::Greater => {
                println!("Too big!");
                return 1;
            },
            Ordering::Equal => {
                println!("You win!");
                return 0;
            }
        }
    }
}

fn sample(guess: &str) -> String {
    return guess.to_string();
}

fn main() {
    let secret_number: u32 = rand::thread_rng().gen_range(1, 101);

    println!("The secret number is: {}", secret_number);

    loop {
        println!("Input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        guess = sample(&guess);

        // Allow potentially negative numbers
        let guess: Guess = match guess.trim().parse::<i32>() {
            Ok(num) => Guess::new(num),
            Err(_) => continue,
        };

        println!("You guessed: {:?}", guess);

        let result = guess.comparison(&secret_number);
        if result == 0 { process::exit(1); }
    }
}

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

    #[test]
    fn test_sample() {
        let actual_guess: &str = "1";
        let expected_response: String = "1".to_string();
        assert_eq!(sample(&actual_guess), expected_response);
    }

    #[test]
    fn test_guess() {
        let actual_guess_number: i32 = 99;
        let actual_guess_instance: Guess = Guess::new(actual_guess_number);
        let expected_guess_instance_value: i32 = actual_guess_instance.value();
        assert_eq!(99, expected_guess_instance_value);
    }

    #[test]
    fn test_comparison() {
        let actual_guess_number: i32 = 50;
        let actual_guess_instance: Guess = Guess::new(actual_guess_number);
        let actual_secret_number: u32 = 50;
        let actual_comparison_result: i32 = actual_guess_instance.comparison(&actual_secret_number);
        let expected_comparison_result: i32 = 0;
        assert_eq!(actual_comparison_result, expected_comparison_result);
    }
}<|endoftext|>


<commit_before>/// Figure 2.14 Print all possible sysconf and pathconf values
///
/// How apue solves this is by writing a program in awk with 70+ printf commands
/// which generates a C program which itself has a #ifdef for every possible PC/SC constant.
/// First I found this very ugly and second #ifdef AFAIK doesn't work in Rust.
///
/// My approach: Parse the header files which contain the `PC` and `SC` definition
/// (binding to an int) and print those via sysconf or pathconf.
/// The header file differ for
/// OSX (/usr/include/sys/unistd.h for PC, /usr/include/unistd.h for SC) and
/// Linux (/usr/include/unistd.h only). The crux is that in Linux the constants are inside
/// an enum so this program tries to emulate that enum which of course is very error prone.
///
/// Current state: works for OSX, and Linux (PC_: seems 100% correct, SC_ seems correct until
/// there is a off by 1 error around _SC_THREAD_SAFE_FUNCTIONS)
///
/// to validate the results compare it against `getconf -a`
///
/// $ f14-limits | grep _PC_NAME_MAX
/// _PC_NAME_MAX =  255

extern crate libc;
#[macro_use(cstr)]
extern crate apue;
extern crate errno;
extern crate regex;

use libc::{EINVAL, puts, printf, pathconf, sysconf};
use apue::{LibcResult, uname};
use errno::errno;
use std::io::{BufReader, BufRead};
use regex::Regex;

fn pr_conf(key: &str, path: &str, name: i32) {
    unsafe {
        printf(cstr!("%s = "), cstr!(key));
        let res = match &key[0..4] {
            "_SC_" => sysconf(name),
            "_PC_" => pathconf(cstr!(path), name),
            _ => {
                panic!("key needs to start either with _PC_ or _SC_ but was {:?}",
                       key)
            }
        };
        if let Some(val) = res.to_option() {
            printf(cstr!(" %ld\n"), val);
        } else {
            let e = errno();
            let _ = match e.0 {
                EINVAL => {
                    puts(cstr!(" (not supported)"));
                }
                0 => {
                    puts(cstr!(" (no limit)"));
                }
                _ => panic!("pathconf error, path = {:?}", path),
            };
        }
    }
}

fn parse_header(hfile: &str) {
    let f = match std::fs::File::open(hfile) {
        Ok(file) => file,
        Err(_) => return,
    };
    let file = BufReader::new(&f);
    let re = Regex::new(r"^\s*#define\s+(_[PS]C_\w+)\s+(\w+).*").unwrap();
    let mut pc_counter = 0;
    let mut sc_counter = 0;
    let mut define_line = false;
    for line in file.lines() {
        if let Ok(line) = line {
            if let Some(groups) = re.captures(&line) {
                if groups.len() == 3 {
                    let key = &groups[1];
                    let val = &groups[2];
                    let val = match val.parse::<i32>() {
                        Ok(n) => n,
                        // assumption: if the definition is not a number, then
                        // we're inside an enum and just count up
                        // that's highly unstable of course..
                        Err(_) => {
                            if key.starts_with("_PC_") {
                                // if there are two #define after each other
                                // there's no increase in the enum value
                                // e.g. here:
                                // #define _SC_PAGESIZE                    _SC_PAGESIZE
                                // #define _SC_PAGE_SIZE                   _SC_PAGESIZE
                                if !define_line {
                                    pc_counter += 1;
                                }
                                pc_counter - 1 // enum starts with zero
                            } else {
                                if !define_line {
                                    sc_counter += 1;
                                }
                                sc_counter - 1
                            }
                        }
                    };
                    pr_conf(key, "/", val);
                    define_line = true;
                }
            } else {
                define_line = false;
            }
        }
    }
}

fn main() {
    match uname().unwrap().as_str() {
        "Linux" => {
            parse_header("/usr/include/bits/confname.h");
        }
        "Darwin" => {
            parse_header("/usr/include/sys/unistd.h"); // for _PC_*
            parse_header("/usr/include/unistd.h"); // for _SC_*
        }
        _ => panic!("{:?} is not supported", uname()),
    }
}
<commit_msg>fix f14 for linux<commit_after>/// Figure 2.14 Print all possible sysconf and pathconf values
///
/// How apue solves this is by writing a program in awk with 70+ printf commands
/// which generates a C program which itself has a #ifdef for every possible PC/SC constant.
/// First I found this very ugly and second #ifdef AFAIK doesn't work in Rust.
///
/// My approach: Parse the header files which contain the `PC` and `SC` definition
/// (binding to an int) and print those via sysconf or pathconf.
/// The header file differ for
/// OSX (/usr/include/sys/unistd.h for PC, /usr/include/unistd.h for SC) and
/// Linux (/usr/include/unistd.h only). The crux is that in Linux the constants are inside
/// an enum so this program tries to emulate that enum which of course is very error prone.
///
/// Current state: works for OSX, and Linux (PC_: seems 100% correct, SC_ seems correct until
/// there is a off by 1 error around _SC_THREAD_SAFE_FUNCTIONS)
///
/// to validate the results compare it against `getconf -a`
///
/// $ f14-limits | grep _PC_NAME_MAX
/// _PC_NAME_MAX =  255

extern crate libc;
#[macro_use(cstr)]
extern crate apue;
extern crate errno;
extern crate regex;

use libc::{EINVAL, puts, printf, pathconf, sysconf};
use apue::{LibcResult, uname};
use errno::errno;
use std::io::{BufReader, BufRead};
use regex::Regex;

fn pr_conf(key: &str, path: &str, name: i32) {
    unsafe {
        printf(cstr!("%s = "), cstr!(key));
        let res = match &key[0..4] {
            "_SC_" => sysconf(name),
            "_PC_" => pathconf(cstr!(path), name),
            _ => {
                panic!("key needs to start either with _PC_ or _SC_ but was {:?}",
                       key)
            }
        };
        if let Some(val) = res.to_option() {
            printf(cstr!(" %ld\n"), val);
        } else {
            let e = errno();
            let _ = match e.0 {
                EINVAL => {
                    puts(cstr!(" (not supported)"));
                }
                0 => {
                    puts(cstr!(" (no limit)"));
                }
                _ => panic!("pathconf error, path = {:?}", path),
            };
        }
    }
}

fn parse_header(hfile: &str) {
    let f = match std::fs::File::open(hfile) {
        Ok(file) => file,
        Err(_) => return,
    };
    let file = BufReader::new(&f);
    let re = Regex::new(r"^\s*#define\s+(_[PS]C_\w+)\s+(\w+).*").unwrap();
    let mut pc_counter = 0;
    let mut sc_counter = 0;
    let mut define_line = false;
    for line in file.lines() {
        if let Ok(line) = line {
            if let Some(groups) = re.captures(&line) {
                if groups.len() == 3 {
                    let key = &groups[1];
                    let val = &groups[2];
                    let val = match val.parse::<i32>() {
                        Ok(n) => n,
                        // assumption: if the definition is not a number, then
                        // we're inside an enum and just count up
                        // that's highly unstable of course..
                        Err(_) => {
                            if key.starts_with("_PC_") {
                                // if there are two #define after each other
                                // there's no increase in the enum value
                                // e.g. here:
                                // #define _SC_PAGESIZE                    _SC_PAGESIZE
                                // #define _SC_PAGE_SIZE                   _SC_PAGESIZE
                                if !define_line {
                                    pc_counter += 1;
                                }
                                pc_counter - 1 // enum starts with zero
                            } else {
                                if !define_line {
                                    sc_counter += 1;
                                }
                                sc_counter - 1
                            }
                        }
                    };
                    pr_conf(key, "/", val);
                    define_line = true;
                }
            } else {
                define_line = false;
            }
        }
    }
}

fn main() {
    match uname().unwrap().as_str() {
        "Linux" => {
            println!("linux!");
            parse_header("/usr/include/x86_64-linux-gnu/bits/confname.h");
        }
        "Darwin" => {
            parse_header("/usr/include/sys/unistd.h"); // for _PC_*
            parse_header("/usr/include/unistd.h"); // for _SC_*
        }
        _ => panic!("{:?} is not supported", uname()),
    }
}
<|endoftext|>