<commit_before>extern crate rosc;

use rosc::{encoder, decoder};
use rosc::types::{OscMessage, OscMidiMessage, OscColor, OscPacket, OscType};

#[test]
fn test_encode_message_wo_args() {
    let msg = OscMessage {
        addr: "/some/addr".to_string(),
        args: None,
    };

    let enc_msg = encoder::encode_message(&msg).unwrap();
    match decoder::decode(&enc_msg).unwrap() {
        OscPacket::Message(dec_msg) => assert_eq!(msg.addr, dec_msg.addr),
        _ => panic!("Expected OSC message!"),
    }
}

#[test]
fn test_encode_message_with_args() {
    let addr = "/another/address/1";
    let string_arg = "This is a string";
    let blob_arg = vec![1u8, 2u8, 3u8];
    let time_arg = (123, 456);
    let int_arg = 4;
    let float_arg = 3.14;
    let long_arg = 42;
    let double_arg = 3.1415;
    let char_arg = 'c';
    let midi_arg = OscMidiMessage {
        port: 12,
        status: 14,
        data1: 120,
        data2: 53,
    };
    let color_arg = OscColor {
        red: 255u8,
        green: 192u8,
        blue: 42u8,
        alpha: 13u8,
    };
    let args = vec![OscType::Int(int_arg),
                    OscType::Float(float_arg),
                    OscType::String(string_arg.to_string()),
                    OscType::Blob(blob_arg.iter().cloned().collect()),
                    OscType::Time(time_arg.0, time_arg.1),
                    OscType::Long(long_arg),
                    OscType::Double(double_arg),
                    OscType::Char(char_arg),
                    OscType::Bool(false),
                    OscType::Bool(true),
                    OscType::Nil,
                    OscType::Inf,
                    OscType::Midi(OscMidiMessage {
                        port: midi_arg.port,
                        status: midi_arg.status,
                        data1: midi_arg.data1,
                        data2: midi_arg.data2,
                    })];
    let arg_cnt = args.len();

    let msg = OscMessage {
        addr: addr.to_string(),
        args: Some(args),
    };

    let enc_msg = encoder::encode_message(&msg).unwrap();
    let dec_msg: OscMessage = match decoder::decode(&enc_msg).unwrap() {
        OscPacket::Message(m) => m,
        _ => panic!("Expected OscMessage!"),
    };

    // check if osc address is equal
    assert_eq!(addr, dec_msg.addr);
    // check if there are arguments
    assert!(dec_msg.args.is_some());
    let dec_args = dec_msg.args.unwrap();

    // check if argument count is equal
    assert_eq!(arg_cnt, dec_args.len());

    for arg in dec_args {
        match arg {
            OscType::Int(x) => assert_eq!(int_arg, x),
            OscType::Long(x) => assert_eq!(long_arg, x),
            OscType::Float(x) => assert_eq!(float_arg, x),
            OscType::Double(x) => assert_eq!(double_arg, x),
            OscType::String(x) => assert_eq!(string_arg, x),
            OscType::Blob(x) => assert_eq!(blob_arg, x),
            OscType::Time(x, y) => assert_eq!(time_arg, (x, y)),
            OscType::Color(x) => {
                assert_eq!(color_arg.red, x.red);
                assert_eq!(color_arg.green, x.green);
                assert_eq!(color_arg.blue, x.blue);
                assert_eq!(color_arg.alpha, x.alpha);
            }
            OscType::Char(x) => assert_eq!(char_arg, x),
            OscType::Bool(_) => (),
            OscType::Inf => (),
            OscType::Nil => (),
            OscType::Midi(x) => {
                assert_eq!(midi_arg.port, x.port);
                assert_eq!(midi_arg.status, x.status);
                assert_eq!(midi_arg.data1, x.data1);
                assert_eq!(midi_arg.data2, x.data2);
            }
            _ => panic!("Unexpected OSC argument!"),
        }
    }
}
<commit_msg>Add checks for message length is multiple of 4 byte<commit_after>extern crate rosc;

use rosc::{encoder, decoder};
use rosc::types::{OscMessage, OscMidiMessage, OscColor, OscPacket, OscType};

#[test]
fn test_encode_message_wo_args() {
    let msg = OscMessage {
        addr: "/some/addr".to_string(),
        args: None,
    };

    let enc_msg = encoder::encode_message(&msg).unwrap();
    assert_eq!(enc_msg.len() % 4, 0);

    match decoder::decode(&enc_msg).unwrap() {
        OscPacket::Message(dec_msg) => assert_eq!(msg.addr, dec_msg.addr),
        _ => panic!("Expected OSC message!"),
    }
}

#[test]
fn test_encode_message_with_args() {
    let addr = "/another/address/1";
    let string_arg = "This is a string";
    let blob_arg = vec![1u8, 2u8, 3u8];
    let time_arg = (123, 456);
    let int_arg = 4;
    let float_arg = 3.14;
    let long_arg = 42;
    let double_arg = 3.1415;
    let char_arg = 'c';
    let midi_arg = OscMidiMessage {
        port: 12,
        status: 14,
        data1: 120,
        data2: 53,
    };
    let color_arg = OscColor {
        red: 255u8,
        green: 192u8,
        blue: 42u8,
        alpha: 13u8,
    };
    let args = vec![OscType::Int(int_arg),
                    OscType::Float(float_arg),
                    OscType::String(string_arg.to_string()),
                    OscType::Blob(blob_arg.iter().cloned().collect()),
                    OscType::Time(time_arg.0, time_arg.1),
                    OscType::Long(long_arg),
                    OscType::Double(double_arg),
                    OscType::Char(char_arg),
                    OscType::Bool(false),
                    OscType::Bool(true),
                    OscType::Nil,
                    OscType::Inf,
                    OscType::Midi(OscMidiMessage {
                        port: midi_arg.port,
                        status: midi_arg.status,
                        data1: midi_arg.data1,
                        data2: midi_arg.data2,
                    })];
    let arg_cnt = args.len();

    let msg = OscMessage {
        addr: addr.to_string(),
        args: Some(args),
    };

    let enc_msg = encoder::encode_message(&msg).unwrap();
    assert_eq!(enc_msg.len() % 4, 0);

    let dec_msg: OscMessage = match decoder::decode(&enc_msg).unwrap() {
        OscPacket::Message(m) => m,
        _ => panic!("Expected OscMessage!"),
    };

    // check if osc address is equal
    assert_eq!(addr, dec_msg.addr);
    // check if there are arguments
    assert!(dec_msg.args.is_some());
    let dec_args = dec_msg.args.unwrap();

    // check if argument count is equal
    assert_eq!(arg_cnt, dec_args.len());

    for arg in dec_args {
        match arg {
            OscType::Int(x) => assert_eq!(int_arg, x),
            OscType::Long(x) => assert_eq!(long_arg, x),
            OscType::Float(x) => assert_eq!(float_arg, x),
            OscType::Double(x) => assert_eq!(double_arg, x),
            OscType::String(x) => assert_eq!(string_arg, x),
            OscType::Blob(x) => assert_eq!(blob_arg, x),
            OscType::Time(x, y) => assert_eq!(time_arg, (x, y)),
            OscType::Color(x) => {
                assert_eq!(color_arg.red, x.red);
                assert_eq!(color_arg.green, x.green);
                assert_eq!(color_arg.blue, x.blue);
                assert_eq!(color_arg.alpha, x.alpha);
            }
            OscType::Char(x) => assert_eq!(char_arg, x),
            OscType::Bool(_) => (),
            OscType::Inf => (),
            OscType::Nil => (),
            OscType::Midi(x) => {
                assert_eq!(midi_arg.port, x.port);
                assert_eq!(midi_arg.status, x.status);
                assert_eq!(midi_arg.data1, x.data1);
                assert_eq!(midi_arg.data2, x.data2);
            }
            _ => panic!("Unexpected OSC argument!"),
        }
    }
}
<|endoftext|>


<commit_before>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use c_ares;
use futures;
use futures::Future;

use error::Error;
use host::HostResults;
use resolver::{
    Options,
    Resolver,
};

/// The type of future returned by methods on the `FutureResolver`.
pub type CAresFuture<T> = futures::BoxFuture<T, c_ares::Error>;

/// An asynchronous DNS resolver, which returns results as
/// `futures::Future`s.
pub struct FutureResolver {
    inner: Resolver,
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<FutureResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<FutureResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = FutureResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_a(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_a(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)  -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_cname(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_cname(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_mx(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_mx(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_naptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_naptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ns(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ns(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.query_soa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.search_soa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_srv(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_srv(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_txt(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_txt(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_address(address, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.query(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.search(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&mut self) {
        self.inner.cancel()
    }
}
<commit_msg>fix docs<commit_after>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use c_ares;
use futures;
use futures::Future;

use error::Error;
use host::HostResults;
use resolver::{
    Options,
    Resolver,
};

/// The type of future returned by methods on the `FutureResolver`.
pub type CAresFuture<T> = futures::BoxFuture<T, c_ares::Error>;

/// An asynchronous DNS resolver, which returns results as
/// `futures::Future`s.
pub struct FutureResolver {
    inner: Resolver,
}

impl FutureResolver {
    /// Create a new `FutureResolver`, using default `Options`.
    pub fn new() -> Result<FutureResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `FutureResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<FutureResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = FutureResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_a(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_a(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)  -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_aaaa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_cname(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> CAresFuture<c_ares::CNameResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_cname(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_mx(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_mx(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_naptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> CAresFuture<c_ares::NAPTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_naptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ns(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ns(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_ptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_ptr(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.query_soa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
        let (c, p) = futures::oneshot();
        self.inner.search_soa(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_srv(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_srv(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.query_txt(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
        let (c, p) = futures::oneshot();
        self.inner.search_txt(name, move |result| {
            let _ = c.send(result);
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_address(address, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> CAresFuture<HostResults> {
        let (c, p) = futures::oneshot();
        self.inner.get_host_by_name(name, family, move |result| {
            let _ = c.send(result.map(|h| h.into()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.query(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `search_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> CAresFuture<Vec<u8>> {
        let (c, p) = futures::oneshot();
        self.inner.search(name, dns_class, query_type, move |result| {
            let _ = c.send(result.map(|h| h.to_owned()));
        });
        p.map_err(|_| c_ares::Error::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    /// Cancel all requests made on this `FutureResolver`.
    pub fn cancel(&mut self) {
        self.inner.cancel()
    }
}
<|endoftext|>


<commit_before>// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity
// Gather all references from a mutable iterator and make sure Miri notices if
// using them is dangerous.
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
    // Gather all those references.
    let mut refs: Vec<&mut T> = iter.collect();
    // Use them all. Twice, to be sure we got all interleavings.
    for r in refs.iter_mut() {
        std::mem::swap(dummy, r);
    }
    for r in refs {
        std::mem::swap(dummy, r);
    }
}

fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);

    test_all_refs(&mut 13, v.iter_mut());
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    // `slice::Iter` (with `T: Copy`) specialization
    v.extend(&[1]);
    let _val = *v0;
    // `vec::IntoIter` specialization
    v.extend(vec![2]);
    let _val = *v0;
    // `TrustedLen` specialization
    v.extend(std::iter::once(3));
    let _val = *v0;
    // base case
    v.extend(std::iter::once(3).filter(|_| true));
    let _val = *v0;
}

fn vec_truncate_ptr_stable() {
    let mut v = vec![0; 10];
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.truncate(5);
    let _val = *v0;
}

fn push_str_ptr_stable() {
    let mut buf = String::with_capacity(11);
    buf.push_str("hello");
    let hello: &str = unsafe { &*(buf.as_str() as *const _) }; // laundering the lifetime -- we take care that `buf` does not reallocate, so that's okay.
    buf.push_str(" world");
    assert_eq!(format!("{}", hello), "hello");
}

fn sort() {
    let mut v = vec![1; 20];
    v.push(0);
    v.sort();
}

fn swap() {
    let mut v = vec![1, 2, 3, 4];
    v.swap(2, 2);
}

fn swap_remove() {
    let mut a = 0;
    let mut b = 1;
    let mut vec = vec![&mut a, &mut b];

    vec.swap_remove(1);
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    // liballoc has a more extensive test of this, but let's at least do a smoke test here.
    vec_push_ptr_stable();
    vec_extend_ptr_stable();
    vec_truncate_ptr_stable();
    push_str_ptr_stable();

    sort();
    swap();
    swap_remove();
}
<commit_msg>regression test for reverse() unsoundness<commit_after>// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity
// Gather all references from a mutable iterator and make sure Miri notices if
// using them is dangerous.
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
    // Gather all those references.
    let mut refs: Vec<&mut T> = iter.collect();
    // Use them all. Twice, to be sure we got all interleavings.
    for r in refs.iter_mut() {
        std::mem::swap(dummy, r);
    }
    for r in refs {
        std::mem::swap(dummy, r);
    }
}

fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);

    test_all_refs(&mut 13, v.iter_mut());
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    // `slice::Iter` (with `T: Copy`) specialization
    v.extend(&[1]);
    let _val = *v0;
    // `vec::IntoIter` specialization
    v.extend(vec![2]);
    let _val = *v0;
    // `TrustedLen` specialization
    v.extend(std::iter::once(3));
    let _val = *v0;
    // base case
    v.extend(std::iter::once(3).filter(|_| true));
    let _val = *v0;
}

fn vec_truncate_ptr_stable() {
    let mut v = vec![0; 10];
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.truncate(5);
    let _val = *v0;
}

fn push_str_ptr_stable() {
    let mut buf = String::with_capacity(11);
    buf.push_str("hello");
    let hello: &str = unsafe { &*(buf.as_str() as *const _) }; // laundering the lifetime -- we take care that `buf` does not reallocate, so that's okay.
    buf.push_str(" world");
    assert_eq!(format!("{}", hello), "hello");
}

fn sort() {
    let mut v = vec![1; 20];
    v.push(0);
    v.sort();
}

fn swap() {
    let mut v = vec![1, 2, 3, 4];
    v.swap(2, 2);
}

fn swap_remove() {
    let mut a = 0;
    let mut b = 1;
    let mut vec = vec![&mut a, &mut b];

    vec.swap_remove(1);
}

fn reverse() {
    #[repr(align(2))]
    #[derive(Debug)]
    struct Foo(u8);

    let mut v: Vec<_> = (0..50).map(Foo).collect();
    v.reverse();
    assert!(v[0].0 == 49);
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    // liballoc has a more extensive test of this, but let's at least do a smoke test here.
    vec_push_ptr_stable();
    vec_extend_ptr_stable();
    vec_truncate_ptr_stable();
    push_str_ptr_stable();

    sort();
    swap();
    swap_remove();
    reverse();
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::fmt;
use std::thread;
use std::time::{Duration, Instant};

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::pin::InputPin;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_request: ioctl::EventRequest,
}

impl Interrupt {
    fn new(cdev_fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd,
            event_request: ioctl::EventRequest::new(cdev_fd, pin, trigger)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_request.fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    fn event(&mut self) -> Result<ioctl::Event> {
        // This might block if there are no events waiting
        ioctl::get_event(self.event_request.fd)
    }

    fn reset(&mut self) -> Result<()> {
        // Close the old event fd before opening a new one
        self.event_request.close();
        self.event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;

        Ok(())
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll<'a>(
        &mut self,
        pins: &[&'a InputPin],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin, Level)>> {
        for pin in pins {
            let trigger_status = &mut self.trigger_status[pin.pin() as usize];

            // Did we cache any trigger events during the previous poll?
            if trigger_status.triggered {
                trigger_status.triggered = false;

                if !reset {
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = trigger_status.interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;

                let trigger_status = &mut self.trigger_status[pin];

                debug_assert!(
                    trigger_status.interrupt.is_some(),
                    format!("No interrupt set for pin {}", pin)
                );

                if let Some(ref mut interrupt) = trigger_status.interrupt {
                    trigger_status.level = match interrupt.event()?.trigger {
                        Trigger::RisingEdge => Level::High,
                        Trigger::FallingEdge => Level::Low,
                        _ => unsafe { std::hint::unreachable_unchecked() },
                    };

                    trigger_status.triggered = true;
                };
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                let trigger_status = &mut self.trigger_status[pin.pin() as usize];

                if trigger_status.triggered {
                    trigger_status.triggered = false;
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = trigger_status.interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        trigger_status.interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        if let Some(interrupt) = trigger_status.interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = match interrupt.event()?.trigger {
                                Trigger::RisingEdge => Level::High,
                                _ => Level::Low,
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Don't wait for the poll thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // poll thread is executing a callback that doesn't return.
        if !thread::panicking() {
            self.stop().ok();
        }
    }
}
<commit_msg>Discard stop() return value in drop()<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::fmt;
use std::thread;
use std::time::{Duration, Instant};

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::pin::InputPin;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_request: ioctl::EventRequest,
}

impl Interrupt {
    fn new(cdev_fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd,
            event_request: ioctl::EventRequest::new(cdev_fd, pin, trigger)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_request.fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    fn event(&mut self) -> Result<ioctl::Event> {
        // This might block if there are no events waiting
        ioctl::get_event(self.event_request.fd)
    }

    fn reset(&mut self) -> Result<()> {
        // Close the old event fd before opening a new one
        self.event_request.close();
        self.event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;

        Ok(())
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll<'a>(
        &mut self,
        pins: &[&'a InputPin],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(&'a InputPin, Level)>> {
        for pin in pins {
            let trigger_status = &mut self.trigger_status[pin.pin() as usize];

            // Did we cache any trigger events during the previous poll?
            if trigger_status.triggered {
                trigger_status.triggered = false;

                if !reset {
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = trigger_status.interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;

                let trigger_status = &mut self.trigger_status[pin];

                debug_assert!(
                    trigger_status.interrupt.is_some(),
                    format!("No interrupt set for pin {}", pin)
                );

                if let Some(ref mut interrupt) = trigger_status.interrupt {
                    trigger_status.level = match interrupt.event()?.trigger {
                        Trigger::RisingEdge => Level::High,
                        Trigger::FallingEdge => Level::Low,
                        _ => unsafe { std::hint::unreachable_unchecked() },
                    };

                    trigger_status.triggered = true;
                };
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                let trigger_status = &mut self.trigger_status[pin.pin() as usize];

                if trigger_status.triggered {
                    trigger_status.triggered = false;
                    return Ok(Some((pin, trigger_status.level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = trigger_status.interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        trigger_status.interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        let trigger_status = &mut self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        if let Some(interrupt) = trigger_status.interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = match interrupt.event()?.trigger {
                                Trigger::RisingEdge => Level::High,
                                _ => Level::Low,
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Don't wait for the poll thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // poll thread is executing a callback that doesn't return.
        if !thread::panicking() {
            let _ = self.stop();
        }
    }
}
<|endoftext|>


<commit_before>//! Simple integration tests oriented towards gravity computations

#![feature(core)]

extern crate acacia;
extern crate nalgebra;
extern crate quickcheck;

use std::cmp::partial_max;
use nalgebra::{ApproxEq, Pnt2, Pnt3, FloatPnt, Vec2, Vec3, zero, Norm, Orig};
use quickcheck::{TestResult, quickcheck};
use acacia::{Tree, Node, AssociatedData, DataQuery, Positioned};
use acacia::partition::Ncube;

#[test]
fn tree_center_of_mass() {
    fn tree_center_of_mass(data: Vec<(f64, (f64, f64))>) -> TestResult {
        // Only test non-empty lists with positive masses
        if data.is_empty() || data.iter().any(|&(m, _)| m <= 0.0) {
            return TestResult::discard();
        }
        // No two points should be in the same place
        for i in 0..data.len() {
            for j in 0..i {
                let (_, pi) = data[i];
                let (_, pj) = data[j];
                if pi == pj {
                    return TestResult::discard();
                }
            }
        }
        // Compute center of mass in the traditional way
        let (mps, ms) = data.iter()
            .map(|&(m, (x, y))| (Vec2::new(x, y) * m, m))
            .fold((zero::<Vec2<f64>>(), 0.0f64), |(mps, ms), (mp, m)| (mps + mp, ms + m));
        let com = mps / ms;
        // Now use the tree
        let tree = Tree::new(
            data.iter().map(|&(m, (x, y))|
                Positioned { object: m, position: Pnt2::new(x, y) }
            ),
            Ncube::new(Orig::orig(), 200.0f64),
            (zero(), 0.0),
            &|obj| (obj.position.to_vec() * obj.object, obj.object),
            &|&(mps, ms), &(mp, m)| (mps + mp, ms + m)
        );
        let (tree_mps, tree_ms) = *tree.data();
        // …and compare
        TestResult::from_bool(ApproxEq::approx_eq(&(tree_mps / tree_ms), &com))
    }
    quickcheck(tree_center_of_mass as fn(Vec<(f64, (f64, f64))>) -> TestResult);
}

#[test]
fn tree_gravity_approx() {
    fn tree_gravity_approx(
            starfield: Vec<(f64, (f64, f64, f64))>,
            test_point: (f64, f64, f64)
        ) -> TestResult
    {
        // We want to have at least one star
        if starfield.is_empty() {
            return TestResult::discard();
        }
        // Only test positive masses
        if starfield.iter().any(|&(m, _)| m <= 0.0) {
            return TestResult::discard();
        }
        // The test point should not be in the same place as any star
        if starfield.iter().any(|&(_, p)| p == test_point) {
            return TestResult::discard();
        }
        // No two stars should be in the same place
        for i in 0..starfield.len() {
            for j in 0..i {
                let (_, pi) = starfield[i];
                let (_, pj) = starfield[j];
                if pi == pj {
                    return TestResult::discard();
                }
            }
        }
        // (T, T, T) -> Pnt3<T>
        fn pnt<T>(p: (T, T, T)) -> Pnt3<T> {
            let (x, y, z) = p;
            Pnt3::new(x, y, z)
        }
        let test_point = pnt(test_point);
        // Newton's law of gravity for two point masses (with G = 1)
        let newton = |(m, p1): (f64, Pnt3<f64>), p2| {
            let diff: Vec3<f64> = p1 - p2;
            let r = diff.norm();
            diff * (m / r.powi(3))
        };
        // Calculate gravity exactly
        let simple_gravity = starfield.iter()
            .map(|&(m, p)| newton((m, pnt(p)), test_point))
            .fold(zero(), |a: Vec3<_>, b| a + b);
        // Calculate gravity using a tree
        let orig: Pnt3<f64> = Orig::orig();
        let tree = Tree::new(
            starfield.iter().map(|&(m, (x, y, z))|
                Positioned { object: m, position: Pnt3::new(x, y, z) }
            ),
            Ncube::new(orig, partial_max(test_point.as_vec().norm() * 2.0, 200.0).unwrap()),
            (orig, zero()),
            &|obj| (obj.position, obj.object),
            &|&(com1, m1), &(com2, m2)|
                if m1 + m2 > zero() {(
                    orig + (com1.to_vec() * m1 + com2.to_vec() * m2) / (m1 + m2),
                    m1 + m2,
                )}
                else {
                    (orig, zero())
                }
        );
        let theta = 0.5; // A bit arbitrary but this appears to work
        let tree_gravity =
            tree.query_data(|node| {
                let &(ref center_of_mass, _) = node.data();
                let d = FloatPnt::dist(&test_point, center_of_mass);
                let delta = FloatPnt::dist(&node.partition().center(), center_of_mass);
                d < node.partition().width() / theta + delta
            })
            .map(|&(com, m)| newton((m, com), test_point))
            .fold(zero::<Vec3<f64>>(), |a, b| a + b);

        // Now the tree gravity should approximate the exact one, within 10 %
        TestResult::from_bool(simple_gravity.approx_eq_eps(&tree_gravity, &(0.1 * simple_gravity.norm())))
    }
    quickcheck(tree_gravity_approx as fn(Vec<(f64, (f64, f64, f64))>, (f64, f64, f64)) -> TestResult)
}
<commit_msg>Use own implementation to find NCube size in the gravity test, as partial_max was deprecated.<commit_after>//! Simple integration tests oriented towards gravity computations

#![feature(core)]

extern crate acacia;
extern crate nalgebra;
extern crate quickcheck;

use nalgebra::{ApproxEq, Pnt2, Pnt3, FloatPnt, Vec2, Vec3, zero, Norm, Orig};
use quickcheck::{TestResult, quickcheck};
use acacia::{Tree, Node, AssociatedData, DataQuery, Positioned};
use acacia::partition::Ncube;

#[test]
fn tree_center_of_mass() {
    fn tree_center_of_mass(data: Vec<(f64, (f64, f64))>) -> TestResult {
        // Only test non-empty lists with positive masses
        if data.is_empty() || data.iter().any(|&(m, _)| m <= 0.0) {
            return TestResult::discard();
        }
        // No two points should be in the same place
        for i in 0..data.len() {
            for j in 0..i {
                let (_, pi) = data[i];
                let (_, pj) = data[j];
                if pi == pj {
                    return TestResult::discard();
                }
            }
        }
        // Compute center of mass in the traditional way
        let (mps, ms) = data.iter()
            .map(|&(m, (x, y))| (Vec2::new(x, y) * m, m))
            .fold((zero::<Vec2<f64>>(), 0.0f64), |(mps, ms), (mp, m)| (mps + mp, ms + m));
        let com = mps / ms;
        // Now use the tree
        let tree = Tree::new(
            data.iter().map(|&(m, (x, y))|
                Positioned { object: m, position: Pnt2::new(x, y) }
            ),
            Ncube::new(Orig::orig(), 200.0f64),
            (zero(), 0.0),
            &|obj| (obj.position.to_vec() * obj.object, obj.object),
            &|&(mps, ms), &(mp, m)| (mps + mp, ms + m)
        );
        let (tree_mps, tree_ms) = *tree.data();
        // …and compare
        TestResult::from_bool(ApproxEq::approx_eq(&(tree_mps / tree_ms), &com))
    }
    quickcheck(tree_center_of_mass as fn(Vec<(f64, (f64, f64))>) -> TestResult);
}

#[test]
fn tree_gravity_approx() {
    fn tree_gravity_approx(
            starfield: Vec<(f64, (f64, f64, f64))>,
            test_point: (f64, f64, f64)
        ) -> TestResult
    {
        // We want to have at least one star
        if starfield.is_empty() {
            return TestResult::discard();
        }
        // Only test positive masses
        if starfield.iter().any(|&(m, _)| m <= 0.0) {
            return TestResult::discard();
        }
        // The test point should not be in the same place as any star
        if starfield.iter().any(|&(_, p)| p == test_point) {
            return TestResult::discard();
        }
        // No two stars should be in the same place
        for i in 0..starfield.len() {
            for j in 0..i {
                let (_, pi) = starfield[i];
                let (_, pj) = starfield[j];
                if pi == pj {
                    return TestResult::discard();
                }
            }
        }
        // (T, T, T) -> Pnt3<T>
        fn pnt<T>(p: (T, T, T)) -> Pnt3<T> {
            let (x, y, z) = p;
            Pnt3::new(x, y, z)
        }
        let test_point = pnt(test_point);
        // Newton's law of gravity for two point masses (with G = 1)
        let newton = |(m, p1): (f64, Pnt3<f64>), p2| {
            let diff: Vec3<f64> = p1 - p2;
            let r = diff.norm();
            diff * (m / r.powi(3))
        };
        // Calculate gravity exactly
        let simple_gravity = starfield.iter()
            .map(|&(m, p)| newton((m, pnt(p)), test_point))
            .fold(zero(), |a: Vec3<_>, b| a + b);
        // Calculate gravity using a tree
        let orig: Pnt3<f64> = Orig::orig();
        let data_width = test_point.as_vec().norm() * 2.0;
        let width = if data_width < 200.0 { 200.0 } else { data_width };
        let tree = Tree::new(
            starfield.iter().map(|&(m, (x, y, z))|
                Positioned { object: m, position: Pnt3::new(x, y, z) }
            ),
            Ncube::new(orig, width),
            (orig, zero()),
            &|obj| (obj.position, obj.object),
            &|&(com1, m1), &(com2, m2)|
                if m1 + m2 > zero() {(
                    orig + (com1.to_vec() * m1 + com2.to_vec() * m2) / (m1 + m2),
                    m1 + m2,
                )}
                else {
                    (orig, zero())
                }
        );
        let theta = 0.5; // A bit arbitrary but this appears to work
        let tree_gravity =
            tree.query_data(|node| {
                let &(ref center_of_mass, _) = node.data();
                let d = FloatPnt::dist(&test_point, center_of_mass);
                let delta = FloatPnt::dist(&node.partition().center(), center_of_mass);
                d < node.partition().width() / theta + delta
            })
            .map(|&(com, m)| newton((m, com), test_point))
            .fold(zero::<Vec3<f64>>(), |a, b| a + b);

        // Now the tree gravity should approximate the exact one, within 10 %
        TestResult::from_bool(simple_gravity.approx_eq_eps(&tree_gravity, &(0.1 * simple_gravity.norm())))
    }
    quickcheck(tree_gravity_approx as fn(Vec<(f64, (f64, f64, f64))>, (f64, f64, f64)) -> TestResult)
}
<|endoftext|>


<commit_before>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod idt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("EXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("EXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("EXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             *stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame, error_code: u64) {
    let stack_frame = unsafe { &*stack_frame };
    use x86::controlregs;
    println!("EXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { controlregs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}
<commit_msg>Print an empty line before exception error messages<commit_after>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod idt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          *const ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

pub fn init() {
    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: *const ExceptionStackFrame) {
    let stack_frame = unsafe { &*stack_frame };
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             *stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: *const ExceptionStackFrame, error_code: u64) {
    let stack_frame = unsafe { &*stack_frame };
    use x86::controlregs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { controlregs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}
<|endoftext|>