<commit_before>//! An asynchronous stub resolver.
//!
//! A resolver is the component in the DNS that answers queries. A stub
//! resolver does so by simply relaying queries to a different resolver
//! chosen from a predefined set. This is how pretty much all user
//! applications use DNS.
//!
//! This module implements a modern, asynchronous stub resolver built on
//! top of [tokio-core].
//!
//! The module provides ways to create a *resolver* that knows how to
//! process DNS *queries*. A query asks for all the resource records
//! associated with a given triple of a domain name, resource record type,
//! and class (known as a *question*). It is a future resolving to a DNS
//! message with the response or an error. Queries can be combined into
//! *lookups* that use the returned resource records to answer more
//! specific enquiries such as all the IP addresses associated with a given
//! host name. The module provides a rich set of common lookups in the
//! [lookup] sub-module.
//!
//! The following gives an introduction into using the resolver. For an
//! introduction into the internal design, please have a look at the [intro]
//! sub-module.
//!
//!
//! # Creating a Resolver
//!
//! The resolver is represented by the [`Resolver`] type. When creating a
//! value of this type, you create all the parts of an actual resolver
//! according to a resolver configuration. Since these parts are handling
//! actual network traffic, the resolver needs a handle to a Tokio reactor
//! into which these parts will be spawned as futures.
//!
//! For the resolver configuration, there’s [`ResolvConf`]. While you can
//! create a value of this type by hand, the more common way is to use your
//! system’s resolver configuration. [`ResolvConf`] implements the `Default`
//! trait doing exactly that by reading `/etc/resolv.conf`.
//!
//! > That probably won’t work on Windows, but, sadly, I have no idea how to
//! > retrieve the resolver configuration there. Some help here would be
//! > very much appreciated.
//!
//! Since using the system configuration is the most common case by far,
//! [`Resolver`]’s `new()` function does just that. So, the easiest way to
//! get a resolver is just this:
//!
//! ```norun
//! use domain::resolv::Resolver;
//! use tokio_core::reactor::Core;
//!
//! let core = Core::new().unwrap();
//! let resolv = Resolver::new(&core.handle()).unwrap();
//! ```
//!
//! If you do have a configuration, you can use the `from_conf()` function
//! instead.
//!
//!
//! # Using the Resolver: Queries
//!
//! As was mentioned above, the [`Resolver`] does’t actually contain the
//! networking parts necessary to answer queries. Instead, it only knows how
//! to contact those parts. Because of this, you can clone the resolver,
//! even pass it to other threads.
//!
//! Oddly, the one thing you can’t do with a resolver is start a query.
//! Instead, you need an intermediary type called [`ResolverTask`]. You’ll
//! get one through [`Resolver::start()`] or, more correctly, you get a future
//! to one through this method. You then chain on your actual query or
//! sequence of queries using combinators such as `Future::and_then()`.
//!
//! The actual query is started through [`ResolverTask::query()`]. It takes a
//! domain name, a resource record type, and a class and returns a future
//! that will resolve into either a [`MessageBuf`] with the response to the
//! query or an [`Error`].
//!
//! As an example, let’s find out the IPv6 addresses for `www.rust-lang.org`:
//!
//! ```ignore
//! extern crate domain;
//! extern crate futures;
//! extern crate tokio_core;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::iana::{Class, Rtype};
//! use domain::rdata::Aaaa;
//! use domain::resolv::Resolver;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!     let resolv = Resolver::new(&core.handle()).unwrap();
//!
//!     let addrs = resolv.start().and_then(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org.").unwrap();
//!         resolv.query(name, Rtype::Aaaa, Class::In)
//!     });
//!     let response = core.run(addrs).unwrap();
//!     for record in response.answer().unwrap().limit_to::<Aaaa>() {
//!         println!("{}", record.unwrap());
//!     }
//! }
//! ```
//!
//! Note the final dot at `"www.rust-lang.org."` making it an absolute domain
//! name. Queries don’t know how to deal with relative names and will error
//! out if given one.
//!
//!
//! # Complex Queries: Lookups
//!
//! Most times when you are using DNS you aren’t really interested in a
//! bunch of resource records, though, you want an answer to a more direct
//! question. For instance, if you want to know the IP addresses for a
//! host name, you don’t really care that you have to make a query for the
//! `A` records and one for `AAAA` records for that host name. You want the
//! addresses.
//!
//! This is what lookups do. They take a [`ResolverTask`] and some additional
//! information and turn that into a future of some specific result. So,
//! to do lookups you have to follow the procedure using `start()` as given
//! above but instead of calling `query()` inside the closure, you use one
//! of the lookup functions from the [lookup] sub-module.
//!
//! Using [`lookup_host()`], the process of looking up the IP addresses
//! becomes much easier. To update above’s example:
//!
//! ```ignore
//! extern crate domain;
//! extern crate futures;
//! extern crate tokio_core;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::resolv::Resolver;
//! use domain::resolv::lookup::lookup_host;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!     let resolv = Resolver::new(&core.handle()).unwrap();
//!
//!     let addrs = resolv.start().and_then(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org").unwrap();
//!         lookup_host(resolv, name)
//!     });
//!     let response = core.run(addrs).unwrap();
//!     for addr in response.iter() {
//!         println!("{}", addr);
//!     }
//! }
//! ```
//!
//! No more fiddeling with record types and classes and the result can now
//! iterate over IP addresses. And we get both IPv4 and IPv6 addresses to
//! boot.
//!
//! Furthermore, we now can use a relative host name. It will be turned into
//! an absolute name according to the rules set down by the configuration we
//! used when creating the resolver.
//!
//! As an aside, the lookup functions are named after the thing they look
//! up not their result following the example of the standard library. So,
//! when you look for the addresses for the host, you have to use
//! [`lookup_host()`], not [`lookup_addr()`].
//!
//! Have a look at the [lookup] module for all the lookup functions
//! currently available.
//!
//!
//! # The Run Shortcut
//!
//! If you only want to do a DNS lookup and don’t otherwise use tokio, there
//! is a shortcut through the [`Resolver::run()`] associated function. It
//! takes a closure from a [`ResolverTask`] to a future and waits while
//! driving the future to completing. In other words, it takes away all the
//! boiler plate from above:
//!
//! ```ignore
//! extern crate domain;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::resolv::Resolver;
//! use domain::resolv::lookup::lookup_host;
//!
//! fn main() {
//!     let response = Resolver::run(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org").unwrap();
//!         lookup_host(resolv, name)
//!     });
//!     for addr in response.unwrap().iter() {
//!         println!("{}", addr);
//!     }
//! }
//! ```
//!
//!
//! [intro]: intro/index.html
//! [lookup]: lookup/index.html
//! [tokio-core]: https://github.com/tokio-rs/tokio-core
//! [`Error`]: error/enum.Error.html
//! [`MessageBuf`]: ../bits/message/struct.MessageBuf.html
//! [`ResolvConf`]: conf/struct.ResolvConf.html
//! [`Resolver`]: struct.Resolver.html
//! [`Resolver::start()`]: struct.Resolver.html#method.start
//! [`Resolver::run()`]: struct.Resolver.html#method.run
//! [`ResolverTask`]: struct.ResolverTask.html
//! [`ResolverTask::query()`]: struct.ResolverTask.html#method.query
//! [`lookup_addr()`]: lookup/fn.lookup_addr.html
//! [`lookup_host()`]: lookup/fn.lookup_host.html

//============ Sub-modules ===================================================

//--- Re-exports

pub use self::conf::ResolvConf;
pub use self::error::{Error, Result};
pub use self::query::Query;

//--- Public modules

pub mod conf;
pub mod error;
pub mod hosts;
pub mod lookup;

//--- Private modules

mod core;
mod query;
mod request;
mod service;
mod tcp;
mod transport;
mod udp;
mod utils;

//--- Meta-modules for documentation

pub mod intro;

//============ Actual Content ================================================

use std::io;
use std::ops::Deref;
use std::result;
use std::sync::Arc;
use futures::{BoxFuture, Future, lazy};
use futures::task::TaskRc;
use tokio_core::reactor;
use ::bits::DName;
use ::iana::{Class, Rtype};
use self::conf::ResolvOptions;
use self::core::Core;

//------------ Resolver -----------------------------------------------------

/// Access to a resolver.
///
/// This types collects all information in order to be able to start a DNS
/// query on a resolver. You can create a new resolver by calling either
/// the `new()` or `from_conf()` functions passing in a handle to a Tokio
/// reactor core. Either function will spawn everything necessary for a
/// resolver into that core. Existing resolver values can be cloned. Clones
/// will refer to the same resolver.
///
/// In order to perform a query, you will have to call the `start()` method
/// to create a future that will resolve into an intermediary value that
/// will than allow calling a `query()` method on it and will also allow
/// more complex operations as a complex future.
///
/// Alternatively, you can use the `run()` associated function to
/// synchronously perfrom a series of queries.
#[derive(Clone, Debug)]
pub struct Resolver {
    core: Arc<Core>
}

impl Resolver {
    /// Creates a new resolver using the system’s default configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn new(reactor: &reactor::Handle) -> io::Result<Self> {
        Self::from_conf(reactor, ResolvConf::default())
    }

    /// Creates a new resolver using the given configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn from_conf(reactor: &reactor::Handle, conf: ResolvConf)
                     -> io::Result<Self> {
        Core::new(reactor, conf)
             .map(|core| Resolver{core: Arc::new(core)})
    }

    /// Returns a reference to the configuration of this resolver.
    pub fn conf(&self) -> &ResolvConf {
        &self.core.conf()
    }

    /// Returns a reference to the configuration options of this resolver.
    pub fn options(&self) -> &ResolvOptions {
        &self.core.conf().options
    }

    /// Starts a resolver future atop this resolver.
    ///
    /// The method returns a future that will resolve into a [ResolverTask]
    /// value that can be used to start queries atop this resolver.
    ///
    /// Since the future will never error, it is generic over the error type.
    ///
    /// [ResolverTask]: struct.ResolverTask.html
    pub fn start<E>(&self) -> BoxFuture<ResolverTask, E>
                 where E: Send + 'static {
        let core = self.core.deref().clone();
        lazy(move || Ok(ResolverTask{core: TaskRc::new(core)})).boxed()
    }
}

/// # Shortcuts
///
impl Resolver {
    /// Synchronously perform a DNS operation atop a standard resolver.
    ///
    /// This associated functions removes almost all boiler plate for the
    /// case that you want to perform some DNS operation on a resolver using
    /// the system’s configuration and wait for the result.
    ///
    /// The only argument is a closure taking a [ResolverTask] for creating
    /// queries and returning a future. Whatever that future resolves to will
    /// be returned.
    pub fn run<R, F>(f: F) -> result::Result<R::Item, R::Error>
               where R: Future, R::Error: From<io::Error> + Send + 'static,
                     F: FnOnce(ResolverTask) -> R {
        let mut reactor = try!(reactor::Core::new());
        let resolver = try!(Resolver::new(&reactor.handle()));
        let fut = resolver.start().and_then(f);
        reactor.run(fut)
    }

    /// Spawn a query.
    ///
    /// This method is a shortcut for `self.start().and_then(f).boxed()`.
    /// Because of the `boxed()` bit, it requires lots of things to be
    /// `Send + 'static` and because of that isn’t necessarily better than
    /// the longer way.
    ///
    /// I am also not sure if *spawn* is the right name. Probably not since
    /// it actually returns the future.
    pub fn spawn<R, F>(&self, f: F) -> BoxFuture<R::Item, R::Error>
                 where R: Future + Send + 'static,
                       R::Error: From<io::Error> + Send + 'static,
                       F: FnOnce(ResolverTask) -> R + Send + 'static {
        self.start().and_then(f).boxed()
    }
}

//------------ ResolverTask --------------------------------------------------

/// A resolver bound to a futures task.
///
/// You can use this type within a running future to start a query on top
/// of the resolver using the `query()` method.
#[derive(Clone)]
pub struct ResolverTask {
    core: TaskRc<Core>
}

impl ResolverTask {
    /// Start a DNS query on this resolver.
    ///
    /// Returns a future that, if successful, will resolve into a DNS
    /// message containing a response to a query for resource records of type
    /// `rtype` associated with the domain name `name` and class `class`. The
    /// name must be an absolute name or else the query will fail.
    pub fn query<N: DName>(&self, name: N, rtype: Rtype, class: Class)
                           -> Query {
        Query::new(self, name, rtype, class)
    }

    /// Returns an arc reference to the resolver’s config.
    pub fn conf(&self) -> Arc<ResolvConf> {
        self.core.with(|core| core.clone_conf())
    }
}

<commit_msg>Reactivate testing of resolv’s examples.<commit_after>//! An asynchronous stub resolver.
//!
//! A resolver is the component in the DNS that answers queries. A stub
//! resolver does so by simply relaying queries to a different resolver
//! chosen from a predefined set. This is how pretty much all user
//! applications use DNS.
//!
//! This module implements a modern, asynchronous stub resolver built on
//! top of [tokio-core].
//!
//! The module provides ways to create a *resolver* that knows how to
//! process DNS *queries*. A query asks for all the resource records
//! associated with a given triple of a domain name, resource record type,
//! and class (known as a *question*). It is a future resolving to a DNS
//! message with the response or an error. Queries can be combined into
//! *lookups* that use the returned resource records to answer more
//! specific enquiries such as all the IP addresses associated with a given
//! host name. The module provides a rich set of common lookups in the
//! [lookup] sub-module.
//!
//! The following gives an introduction into using the resolver. For an
//! introduction into the internal design, please have a look at the [intro]
//! sub-module.
//!
//!
//! # Creating a Resolver
//!
//! The resolver is represented by the [`Resolver`] type. When creating a
//! value of this type, you create all the parts of an actual resolver
//! according to a resolver configuration. Since these parts are handling
//! actual network traffic, the resolver needs a handle to a Tokio reactor
//! into which these parts will be spawned as futures.
//!
//! For the resolver configuration, there’s [`ResolvConf`]. While you can
//! create a value of this type by hand, the more common way is to use your
//! system’s resolver configuration. [`ResolvConf`] implements the `Default`
//! trait doing exactly that by reading `/etc/resolv.conf`.
//!
//! > That probably won’t work on Windows, but, sadly, I have no idea how to
//! > retrieve the resolver configuration there. Some help here would be
//! > very much appreciated.
//!
//! Since using the system configuration is the most common case by far,
//! [`Resolver`]’s `new()` function does just that. So, the easiest way to
//! get a resolver is just this:
//!
//! ```
//! # extern crate domain;
//! # extern crate tokio_core;
//! use domain::resolv::Resolver;
//! use tokio_core::reactor::Core;
//!
//! # fn main() {
//! let core = Core::new().unwrap();
//! let resolv = Resolver::new(&core.handle()).unwrap();
//! # }
//! ```
//!
//! If you do have a configuration, you can use the `from_conf()` function
//! instead.
//!
//!
//! # Using the Resolver: Queries
//!
//! As was mentioned above, the [`Resolver`] does’t actually contain the
//! networking parts necessary to answer queries. Instead, it only knows how
//! to contact those parts. Because of this, you can clone the resolver,
//! even pass it to other threads.
//!
//! Oddly, the one thing you can’t do with a resolver is start a query.
//! Instead, you need an intermediary type called [`ResolverTask`]. You’ll
//! get one through [`Resolver::start()`] or, more correctly, you get a future
//! to one through this method. You then chain on your actual query or
//! sequence of queries using combinators such as `Future::and_then()`.
//!
//! The actual query is started through [`ResolverTask::query()`]. It takes a
//! domain name, a resource record type, and a class and returns a future
//! that will resolve into either a [`MessageBuf`] with the response to the
//! query or an [`Error`].
//!
//! As an example, let’s find out the IPv6 addresses for `www.rust-lang.org`:
//!
//! ```
//! extern crate domain;
//! extern crate futures;
//! extern crate tokio_core;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::iana::{Class, Rtype};
//! use domain::rdata::Aaaa;
//! use domain::resolv::Resolver;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!     let resolv = Resolver::new(&core.handle()).unwrap();
//!
//!     let addrs = resolv.start().and_then(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org.").unwrap();
//!         resolv.query(name, Rtype::Aaaa, Class::In)
//!     });
//!     let response = core.run(addrs).unwrap();
//!     for record in response.answer().unwrap().limit_to::<Aaaa>() {
//!         println!("{}", record.unwrap());
//!     }
//! }
//! ```
//!
//! Note the final dot at `"www.rust-lang.org."` making it an absolute domain
//! name. Queries don’t know how to deal with relative names and will error
//! out if given one.
//!
//!
//! # Complex Queries: Lookups
//!
//! Most times when you are using DNS you aren’t really interested in a
//! bunch of resource records, though, you want an answer to a more direct
//! question. For instance, if you want to know the IP addresses for a
//! host name, you don’t really care that you have to make a query for the
//! `A` records and one for `AAAA` records for that host name. You want the
//! addresses.
//!
//! This is what lookups do. They take a [`ResolverTask`] and some additional
//! information and turn that into a future of some specific result. So,
//! to do lookups you have to follow the procedure using `start()` as given
//! above but instead of calling `query()` inside the closure, you use one
//! of the lookup functions from the [lookup] sub-module.
//!
//! Using [`lookup_host()`], the process of looking up the IP addresses
//! becomes much easier. To update above’s example:
//!
//! ```
//! extern crate domain;
//! extern crate futures;
//! extern crate tokio_core;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::resolv::Resolver;
//! use domain::resolv::lookup::lookup_host;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!     let resolv = Resolver::new(&core.handle()).unwrap();
//!
//!     let addrs = resolv.start().and_then(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org").unwrap();
//!         lookup_host(resolv, name)
//!     });
//!     let response = core.run(addrs).unwrap();
//!     for addr in response.iter() {
//!         println!("{}", addr);
//!     }
//! }
//! ```
//!
//! No more fiddeling with record types and classes and the result can now
//! iterate over IP addresses. And we get both IPv4 and IPv6 addresses to
//! boot.
//!
//! Furthermore, we now can use a relative host name. It will be turned into
//! an absolute name according to the rules set down by the configuration we
//! used when creating the resolver.
//!
//! As an aside, the lookup functions are named after the thing they look
//! up not their result following the example of the standard library. So,
//! when you look for the addresses for the host, you have to use
//! [`lookup_host()`], not [`lookup_addr()`].
//!
//! Have a look at the [lookup] module for all the lookup functions
//! currently available.
//!
//!
//! # The Run Shortcut
//!
//! If you only want to do a DNS lookup and don’t otherwise use tokio, there
//! is a shortcut through the [`Resolver::run()`] associated function. It
//! takes a closure from a [`ResolverTask`] to a future and waits while
//! driving the future to completing. In other words, it takes away all the
//! boiler plate from above:
//!
//! ```
//! extern crate domain;
//!
//! use std::str::FromStr;
//! use domain::bits::DNameBuf;
//! use domain::resolv::Resolver;
//! use domain::resolv::lookup::lookup_host;
//!
//! fn main() {
//!     let response = Resolver::run(|resolv| {
//!         let name = DNameBuf::from_str("www.rust-lang.org").unwrap();
//!         lookup_host(resolv, name)
//!     });
//!     for addr in response.unwrap().iter() {
//!         println!("{}", addr);
//!     }
//! }
//! ```
//!
//!
//! [intro]: intro/index.html
//! [lookup]: lookup/index.html
//! [tokio-core]: https://github.com/tokio-rs/tokio-core
//! [`Error`]: error/enum.Error.html
//! [`MessageBuf`]: ../bits/message/struct.MessageBuf.html
//! [`ResolvConf`]: conf/struct.ResolvConf.html
//! [`Resolver`]: struct.Resolver.html
//! [`Resolver::start()`]: struct.Resolver.html#method.start
//! [`Resolver::run()`]: struct.Resolver.html#method.run
//! [`ResolverTask`]: struct.ResolverTask.html
//! [`ResolverTask::query()`]: struct.ResolverTask.html#method.query
//! [`lookup_addr()`]: lookup/fn.lookup_addr.html
//! [`lookup_host()`]: lookup/fn.lookup_host.html

//============ Sub-modules ===================================================

//--- Re-exports

pub use self::conf::ResolvConf;
pub use self::error::{Error, Result};
pub use self::query::Query;

//--- Public modules

pub mod conf;
pub mod error;
pub mod hosts;
pub mod lookup;

//--- Private modules

mod core;
mod query;
mod request;
mod service;
mod tcp;
mod transport;
mod udp;
mod utils;

//--- Meta-modules for documentation

pub mod intro;

//============ Actual Content ================================================

use std::io;
use std::ops::Deref;
use std::result;
use std::sync::Arc;
use futures::{BoxFuture, Future, lazy};
use futures::task::TaskRc;
use tokio_core::reactor;
use ::bits::DName;
use ::iana::{Class, Rtype};
use self::conf::ResolvOptions;
use self::core::Core;

//------------ Resolver -----------------------------------------------------

/// Access to a resolver.
///
/// This types collects all information in order to be able to start a DNS
/// query on a resolver. You can create a new resolver by calling either
/// the `new()` or `from_conf()` functions passing in a handle to a Tokio
/// reactor core. Either function will spawn everything necessary for a
/// resolver into that core. Existing resolver values can be cloned. Clones
/// will refer to the same resolver.
///
/// In order to perform a query, you will have to call the `start()` method
/// to create a future that will resolve into an intermediary value that
/// will than allow calling a `query()` method on it and will also allow
/// more complex operations as a complex future.
///
/// Alternatively, you can use the `run()` associated function to
/// synchronously perfrom a series of queries.
#[derive(Clone, Debug)]
pub struct Resolver {
    core: Arc<Core>
}

impl Resolver {
    /// Creates a new resolver using the system’s default configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn new(reactor: &reactor::Handle) -> io::Result<Self> {
        Self::from_conf(reactor, ResolvConf::default())
    }

    /// Creates a new resolver using the given configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn from_conf(reactor: &reactor::Handle, conf: ResolvConf)
                     -> io::Result<Self> {
        Core::new(reactor, conf)
             .map(|core| Resolver{core: Arc::new(core)})
    }

    /// Returns a reference to the configuration of this resolver.
    pub fn conf(&self) -> &ResolvConf {
        &self.core.conf()
    }

    /// Returns a reference to the configuration options of this resolver.
    pub fn options(&self) -> &ResolvOptions {
        &self.core.conf().options
    }

    /// Starts a resolver future atop this resolver.
    ///
    /// The method returns a future that will resolve into a [ResolverTask]
    /// value that can be used to start queries atop this resolver.
    ///
    /// Since the future will never error, it is generic over the error type.
    ///
    /// [ResolverTask]: struct.ResolverTask.html
    pub fn start<E>(&self) -> BoxFuture<ResolverTask, E>
                 where E: Send + 'static {
        let core = self.core.deref().clone();
        lazy(move || Ok(ResolverTask{core: TaskRc::new(core)})).boxed()
    }
}

/// # Shortcuts
///
impl Resolver {
    /// Synchronously perform a DNS operation atop a standard resolver.
    ///
    /// This associated functions removes almost all boiler plate for the
    /// case that you want to perform some DNS operation on a resolver using
    /// the system’s configuration and wait for the result.
    ///
    /// The only argument is a closure taking a [ResolverTask] for creating
    /// queries and returning a future. Whatever that future resolves to will
    /// be returned.
    pub fn run<R, F>(f: F) -> result::Result<R::Item, R::Error>
               where R: Future, R::Error: From<io::Error> + Send + 'static,
                     F: FnOnce(ResolverTask) -> R {
        let mut reactor = try!(reactor::Core::new());
        let resolver = try!(Resolver::new(&reactor.handle()));
        let fut = resolver.start().and_then(f);
        reactor.run(fut)
    }

    /// Spawn a query.
    ///
    /// This method is a shortcut for `self.start().and_then(f).boxed()`.
    /// Because of the `boxed()` bit, it requires lots of things to be
    /// `Send + 'static` and because of that isn’t necessarily better than
    /// the longer way.
    ///
    /// I am also not sure if *spawn* is the right name. Probably not since
    /// it actually returns the future.
    pub fn spawn<R, F>(&self, f: F) -> BoxFuture<R::Item, R::Error>
                 where R: Future + Send + 'static,
                       R::Error: From<io::Error> + Send + 'static,
                       F: FnOnce(ResolverTask) -> R + Send + 'static {
        self.start().and_then(f).boxed()
    }
}

//------------ ResolverTask --------------------------------------------------

/// A resolver bound to a futures task.
///
/// You can use this type within a running future to start a query on top
/// of the resolver using the `query()` method.
#[derive(Clone)]
pub struct ResolverTask {
    core: TaskRc<Core>
}

impl ResolverTask {
    /// Start a DNS query on this resolver.
    ///
    /// Returns a future that, if successful, will resolve into a DNS
    /// message containing a response to a query for resource records of type
    /// `rtype` associated with the domain name `name` and class `class`. The
    /// name must be an absolute name or else the query will fail.
    pub fn query<N: DName>(&self, name: N, rtype: Rtype, class: Class)
                           -> Query {
        Query::new(self, name, rtype, class)
    }

    /// Returns an arc reference to the resolver’s config.
    pub fn conf(&self) -> Arc<ResolvConf> {
        self.core.with(|core| core.clone_conf())
    }
}

<|endoftext|>


<commit_before>#[derive(Debug, serde_derive::Deserialize)]
pub struct Config {
    pub name: String,
    pub package_key: Option<String>,
    pub repo_key: Option<String>,
    pub srcdest: String,
    pub logdest: String,
    pub pkgbuild: String,
    pub builds: std::collections::HashMap<super::builder::Arch, BuildConfig>,
    pub s3: Option<S3Config>,
}

#[derive(Debug, serde_derive::Deserialize)]
pub struct BuildConfig {
    pub chroot: String,
}

#[derive(Debug, serde_derive::Deserialize)]
pub struct S3Config {
    pub bucket: String,
    pub region: Region,
}

#[derive(Debug)]
pub struct Region(rusoto_core::Region);

impl<'de> serde::Deserialize<'de> for Region {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct Visitor;
        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Region;

            fn expecting(
                &self,
                formatter: &mut std::fmt::Formatter,
            ) -> Result<(), std::fmt::Error> {
                write!(formatter, "a valid AWS region name")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                use std::str::FromStr;

                match rusoto_core::Region::from_str(v) {
                    Ok(r) => Ok(Region(r)),
                    Err(e) => Err(serde::de::Error::invalid_value(
                        serde::de::Unexpected::Str(v),
                        &format!("{}", e).as_str(),
                    )),
                }
            }
        }
        deserializer.deserialize_str(Visitor {})
    }
}

impl Config {
    pub fn from_reader<R>(reader: R) -> serde_yaml::Result<Self>
    where
        R: std::io::Read,
    {
        serde_yaml::from_reader(reader)
    }

    pub fn repo_dir(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        std::path::PathBuf::from(&self.name)
            .join("os")
            .join(format!("{}", arch))
    }

    pub fn db_path(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        let mut path = self.repo_dir(arch).join(&self.name).into_os_string();
        path.push(".db");
        std::path::PathBuf::from(path)
    }

    pub fn files_path(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        let mut path = self.repo_dir(arch).join(&self.name).into_os_string();
        path.push(".files");
        std::path::PathBuf::from(path)
    }

    pub fn package_dir(&self, package_name: &str) -> std::path::PathBuf {
        std::path::PathBuf::from(&self.pkgbuild).join(package_name)
    }
}

pub struct S3 {
    client: rusoto_s3::S3Client,
    bucket: String,
}

impl S3 {
    pub fn new(config: &S3Config) -> Self {
        let Region(ref region) = config.region;
        let client = rusoto_s3::S3Client::new(region.clone());
        S3 {
            client,
            bucket: config.bucket.to_owned(),
        }
    }

    pub async fn download_repository(
        &self,
        config: &Config,
        arch: &super::builder::Arch,
    ) -> Result<(), anyhow::Error> {
        self.get(config.db_path(arch)).await?;
        self.get(config.files_path(arch)).await
    }

    pub async fn upload_repository<P>(
        &self,
        config: &Config,
        arch: &super::builder::Arch,
        package_paths: &[P],
    ) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        const XZ_MIME_TYPE: &str = "application/x-xz";
        const SIG_MIME_TYPE: &str = "application/pgp-signature";
        const GZIP_MIME_TYPE: &str = "application/gzip";

        for package_path in package_paths {
            self.put(package_path, XZ_MIME_TYPE).await?;
            if config.package_key.is_some() {
                let mut sig_path = package_path.as_ref().as_os_str().to_os_string();
                sig_path.push(".sig");
                self.put(&sig_path, SIG_MIME_TYPE).await?;
            }
        }
        self.put(config.files_path(arch), GZIP_MIME_TYPE).await?;
        let db_path = config.db_path(arch);
        self.put(&db_path, GZIP_MIME_TYPE).await?;
        if config.repo_key.is_some() {
            let mut sig_path = db_path.clone().into_os_string();
            sig_path.push(".sig");
            self.put(sig_path, SIG_MIME_TYPE).await?;
        }
        Ok(())
    }

    async fn get<P>(&self, path: P) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        use rusoto_s3::S3;

        let path = path.as_ref();
        let request = rusoto_s3::GetObjectRequest {
            bucket: self.bucket.to_owned(),
            key: path.to_string_lossy().into_owned(),
            ..rusoto_s3::GetObjectRequest::default()
        };
        println!("Download {}", path.display());
        match self.client.get_object(request).await {
            Ok(output) => {
                if let Some(mut body) = output.body {
                    use futures::StreamExt as _;
                    use tokio::io::AsyncWriteExt as _;

                    let file = tokio::fs::File::create(path).await?;
                    let mut writer = tokio::io::BufWriter::new(file);
                    while let Some(item) = body.next().await {
                        writer.write_all(&item?).await?;
                    }
                    writer.shutdown().await?;
                }
                Ok(())
            }
            Err(rusoto_core::RusotoError::Service(rusoto_s3::GetObjectError::NoSuchKey(_))) => {
                Ok(())
            }
            Err(e) => Err(anyhow::Error::from(e)),
        }
    }

    async fn put<P>(&self, path: P, content_type: &str) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        use futures::FutureExt as _;
        use futures::TryStreamExt as _;
        use rusoto_s3::S3;

        let path = path.as_ref();
        let metadata = tokio::fs::metadata(path).await?;
        let stream = rusoto_s3::StreamingBody::new(
            tokio::fs::read(path.to_owned())
                .into_stream()
                .map_ok(|b| bytes::Bytes::from(b)),
        );
        let request = rusoto_s3::PutObjectRequest {
            bucket: self.bucket.to_owned(),
            key: path.to_string_lossy().into_owned(),
            content_type: Some(content_type.to_owned()),
            content_length: Some(metadata.len() as i64),
            body: Some(stream),
            ..Default::default()
        };
        println!("Upload {}", path.display());
        self.client.put_object(request).await?;
        Ok(())
    }
}
<commit_msg>Simplify closure<commit_after>#[derive(Debug, serde_derive::Deserialize)]
pub struct Config {
    pub name: String,
    pub package_key: Option<String>,
    pub repo_key: Option<String>,
    pub srcdest: String,
    pub logdest: String,
    pub pkgbuild: String,
    pub builds: std::collections::HashMap<super::builder::Arch, BuildConfig>,
    pub s3: Option<S3Config>,
}

#[derive(Debug, serde_derive::Deserialize)]
pub struct BuildConfig {
    pub chroot: String,
}

#[derive(Debug, serde_derive::Deserialize)]
pub struct S3Config {
    pub bucket: String,
    pub region: Region,
}

#[derive(Debug)]
pub struct Region(rusoto_core::Region);

impl<'de> serde::Deserialize<'de> for Region {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct Visitor;
        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Region;

            fn expecting(
                &self,
                formatter: &mut std::fmt::Formatter,
            ) -> Result<(), std::fmt::Error> {
                write!(formatter, "a valid AWS region name")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                use std::str::FromStr;

                match rusoto_core::Region::from_str(v) {
                    Ok(r) => Ok(Region(r)),
                    Err(e) => Err(serde::de::Error::invalid_value(
                        serde::de::Unexpected::Str(v),
                        &format!("{}", e).as_str(),
                    )),
                }
            }
        }
        deserializer.deserialize_str(Visitor {})
    }
}

impl Config {
    pub fn from_reader<R>(reader: R) -> serde_yaml::Result<Self>
    where
        R: std::io::Read,
    {
        serde_yaml::from_reader(reader)
    }

    pub fn repo_dir(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        std::path::PathBuf::from(&self.name)
            .join("os")
            .join(format!("{}", arch))
    }

    pub fn db_path(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        let mut path = self.repo_dir(arch).join(&self.name).into_os_string();
        path.push(".db");
        std::path::PathBuf::from(path)
    }

    pub fn files_path(&self, arch: &super::builder::Arch) -> std::path::PathBuf {
        let mut path = self.repo_dir(arch).join(&self.name).into_os_string();
        path.push(".files");
        std::path::PathBuf::from(path)
    }

    pub fn package_dir(&self, package_name: &str) -> std::path::PathBuf {
        std::path::PathBuf::from(&self.pkgbuild).join(package_name)
    }
}

pub struct S3 {
    client: rusoto_s3::S3Client,
    bucket: String,
}

impl S3 {
    pub fn new(config: &S3Config) -> Self {
        let Region(ref region) = config.region;
        let client = rusoto_s3::S3Client::new(region.clone());
        S3 {
            client,
            bucket: config.bucket.to_owned(),
        }
    }

    pub async fn download_repository(
        &self,
        config: &Config,
        arch: &super::builder::Arch,
    ) -> Result<(), anyhow::Error> {
        self.get(config.db_path(arch)).await?;
        self.get(config.files_path(arch)).await
    }

    pub async fn upload_repository<P>(
        &self,
        config: &Config,
        arch: &super::builder::Arch,
        package_paths: &[P],
    ) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        const XZ_MIME_TYPE: &str = "application/x-xz";
        const SIG_MIME_TYPE: &str = "application/pgp-signature";
        const GZIP_MIME_TYPE: &str = "application/gzip";

        for package_path in package_paths {
            self.put(package_path, XZ_MIME_TYPE).await?;
            if config.package_key.is_some() {
                let mut sig_path = package_path.as_ref().as_os_str().to_os_string();
                sig_path.push(".sig");
                self.put(&sig_path, SIG_MIME_TYPE).await?;
            }
        }
        self.put(config.files_path(arch), GZIP_MIME_TYPE).await?;
        let db_path = config.db_path(arch);
        self.put(&db_path, GZIP_MIME_TYPE).await?;
        if config.repo_key.is_some() {
            let mut sig_path = db_path.clone().into_os_string();
            sig_path.push(".sig");
            self.put(sig_path, SIG_MIME_TYPE).await?;
        }
        Ok(())
    }

    async fn get<P>(&self, path: P) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        use rusoto_s3::S3;

        let path = path.as_ref();
        let request = rusoto_s3::GetObjectRequest {
            bucket: self.bucket.to_owned(),
            key: path.to_string_lossy().into_owned(),
            ..rusoto_s3::GetObjectRequest::default()
        };
        println!("Download {}", path.display());
        match self.client.get_object(request).await {
            Ok(output) => {
                if let Some(mut body) = output.body {
                    use futures::StreamExt as _;
                    use tokio::io::AsyncWriteExt as _;

                    let file = tokio::fs::File::create(path).await?;
                    let mut writer = tokio::io::BufWriter::new(file);
                    while let Some(item) = body.next().await {
                        writer.write_all(&item?).await?;
                    }
                    writer.shutdown().await?;
                }
                Ok(())
            }
            Err(rusoto_core::RusotoError::Service(rusoto_s3::GetObjectError::NoSuchKey(_))) => {
                Ok(())
            }
            Err(e) => Err(anyhow::Error::from(e)),
        }
    }

    async fn put<P>(&self, path: P, content_type: &str) -> Result<(), anyhow::Error>
    where
        P: AsRef<std::path::Path>,
    {
        use futures::FutureExt as _;
        use futures::TryStreamExt as _;
        use rusoto_s3::S3;

        let path = path.as_ref();
        let metadata = tokio::fs::metadata(path).await?;
        let stream = rusoto_s3::StreamingBody::new(
            tokio::fs::read(path.to_owned())
                .into_stream()
                .map_ok(bytes::Bytes::from),
        );
        let request = rusoto_s3::PutObjectRequest {
            bucket: self.bucket.to_owned(),
            key: path.to_string_lossy().into_owned(),
            content_type: Some(content_type.to_owned()),
            content_length: Some(metadata.len() as i64),
            body: Some(stream),
            ..Default::default()
        };
        println!("Upload {}", path.display());
        self.client.put_object(request).await?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/// Get the (arbitrary) zeroth element of a hashset.
#[marco_export]
macro_rules! zeroth {
    ($hs: expr) => {{
        *$hs.iter().next().unwrap()
    }}
}

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, HashSet<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    /// Add a clause, return the ID of the inserted clause
    /// Right now, this isn't public; api is odd as we have an odd representation of literals.
    /// TODO: Mask this with public function?
    fn add_clause(&mut self, clause: HashSet<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id: i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    /// Unit propagation: propagate the literal associated with the clause id `clause`, and remove
    /// it from `self.units`.
    pub fn unit_propagate(&mut self, unit: i32) {
		println!("UNIT_PROP {}",unit);
        // Remove clauses with lit and remove lit from occurrences.
        let lit = zeroth!(self.clauses.get(&unit).expect("unit clause not found"));
        self.propagate(lit);
        // This needs to be true, i.e. unit clause id needs to be in the unit clauses
        assert!(self.units.remove(&unit));
    }

    /// Remove all clauses containing literal `lit` from the CNF, and remove the negation of `lit`
    /// from the remaining clauses.
    /// TODO: unit_propagate and propagate should return true/false
    /// depending on whether the updated CNF problem is satisfiable
    pub fn propagate(&mut self, lit: i32) {
		// Remove clauses with lit and remove lit from occurrences.
		if let Some(vec) = self.occurrences.remove(&lit) {
			for occ in &vec {
				self.clauses.remove(occ);
				self.nclause-=1;
			}
		}

        // Remove ~lit from other clausesa
		self.remove_negation(lit);
    }

	fn remove_negation(&mut self, lit : i32){
		let neg = lit^1;
		if let Some(vec) = self.occurrences.remove(&neg) {
			for occ in &vec {
				if let Some(mut c) = self.clauses.remove(occ) {
					c.remove(&neg);
					if c.len()==1 { self.units.insert(*occ); }
					self.clauses.insert(*occ, c);
				}
			}
		}
	}
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?} Units: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause, self.units,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>
}

impl PartialAssignment {
    pub fn new(n: usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect()
        }
    }

    fn assign(&mut self, v: usize, assn: bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
		self.unassigned.remove(&(v as i32));
    }

    pub fn assign_literal(&mut self, lit: i32){
        let polarity: bool = lit & 1 == 0;
        let v: usize = (lit >> 1) as usize;
        self.assign(v - 1, polarity);
    }

    fn unassign(&mut self, v: usize) {
        self.assignment[v] = None;
		self.unassigned.insert(v as i32);
    }

    pub fn unassign_literal(&mut self, lit: i32){
        let v: usize = (lit >> 1) as usize;
        self.unassign(v - 1);
    }
}

impl Clone for PartialAssignment {
    fn clone(&self) -> PartialAssignment {
		PartialAssignment {
            assignment : self.assignment.clone(),
            unassigned : self.unassigned.clone(),
        }
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: HashSet<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;
    use std::collections::HashSet;

    use super::parse_dimacs_file;
    // use super::zeroth;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }

    // TODO: Make this doc test (with unit propagate); create_tempfile may need to be an importable
    // macro up there
    #[test]
    fn unit_propagate_works() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        assert!(cnf.units.is_empty());
    }

    #[test]
    fn unit_propagate_works_2() {
        let tmpfile = create_tempfile!("
            p cnf 4 4
            1 0
            1 2 0
            2 3 0
            4 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        // Only one unit clause left
        assert_eq!(cnf.units.len(), 1);
        cnf.unit_propagate(3);
        // No more unit clauses
        assert!(cnf.units.is_empty());
    }

    #[test]
    #[should_panic(expected = "unit clause not found")]
    fn unit_clause_not_found() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(2);
    }

    #[test]
    fn zeroth_works() {
        let mut hs = HashSet::new();
        hs.insert(5);
        assert_eq!(zeroth!(hs), 5);
    }

    #[test]
    fn zeroth_works_2() {
        let mut hs = HashSet::new();
        hs.insert(5);
        hs.insert(535);
        let zth = zeroth!(hs);
        assert!(zth == 5 || zth == 535);
    }
}
<commit_msg>Add duplicate unit clause test (currently fails)<commit_after>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/// Get the (arbitrary) zeroth element of a hashset.
#[marco_export]
macro_rules! zeroth {
    ($hs: expr) => {{
        *$hs.iter().next().unwrap()
    }}
}

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, HashSet<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    /// Add a clause, return the ID of the inserted clause
    /// Right now, this isn't public; api is odd as we have an odd representation of literals.
    /// TODO: Mask this with public function?
    fn add_clause(&mut self, clause: HashSet<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id: i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    /// Unit propagation: propagate the literal associated with the clause id `clause`, and remove
    /// it from `self.units`.
    pub fn unit_propagate(&mut self, unit: i32) {
		println!("UNIT_PROP {}",unit);
        // Remove clauses with lit and remove lit from occurrences.
        let lit = zeroth!(self.clauses.get(&unit).expect("unit clause not found"));
        self.propagate(lit);
        // This needs to be true, i.e. unit clause id needs to be in the unit clauses
        assert!(self.units.remove(&unit));
    }

    /// Remove all clauses containing literal `lit` from the CNF, and remove the negation of `lit`
    /// from the remaining clauses.
    /// TODO: unit_propagate and propagate should return true/false
    /// depending on whether the updated CNF problem is satisfiable
    pub fn propagate(&mut self, lit: i32) {
		// Remove clauses with lit and remove lit from occurrences.
		if let Some(vec) = self.occurrences.remove(&lit) {
			for occ in &vec {
				self.clauses.remove(occ);
				self.nclause-=1;
			}
		}

        // Remove ~lit from other clausesa
		self.remove_negation(lit);
    }

	fn remove_negation(&mut self, lit : i32){
		let neg = lit^1;
		if let Some(vec) = self.occurrences.remove(&neg) {
			for occ in &vec {
				if let Some(mut c) = self.clauses.remove(occ) {
					c.remove(&neg);
					if c.len()==1 { self.units.insert(*occ); }
					self.clauses.insert(*occ, c);
				}
			}
		}
	}
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?} Units: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause, self.units,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>
}

impl PartialAssignment {
    pub fn new(n: usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect()
        }
    }

    fn assign(&mut self, v: usize, assn: bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
		self.unassigned.remove(&(v as i32));
    }

    pub fn assign_literal(&mut self, lit: i32){
        let polarity: bool = lit & 1 == 0;
        let v: usize = (lit >> 1) as usize;
        self.assign(v - 1, polarity);
    }

    fn unassign(&mut self, v: usize) {
        self.assignment[v] = None;
		self.unassigned.insert(v as i32);
    }

    pub fn unassign_literal(&mut self, lit: i32){
        let v: usize = (lit >> 1) as usize;
        self.unassign(v - 1);
    }
}

impl Clone for PartialAssignment {
    fn clone(&self) -> PartialAssignment {
		PartialAssignment {
            assignment : self.assignment.clone(),
            unassigned : self.unassigned.clone(),
        }
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: HashSet<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;
    use std::collections::HashSet;

    use super::parse_dimacs_file;
    // use super::zeroth;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }

    // TODO: Make this doc test (with unit propagate); create_tempfile may need to be an importable
    // macro up there
    #[test]
    fn unit_propagate_works() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        assert!(cnf.units.is_empty());
    }

    #[test]
    fn unit_propagate_works_2() {
        let tmpfile = create_tempfile!("
            p cnf 4 4
            1 0
            1 2 0
            2 3 0
            4 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        // Only one unit clause left
        assert_eq!(cnf.units.len(), 1);
        cnf.unit_propagate(3);
        // No more unit clauses
        assert!(cnf.units.is_empty());
    }

    /// This one is making sure that if unit_propagate removes a separate unit clause, the separate
    /// unit clause can still be unit propagated and will fail gracefully
    #[test]
    fn unit_propagate_works_special() {
        let tmpfile = create_tempfile!("
            p cnf 2 6
            1 0
            1 0
            2 0
            2 0
            2 0
            2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        // There are six clauses and all of them are units. One iteration of dpll will attempt to
        // remove all of these clauses. Even though unit_propagate(0) and unit_propagate(2) will
        // remove all of the clauses, the other unit_propagates should not panic.
        cnf.unit_propagate(0);
        cnf.unit_propagate(1);
        cnf.unit_propagate(2);
        cnf.unit_propagate(3);
        cnf.unit_propagate(4);
        cnf.unit_propagate(5);
        // The result should be an empty cnf - no clauses, no unit clauses.
        assert_eq!(cnf.clauses.len(), 0);
        assert_eq!(cnf.units.len(), 0);
    }

    #[test]
    #[should_panic(expected = "unit clause not found")]
    fn unit_clause_not_found() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(2);
    }

    #[test]
    fn zeroth_works() {
        let mut hs = HashSet::new();
        hs.insert(5);
        assert_eq!(zeroth!(hs), 5);
    }

    #[test]
    fn zeroth_works_2() {
        let mut hs = HashSet::new();
        hs.insert(5);
        hs.insert(535);
        let zth = zeroth!(hs);
        assert!(zth == 5 || zth == 535);
    }

    // TODO: nclauses bookkeeping test.
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use cgmath::Point2;

use crate::bsdf::BSDF;
use crate::color::Color;
use crate::float::*;
use crate::obj_load;
use crate::texture::Texture;

mod diffuse;
mod glossy;
mod specular;

use self::diffuse::*;
use self::glossy::*;
use self::specular::*;

/// Scattering model over the whole surface
pub trait ScatteringT {
    /// Get the local scattering functions
    fn local(&self, tex_coords: Point2<Float>) -> BSDF;
    /// The texture to use for preview rendering
    fn preview_texture(&self) -> &Texture;
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum Scattering {
    DR(DiffuseReflection),
    GB(GlossyBlend),
    GR(GlossyReflection),
    GT(GlossyTransmission),
    SR(SpecularReflection),
    ST(SpecularTransmission),
}

fn diffuse_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.diffuse_texture {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.diffuse_color.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn specular_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.specular_texture {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.specular_color.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn transmissive_texture(obj_mat: &obj_load::Material) -> Texture {
    let color = Color::from(
        obj_mat
            .transmission_color
            .expect("No transmission color for transmissive material"),
    );
    // MTL spec states that transmissive color defines light that is able to pass through
    // but some scenes seem to interpret it as a filter that removes light
    let color = Color::white() - color;
    Texture::from_color(color)
}

impl Scattering {
    pub fn from_obj(obj_mat: &obj_load::Material) -> Self {
        use self::Scattering::*;

        let diffuse = diffuse_texture(obj_mat);
        let specular = specular_texture(obj_mat);
        match obj_mat.illumination_model.unwrap_or(0) {
            2 => {
                let exponent = obj_mat.specular_exponent.unwrap().to_float();
                if diffuse.is_black() {
                    GR(GlossyReflection::new(specular, exponent))
                } else if specular.is_black() {
                    DR(DiffuseReflection::new(diffuse))
                } else {
                    GB(GlossyBlend::new(diffuse, specular, exponent))
                }
            }
            5 => {
                let texture = specular_texture(obj_mat);
                SR(SpecularReflection::new(texture))
            }
            4 | 6 | 7 => {
                let transmissive = transmissive_texture(obj_mat);
                let exponent = obj_mat.specular_exponent.unwrap().to_float();
                let eta = obj_mat
                    .index_of_refraction
                    .expect("No index of refraction for translucent material")
                    .to_float();
                if (eta - 1.0).abs() < crate::consts::EPSILON {
                    // Glossy does not handle eta = 1 properly
                    // and the distribution would be the same anyways
                    ST(SpecularTransmission::new(specular, transmissive, eta))
                } else {
                    GT(GlossyTransmission::new(
                        specular,
                        transmissive,
                        exponent,
                        eta,
                    ))
                }
            }
            i => {
                if i > 10 {
                    println!("Illumination model {} is not defined in the mtl spec!", i);
                    println!("Defaulting to diffuse reflection.");
                } else {
                    println!("Unimplemented illumination model {}!", i);
                    println!("Defaulting to diffuse reflection.");
                }
                DR(DiffuseReflection::new(diffuse))
            }
        }
    }
}

impl Deref for Scattering {
    type Target = dyn ScatteringT;

    fn deref(&self) -> &Self::Target {
        use self::Scattering::*;
        match self {
            DR(inner) => inner,
            GB(inner) => inner,
            GR(inner) => inner,
            GT(inner) => inner,
            SR(inner) => inner,
            ST(inner) => inner,
        }
    }
}
<commit_msg>Match illumination model properly<commit_after>use std::ops::Deref;

use cgmath::Point2;

use crate::bsdf::BSDF;
use crate::color::Color;
use crate::float::*;
use crate::obj_load;
use crate::texture::Texture;

mod diffuse;
mod glossy;
mod specular;

use self::diffuse::*;
use self::glossy::*;
use self::specular::*;

/// Scattering model over the whole surface
pub trait ScatteringT {
    /// Get the local scattering functions
    fn local(&self, tex_coords: Point2<Float>) -> BSDF;
    /// The texture to use for preview rendering
    fn preview_texture(&self) -> &Texture;
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum Scattering {
    DR(DiffuseReflection),
    GB(GlossyBlend),
    GR(GlossyReflection),
    GT(GlossyTransmission),
    SR(SpecularReflection),
    ST(SpecularTransmission),
}

fn diffuse_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.diffuse_texture {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.diffuse_color.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn specular_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.specular_texture {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.specular_color.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn transmissive_texture(obj_mat: &obj_load::Material) -> Texture {
    let color = Color::from(
        obj_mat
            .transmission_color
            .expect("No transmission color for transmissive material"),
    );
    // MTL spec states that transmissive color defines light that is able to pass through
    // but some scenes seem to interpret it as a filter that removes light
    let color = Color::white() - color;
    Texture::from_color(color)
}

impl Scattering {
    pub fn from_obj(obj_mat: &obj_load::Material) -> Self {
        use self::Scattering::*;

        let diffuse = diffuse_texture(obj_mat);
        let specular = specular_texture(obj_mat);
        match obj_mat.illumination_model {
            Some(2) => {
                let exponent = obj_mat.specular_exponent.unwrap().to_float();
                if diffuse.is_black() {
                    GR(GlossyReflection::new(specular, exponent))
                } else if specular.is_black() {
                    DR(DiffuseReflection::new(diffuse))
                } else {
                    GB(GlossyBlend::new(diffuse, specular, exponent))
                }
            }
            Some(5) => {
                let texture = specular_texture(obj_mat);
                SR(SpecularReflection::new(texture))
            }
            Some(4) | Some(6) | Some(7) => {
                let transmissive = transmissive_texture(obj_mat);
                let exponent = obj_mat.specular_exponent.unwrap().to_float();
                let eta = obj_mat
                    .index_of_refraction
                    .expect("No index of refraction for translucent material")
                    .to_float();
                if (eta - 1.0).abs() < crate::consts::EPSILON {
                    // Glossy does not handle eta = 1 properly
                    // and the distribution would be the same anyways
                    ST(SpecularTransmission::new(specular, transmissive, eta))
                } else {
                    GT(GlossyTransmission::new(
                        specular,
                        transmissive,
                        exponent,
                        eta,
                    ))
                }
            }
            Some(i) => {
                if i > 10 {
                    println!("Illumination model {} is not defined in the mtl spec!", i);
                    println!("Defaulting to diffuse reflection.");
                } else {
                    println!("Unimplemented illumination model {}!", i);
                    println!("Defaulting to diffuse reflection.");
                }
                DR(DiffuseReflection::new(diffuse))
            }
            None => {
                DR(DiffuseReflection::new(diffuse))
            }
        }
    }
}

impl Deref for Scattering {
    type Target = dyn ScatteringT;

    fn deref(&self) -> &Self::Target {
        use self::Scattering::*;
        match self {
            DR(inner) => inner,
            GB(inner) => inner,
            GR(inner) => inner,
            GT(inner) => inner,
            SR(inner) => inner,
            ST(inner) => inner,
        }
    }
}
<|endoftext|>


<commit_before>/// Registers a selector, returning an `Sel`.
///
/// # Example
/// ``` ignore
/// let sel = sel!(description);
/// let sel = sel!(setObject:forKey:);
/// ```
#[macro_export]
macro_rules! sel {
    // Declare a function to hide unsafety, otherwise we can trigger the
    // unused_unsafe lint; see rust-lang/rust#8472
    ($name:ident) => ({
        #[inline(always)]
        fn register_sel(name_with_nul: &str) -> $crate::runtime::Sel {
            let ptr = name_with_nul.as_ptr() as *const i8;
            unsafe { $crate::runtime::sel_registerName(ptr) }
        }
        register_sel(concat!(stringify!($name), '\0'))

    });
    ($($name:ident :)+) => ({
        #[inline(always)]
        fn register_sel(name_with_nul: &str) -> $crate::runtime::Sel {
            let ptr = name_with_nul.as_ptr() as *const i8;
            unsafe { $crate::runtime::sel_registerName(ptr) }
        }
        register_sel(concat!($(stringify!($name), ':'),+, '\0'))
    });
}

/// Sends a message to an object. The first argument should implement the
/// `ToMessage` trait, and the syntax is similar to the message syntax in
/// Objective-C.
///
/// Variadic arguments are not currently supported. This macro should only be
/// used in cases where `objc_msgSend` would be used, as opposed to
/// `objc_msgSend_stret` or `objc_msgSend_fpret`.
/// For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// # Example
/// ``` ignore
/// let description = msg_send![obj, description];
/// msg_send![obj, setArg1:1u arg2:2u];
/// ```
#[macro_export]
macro_rules! msg_send {
    ($obj:expr, $name:ident) => ({
        let obj = &$obj;
        let sel = sel!($name);
        let args = ();
        if cfg!(not(ndebug)) {
            match $crate::send_message_verified(obj, sel, args) {
                Err(s) => panic!("Verify message failed: {}", s),
                Ok(r) => r,
            }
        } else {
            $crate::send_message(obj, sel, args)
        }
    });
    ($obj:expr, $($name:ident : $arg:expr)+) => ({
        let obj = &$obj;
        let sel = sel!($($name:)+);
        let args = ($($arg,)*);
        if cfg!(not(ndebug)) {
            match $crate::send_message_verified(obj, sel, args) {
                Err(s) => panic!("Verify message failed: {}", s),
                Ok(r) => r,
            }
        } else {
            $crate::send_message(obj, sel, args)
        }
    });
}

/// Declares a method, returning a `MethodDecl`.
/// The syntax is a combination of Objective-C's syntax and Rust's:
///
/// * The first part is the type and name of the self variable for the method
/// followed by a comma, like: `(&MyObject)this,`.
/// * Then, the parts of the selector and arguments follow, separated by commas,
/// like `setArg1:(uint)arg1, arg2:(uint)arg2`.
/// * After this, if the method has a return type, it should be followed by an
/// arrow ("->"), otherwise it should be terminated by a semicolon.
/// * Then a block declares the implementation of the method using the provided
/// arguments.
///
/// # Example
/// ``` ignore
/// method!(
///     (&mut MYObject)this, setNumber:(uint)number; {
///         this.set_number(number);
///     }
/// )
///
/// method!(
///     (&MYObject)this, number -> uint, {
///         this.number()
///     }
/// )
/// ```
#[macro_export]
macro_rules! method {
    // Void no arguments
    (
        ($self_ty:ty)$self_name:ident,
        $name:ident
        ; $body:block
    ) => ({
        method!(-$name,; sel!($name), $body, (), $self_name: $self_ty,)
    });
    // No arguments
    (
        ($self_ty:ty)$self_name:ident,
        $name:ident
        -> $ret_ty:ty, $body:block
    ) => ({
        method!(-$name,; sel!($name), $body, $ret_ty, $self_name: $self_ty,)
    });
    // Void with arguments
    (
        ($self_ty:ty)$self_name:ident,
        $($name:ident : ($arg_ty:ty) $arg_name:ident),+
        ; $body:block
    ) => ({
        method!($(-$name,)+; sel!($($name:)+), $body, (), $self_name: $self_ty, $($arg_name: $arg_ty),+)
    });
    // Arguments
    (
        ($self_ty:ty)$self_name:ident,
        $($name:ident : ($arg_ty:ty) $arg_name:ident),+
        -> $ret_ty:ty, $body:block
    ) => ({
        method!($(-$name,)+; sel!($($name:)+), $body, $ret_ty, $self_name: $self_ty, $($arg_name: $arg_ty),+)
    });
    (
        // Preceding dash is necessary to disambiguate
        -$first_name:ident, $(-$next_name:ident,)*;
        $sel:expr, $body:block, $ret_ty:ty,
        $self_name:ident : $self_ty:ty, $($arg_name:ident : $arg_ty:ty),*
    ) => ({
        #[allow(non_snake_case)]
        extern fn $first_name($self_name: $self_ty, _cmd: $crate::runtime::Sel $(, $arg_name: $arg_ty)*) -> $ret_ty $body

        let f: extern fn($self_ty, $crate::runtime::Sel $(, $arg_ty)*) -> $ret_ty = $first_name;
        $crate::MethodDecl::new($sel, f).unwrap()
    });
}
<commit_msg>Removed the complicated method! macro.<commit_after>/// Registers a selector, returning an `Sel`.
///
/// # Example
/// ``` ignore
/// let sel = sel!(description);
/// let sel = sel!(setObject:forKey:);
/// ```
#[macro_export]
macro_rules! sel {
    // Declare a function to hide unsafety, otherwise we can trigger the
    // unused_unsafe lint; see rust-lang/rust#8472
    ($name:ident) => ({
        #[inline(always)]
        fn register_sel(name_with_nul: &str) -> $crate::runtime::Sel {
            let ptr = name_with_nul.as_ptr() as *const i8;
            unsafe { $crate::runtime::sel_registerName(ptr) }
        }
        register_sel(concat!(stringify!($name), '\0'))

    });
    ($($name:ident :)+) => ({
        #[inline(always)]
        fn register_sel(name_with_nul: &str) -> $crate::runtime::Sel {
            let ptr = name_with_nul.as_ptr() as *const i8;
            unsafe { $crate::runtime::sel_registerName(ptr) }
        }
        register_sel(concat!($(stringify!($name), ':'),+, '\0'))
    });
}

/// Sends a message to an object. The first argument should implement the
/// `ToMessage` trait, and the syntax is similar to the message syntax in
/// Objective-C.
///
/// Variadic arguments are not currently supported. This macro should only be
/// used in cases where `objc_msgSend` would be used, as opposed to
/// `objc_msgSend_stret` or `objc_msgSend_fpret`.
/// For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// # Example
/// ``` ignore
/// let description = msg_send![obj, description];
/// msg_send![obj, setArg1:1u arg2:2u];
/// ```
#[macro_export]
macro_rules! msg_send {
    ($obj:expr, $name:ident) => ({
        let obj = &$obj;
        let sel = sel!($name);
        let args = ();
        if cfg!(not(ndebug)) {
            match $crate::send_message_verified(obj, sel, args) {
                Err(s) => panic!("Verify message failed: {}", s),
                Ok(r) => r,
            }
        } else {
            $crate::send_message(obj, sel, args)
        }
    });
    ($obj:expr, $($name:ident : $arg:expr)+) => ({
        let obj = &$obj;
        let sel = sel!($($name:)+);
        let args = ($($arg,)*);
        if cfg!(not(ndebug)) {
            match $crate::send_message_verified(obj, sel, args) {
                Err(s) => panic!("Verify message failed: {}", s),
                Ok(r) => r,
            }
        } else {
            $crate::send_message(obj, sel, args)
        }
    });
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use middleware::Application;
use server::request::{Request, ServerRequest};

use server_backend::server::{Handler, Incoming};
use server_backend::server::Request as RawRequest;
use server_backend::server::Response as RawResponse;
use server_backend::header::common::ContentLength;
use server_backend::net::{HttpStream, HttpAcceptor, Fresh};

pub trait ConcurrentHandler: Send + Sync {
    fn handle(&self, req: RawRequest, res: RawResponse<Fresh>);
}

pub struct Concurrent<H: ConcurrentHandler> { pub handler: Arc<H> }

impl<H: ConcurrentHandler> Handler<HttpAcceptor, HttpStream> for Concurrent<H> {
    fn handle(self, mut incoming: Incoming) {
        for (mut req, mut res) in incoming {
            let clone = self.handler.clone();
            spawn(proc() { clone.handle(req, res) })
        }
    }
}

macro_rules! try_abort(
    ($e:expr) => {{
        match $e {
            Ok(v) => v,
            Err(..) => return
        }
    }}
)

impl ConcurrentHandler for Application {
    fn handle(&self, req: RawRequest, mut res: RawResponse<Fresh>) {

        let mut request = ServerRequest::wrap(req).unwrap();
        let maybe_response = self.call(&mut request);

        match maybe_response {
            Ok(response) => {
                *res.status_mut() = response.status;
                *res.headers_mut() = response.headers;

                match response.body {
                    Some(mut reader) => {
                        let content = try_abort!(reader.read_to_end());
                        res.headers_mut().set(ContentLength(content.len()));
                        let mut res = try_abort!(res.start());
                        try_abort!(res.write(content.as_slice()));
                        try_abort!(res.end());
                    },
                    _ => try_abort!(res.start().and_then(|res| res.end()))
                }
            },

            Err(_) => {
                println!("No response");
                try_abort!(res.start().and_then(|res| res.end()));
            }
        }
    }
}<commit_msg>refactor: update hyper<commit_after>use std::sync::Arc;

use middleware::Application;
use server::request::{Request, ServerRequest};

use server_backend::server::{Connection, Handler, Incoming};
use server_backend::header::common::ContentLength;
use server_backend::net::{HttpStream, HttpAcceptor};

pub trait ConcurrentHandler: Send + Sync {
    fn handle(&self, Connection);
}

pub struct Concurrent<H: ConcurrentHandler> { pub handler: Arc<H> }

impl<H: ConcurrentHandler> Handler<HttpAcceptor, HttpStream> for Concurrent<H> {
    fn handle(self, mut incoming: Incoming) {
        for mut connection in incoming {
            let clone = self.handler.clone();
            spawn(proc() { clone.handle(connection) })
        }
    }
}

macro_rules! try_abort(
    ($e:expr) => {{
        match $e {
            Ok(v) => v,
            Err(..) => return
        }
    }}
)

impl ConcurrentHandler for Application {
    fn handle(&self, connection: Connection) {

        let (req, mut res) = connection.open().unwrap();

        let mut request = ServerRequest::wrap(req).unwrap();
        let maybe_response = self.call(&mut request);

        match maybe_response {
            Ok(response) => {
                *res.status_mut() = response.status;
                *res.headers_mut() = response.headers;

                match response.body {
                    Some(mut reader) => {
                        let content = try_abort!(reader.read_to_end());
                        res.headers_mut().set(ContentLength(content.len()));
                        let mut res = try_abort!(res.start());
                        try_abort!(res.write(content.as_slice()));
                        try_abort!(res.end());
                    },
                    _ => try_abort!(res.start().and_then(|res| res.end()))
                }
            },

            Err(_) => {
                println!("No response");
                try_abort!(res.start().and_then(|res| res.end()));
            }
        }
    }
}<|endoftext|>