<commit_before>//! Plugin (SIP003)
//!
//! ```plain
//! +------------+                    +---------------------------+
//! |  SS Client +-- Local Loopback --+  Plugin Client (Tunnel)   +--+
//! +------------+                    +---------------------------+  |
//!                                                                  |
//!             Public Internet (Obfuscated/Transformed traffic) ==> |
//!                                                                  |
//! +------------+                    +---------------------------+  |
//! |  SS Server +-- Local Loopback --+  Plugin Server (Tunnel)   +--+
//! +------------+                    +---------------------------+
//! ```

use std::{
    future::Future,
    io::{self, Error, ErrorKind},
    net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener},
    pin::Pin,
    task::{Context, Poll},
    time::Duration,
};

use futures::future;
use log::{debug, error, info, trace};
use tokio::{net::TcpStream, process::Child, time};

use crate::config::{Config, ServerAddr};

mod obfs_proxy;
mod ss_plugin;

/// Config for plugin
#[derive(Debug, Clone)]
pub struct PluginConfig {
    pub plugin: String,
    pub plugin_opt: Option<String>,
}

/// Mode of Plugin
#[derive(Debug, Clone, Copy)]
pub enum PluginMode {
    Server,
    Client,
}

/// Started plugins' subprocesses carrier
pub struct Plugins {
    plugins: Vec<Child>,
}

impl Drop for Plugins {
    #[cfg(not(unix))]
    fn drop(&mut self) {
        for plugin in &mut self.plugins {
            debug!("killing plugin process {}", plugin.id());
            let _ = plugin.kill();
        }
    }

    #[cfg(unix)]
    fn drop(&mut self) {
        use std::{collections::BTreeSet, time::Instant};

        let mut exited = BTreeSet::new();

        // Step.1 Send SIGTERM to let them exit gracefully
        for plugin in &self.plugins {
            debug!("terminating plugin process {}", plugin.id());

            unsafe {
                let ret = libc::kill(plugin.id() as libc::pid_t, libc::SIGTERM);
                if ret != 0 {
                    let err = io::Error::last_os_error();
                    error!("terminating plugin process {}, error: {}", plugin.id(), err);
                }
            }
        }

        // Step.2 Waits for gracefully exit
        for plugin in &self.plugins {
            const MAX_WAIT_DURATION: Duration = Duration::from_millis(10);

            let start = Instant::now();

            loop {
                unsafe {
                    let mut status: libc::c_int = 0;
                    let ret = libc::waitpid(plugin.id() as libc::pid_t, &mut status, libc::WNOHANG);
                    if ret < 0 {
                        let err = io::Error::last_os_error();
                        error!("waitpid({}) error: {}", plugin.id(), err);
                        break;
                    } else if ret > 0 {
                        // subprocess is finished
                        debug!("plugin process {} is terminated gracefully", plugin.id());
                        exited.insert(plugin.id());
                        break;
                    }
                }

                let elapsed = Instant::now() - start;
                if elapsed > MAX_WAIT_DURATION {
                    debug!(
                        "plugin process {} isn't terminated in {:?}",
                        plugin.id(),
                        MAX_WAIT_DURATION
                    );
                    break;
                }

                std::thread::yield_now();
            }
        }

        // Step.3 SIGKILL. Kill all of them forcibly
        for plugin in &mut self.plugins {
            if exited.contains(&plugin.id()) {
                continue;
            }

            if let Ok(..) = plugin.kill() {
                debug!("killed plugin process {}", plugin.id());
            }
        }
    }
}

impl Plugins {
    /// Launch plugins in configuration.
    ///
    /// Will modify servers' listen addresses to plugins' listen addresses.
    pub fn launch_plugins(config: &mut Config, mode: PluginMode) -> io::Result<Plugins> {
        let mut plugins = Vec::new();

        for svr in &mut config.server {
            let mut svr_addr_opt = None;

            if let Some(c) = svr.plugin() {
                let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
                let local_addr = SocketAddr::new(loop_ip, get_local_port()?);

                let svr_addr = match start_plugin(c, svr.addr(), &local_addr, mode) {
                    Err(err) => {
                        error!(
                            "failed to start plugin \"{}\" for server {}, err: {}",
                            c.plugin,
                            svr.addr(),
                            err
                        );
                        return Err(err);
                    }
                    Ok(process) => {
                        let svr_addr = ServerAddr::SocketAddr(local_addr);
                        plugins.push(process);

                        // Replace addr with plugin
                        svr_addr
                    }
                };

                match mode {
                    PluginMode::Client => info!("started plugin \"{}\" on {} <-> {}", c.plugin, local_addr, svr.addr()),
                    PluginMode::Server => info!("started plugin \"{}\" on {} <-> {}", c.plugin, svr.addr(), local_addr),
                }

                svr_addr_opt = Some(svr_addr); // Fuck borrow checker
            }

            if let Some(svr_addr) = svr_addr_opt {
                svr.set_plugin_addr(svr_addr);
            }
        }

        if plugins.is_empty() {
            panic!("didn't find any plugins to start");
        }

        Ok(Plugins { plugins })
    }

    /// Check plugin started
    ///
    /// This future won't resolve until all plugins are started
    pub async fn check_plugins_started(config: &Config) -> io::Result<()> {
        if !config.has_server_plugins() {
            return Ok(());
        }

        let mut v = Vec::new();

        for svr in &config.server {
            if let Some(ref saddr) = svr.plugin_addr() {
                let addr = match *saddr {
                    ServerAddr::SocketAddr(a) => a,
                    ServerAddr::DomainName(..) => unreachable!("impossible, plugin_addr shouldn't be domain name"),
                };

                v.push(async move {
                    // Try to connect plugin 10 times (nearly 2 seconds)
                    for r in 0..10 {
                        if let Ok(..) = TcpStream::connect(&addr).await {
                            debug!(
                                "plugin \"{}\" for {} listening on {} is started",
                                svr.plugin().as_ref().unwrap().plugin,
                                svr.addr(),
                                addr
                            );

                            return Ok(());
                        }

                        trace!(
                            "plugin \"{}\" for {} listening on {} isn't started yet, tried {} times",
                            svr.plugin().as_ref().unwrap().plugin,
                            svr.addr(),
                            addr,
                            r
                        );

                        time::delay_for(Duration::from_millis(200)).await;
                    }

                    let err = Error::new(ErrorKind::Other, format!("failed to connect plugin \"{}\"", addr));
                    Err(err)
                });
            }
        }

        future::try_join_all(v).await.map(|_| ())
    }
}

impl Future for Plugins {
    type Output = io::Result<()>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        for p in &mut self.plugins {
            match Pin::new(p).poll(cx) {
                Poll::Ready(Ok(exit_status)) => {
                    let msg = format!("plugin exited unexpectedly with {}", exit_status);
                    return Poll::Ready(Err(Error::new(io::ErrorKind::Other, msg)));
                }
                Poll::Ready(Err(err)) => {
                    error!("error while waiting for plugin subprocess: {}", err);
                    return Poll::Ready(Err(err));
                }
                Poll::Pending => {}
            }
        }
        Poll::Pending
    }
}

fn start_plugin(plugin: &PluginConfig, remote: &ServerAddr, local: &SocketAddr, mode: PluginMode) -> io::Result<Child> {
    let mut cmd = if plugin.plugin == "obfsproxy" {
        obfs_proxy::plugin_cmd(plugin, remote, local, mode)
    } else {
        ss_plugin::plugin_cmd(plugin, remote, local, mode)
    };
    cmd.spawn()
}

fn get_local_port() -> io::Result<u16> {
    let listener = TcpListener::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0))?;
    let addr = listener.local_addr()?;
    Ok(addr.port())
}

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

    #[test]
    fn generate_random_port() {
        let port = get_local_port().unwrap();
        println!("{:?}", port);
    }
}
<commit_msg>Prints plugin process ID in log<commit_after>//! Plugin (SIP003)
//!
//! ```plain
//! +------------+                    +---------------------------+
//! |  SS Client +-- Local Loopback --+  Plugin Client (Tunnel)   +--+
//! +------------+                    +---------------------------+  |
//!                                                                  |
//!             Public Internet (Obfuscated/Transformed traffic) ==> |
//!                                                                  |
//! +------------+                    +---------------------------+  |
//! |  SS Server +-- Local Loopback --+  Plugin Server (Tunnel)   +--+
//! +------------+                    +---------------------------+
//! ```

use std::{
    future::Future,
    io::{self, Error, ErrorKind},
    net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener},
    pin::Pin,
    task::{Context, Poll},
    time::Duration,
};

use futures::future;
use log::{debug, error, info, trace};
use tokio::{net::TcpStream, process::Child, time};

use crate::config::{Config, ServerAddr};

mod obfs_proxy;
mod ss_plugin;

/// Config for plugin
#[derive(Debug, Clone)]
pub struct PluginConfig {
    pub plugin: String,
    pub plugin_opt: Option<String>,
}

/// Mode of Plugin
#[derive(Debug, Clone, Copy)]
pub enum PluginMode {
    Server,
    Client,
}

/// Started plugins' subprocesses carrier
pub struct Plugins {
    plugins: Vec<Child>,
}

impl Drop for Plugins {
    #[cfg(not(unix))]
    fn drop(&mut self) {
        for plugin in &mut self.plugins {
            debug!("killing plugin process {}", plugin.id());
            let _ = plugin.kill();
        }
    }

    #[cfg(unix)]
    fn drop(&mut self) {
        use std::{collections::BTreeSet, time::Instant};

        let mut exited = BTreeSet::new();

        // Step.1 Send SIGTERM to let them exit gracefully
        for plugin in &self.plugins {
            debug!("terminating plugin process {}", plugin.id());

            unsafe {
                let ret = libc::kill(plugin.id() as libc::pid_t, libc::SIGTERM);
                if ret != 0 {
                    let err = io::Error::last_os_error();
                    error!("terminating plugin process {}, error: {}", plugin.id(), err);
                }
            }
        }

        // Step.2 Waits for gracefully exit
        for plugin in &self.plugins {
            const MAX_WAIT_DURATION: Duration = Duration::from_millis(10);

            let start = Instant::now();

            loop {
                unsafe {
                    let mut status: libc::c_int = 0;
                    let ret = libc::waitpid(plugin.id() as libc::pid_t, &mut status, libc::WNOHANG);
                    if ret < 0 {
                        let err = io::Error::last_os_error();
                        error!("waitpid({}) error: {}", plugin.id(), err);
                        break;
                    } else if ret > 0 {
                        // subprocess is finished
                        debug!("plugin process {} is terminated gracefully", plugin.id());
                        exited.insert(plugin.id());
                        break;
                    }
                }

                let elapsed = Instant::now() - start;
                if elapsed > MAX_WAIT_DURATION {
                    debug!(
                        "plugin process {} isn't terminated in {:?}",
                        plugin.id(),
                        MAX_WAIT_DURATION
                    );
                    break;
                }

                std::thread::yield_now();
            }
        }

        // Step.3 SIGKILL. Kill all of them forcibly
        for plugin in &mut self.plugins {
            if exited.contains(&plugin.id()) {
                continue;
            }

            if let Ok(..) = plugin.kill() {
                debug!("killed plugin process {}", plugin.id());
            }
        }
    }
}

impl Plugins {
    /// Launch plugins in configuration.
    ///
    /// Will modify servers' listen addresses to plugins' listen addresses.
    pub fn launch_plugins(config: &mut Config, mode: PluginMode) -> io::Result<Plugins> {
        let mut plugins = Vec::new();

        for svr in &mut config.server {
            let mut svr_addr_opt = None;

            if let Some(c) = svr.plugin() {
                let loop_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
                let local_addr = SocketAddr::new(loop_ip, get_local_port()?);

                match start_plugin(c, svr.addr(), &local_addr, mode) {
                    Err(err) => {
                        error!(
                            "failed to start plugin \"{}\" for server {}, err: {}",
                            c.plugin,
                            svr.addr(),
                            err
                        );
                        return Err(err);
                    }
                    Ok(process) => {
                        let svr_addr = ServerAddr::SocketAddr(local_addr);

                        match mode {
                            PluginMode::Client => {
                                info!(
                                    "started plugin \"{}\" on {} <-> {} ({})",
                                    c.plugin,
                                    local_addr,
                                    svr.addr(),
                                    process.id()
                                );
                            }
                            PluginMode::Server => {
                                info!(
                                    "started plugin \"{}\" on {} <-> {} ({})",
                                    c.plugin,
                                    svr.addr(),
                                    local_addr,
                                    process.id()
                                );
                            }
                        }

                        plugins.push(process);

                        // Replace addr with plugin, svr is borrowed immutable.
                        svr_addr_opt = Some(svr_addr);
                    }
                }
            }

            if let Some(svr_addr) = svr_addr_opt {
                svr.set_plugin_addr(svr_addr);
            }
        }

        if plugins.is_empty() {
            panic!("didn't find any plugins to start");
        }

        Ok(Plugins { plugins })
    }

    /// Check plugin started
    ///
    /// This future won't resolve until all plugins are started
    pub async fn check_plugins_started(config: &Config) -> io::Result<()> {
        if !config.has_server_plugins() {
            return Ok(());
        }

        let mut v = Vec::new();

        for svr in &config.server {
            if let Some(ref saddr) = svr.plugin_addr() {
                let addr = match *saddr {
                    ServerAddr::SocketAddr(a) => a,
                    ServerAddr::DomainName(..) => unreachable!("impossible, plugin_addr shouldn't be domain name"),
                };

                v.push(async move {
                    // Try to connect plugin 10 times (nearly 2 seconds)
                    for r in 0..10 {
                        if let Ok(..) = TcpStream::connect(&addr).await {
                            debug!(
                                "plugin \"{}\" for {} listening on {} is started",
                                svr.plugin().as_ref().unwrap().plugin,
                                svr.addr(),
                                addr
                            );

                            return Ok(());
                        }

                        trace!(
                            "plugin \"{}\" for {} listening on {} isn't started yet, tried {} times",
                            svr.plugin().as_ref().unwrap().plugin,
                            svr.addr(),
                            addr,
                            r
                        );

                        time::delay_for(Duration::from_millis(200)).await;
                    }

                    let err = Error::new(ErrorKind::Other, format!("failed to connect plugin \"{}\"", addr));
                    Err(err)
                });
            }
        }

        future::try_join_all(v).await.map(|_| ())
    }
}

impl Future for Plugins {
    type Output = io::Result<()>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        for p in &mut self.plugins {
            match Pin::new(p).poll(cx) {
                Poll::Ready(Ok(exit_status)) => {
                    let msg = format!("plugin exited unexpectedly with {}", exit_status);
                    return Poll::Ready(Err(Error::new(io::ErrorKind::Other, msg)));
                }
                Poll::Ready(Err(err)) => {
                    error!("error while waiting for plugin subprocess: {}", err);
                    return Poll::Ready(Err(err));
                }
                Poll::Pending => {}
            }
        }
        Poll::Pending
    }
}

fn start_plugin(plugin: &PluginConfig, remote: &ServerAddr, local: &SocketAddr, mode: PluginMode) -> io::Result<Child> {
    let mut cmd = if plugin.plugin == "obfsproxy" {
        obfs_proxy::plugin_cmd(plugin, remote, local, mode)
    } else {
        ss_plugin::plugin_cmd(plugin, remote, local, mode)
    };
    cmd.spawn()
}

fn get_local_port() -> io::Result<u16> {
    let listener = TcpListener::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0))?;
    let addr = listener.local_addr()?;
    Ok(addr.port())
}

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

    #[test]
    fn generate_random_port() {
        let port = get_local_port().unwrap();
        println!("{:?}", port);
    }
}
<|endoftext|>


<commit_before>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::select_solutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F> where F: MultiObjective, G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F> where F: MultiObjective, G: Send {
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }
}

impl<G, F> Individual<G, F> where F: MultiObjective, G: Send {
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            selected: false,
        }
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

    pub fn new() -> Self {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation {
            individuals: individuals,
        }
    }
}

impl<G, F> RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> RankedPopulation<G, F>
        where D: Domination<F>
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance
        select_solutions(&mut individuals,
                         population_size,
                         num_objectives,
                         domination);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        assert!(individuals.len() == population_size);

        RankedPopulation {
            individuals: individuals,
        }
    }

    pub fn new() -> Self {
        RatedPopulation {
            individuals: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /*
    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
    pub fn fitness_mut(&mut self) -> &mut [F] {
        &mut self.fitness
    }
    */
}

impl<G, F> RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    /// Generate an unrated offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<_> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    Individual::from_genome(mate(rng, &self.individuals[p1].genome, &self.individuals[p2].genome))
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation {
            individuals: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation {
            individuals: individuals,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

/*

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f64)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    */
}
<commit_msg>Add fitness() and fitness_mut() methods. But with index<commit_after>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::select_solutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F> where F: MultiObjective, G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F> where F: MultiObjective, G: Send {
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }
}

impl<G, F> Individual<G, F> where F: MultiObjective, G: Send {
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            selected: false,
        }
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

    pub fn new() -> Self {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation {
            individuals: individuals,
        }
    }
}

impl<G, F> RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> RankedPopulation<G, F>
        where D: Domination<F>
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance
        select_solutions(&mut individuals,
                         population_size,
                         num_objectives,
                         domination);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        assert!(individuals.len() == population_size);

        RankedPopulation {
            individuals: individuals,
        }
    }

    pub fn new() -> Self {
        RatedPopulation {
            individuals: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    pub fn fitness(&self, index: usize) -> &F {
        self.individuals[index].fitness.as_ref().unwrap()
    }

    pub fn fitness_mut(&mut self, index: usize) -> &mut F {
        self.individuals[index].fitness.as_mut().unwrap()
    }
}

impl<G, F> RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    /// Generate an unrated offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<_> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    Individual::from_genome(mate(rng, &self.individuals[p1].genome, &self.individuals[p2].genome))
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation {
            individuals: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation {
            individuals: individuals,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

/*

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f64)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    */
}
<|endoftext|>


<commit_before>use std::io;
use std::vec::Vec;

use byteorder::{ByteOrder, BigEndian};
use protobuf::{Message, MessageStatic};

use raft::errors::{Result, Error};

const MSG_HEADER_LEN: usize = 16;
const MSG_MAGIC: u16 = 0xdaf4;
const MSG_VERSION_V1: u16 = 1;

// Encodes message with message ID and protobuf body.
// Message contains header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Payload is a protobuf message.
pub fn encode_message<T: io::Write, M: Message>(w: &mut T, msg_id: u64, msg: &M) -> Result<()> {
    // Create a 16 bytes header and write it.
    let mut buf = vec!(0; MSG_HEADER_LEN);
    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    try!(msg.write_to_vec(&mut buf));

    // Set payload length here
    let payload_len = (buf.len() - MSG_HEADER_LEN) as u32;
    BigEndian::write_u32(&mut buf[4..8], payload_len);

    try!(w.write(&buf));

    Ok(())
}

// Decodes message with above encoded format, returns message ID.
pub fn decode_message<T: io::Read, M: Message>(r: &mut T, m: &mut M) -> Result<u64> {
    // First read 16 bytes header
    let mut header = [0; MSG_HEADER_LEN];
    // TODO: check exact read bytes number.
    try!(r.read(&mut header));

    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(Error::Other(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(Error::Other(format!("unsupported version {}, we need {} now",
                                        version,
                                        MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let msg_id: u64 = BigEndian::read_u64(&header[8..16]);
    let mut payload = vec![0;payload_len];

    let n = try!(r.read(&mut payload));
    try!(m.merge_from_bytes(&payload));

    Ok(msg_id)
}

#[cfg(test)]
mod tests {
    use bytes::{Buf, ByteBuf, MutByteBuf};

    use raft::codec::{encode_message, decode_message};
    use raft::raftpb::{Message, MessageType};
    use raft::errors::{Result, Error};

    #[test]
    fn test_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_message(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_message(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }
}
<commit_msg>raft: Address comment.<commit_after>use std::io;

use byteorder::{ByteOrder, BigEndian};
use protobuf::Message;

use raft::errors::{Result, Error};

const MSG_HEADER_LEN: usize = 16;
const MSG_MAGIC: u16 = 0xdaf4;
const MSG_VERSION_V1: u16 = 1;

// Encodes message with message ID and protobuf body.
// Message contains header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Payload is a protobuf message.
pub fn encode_message<T: io::Write, M: Message>(w: &mut T, msg_id: u64, msg: &M) -> Result<()> {
    // Create a 16 bytes header and write it.
    let mut buf = vec!(0; MSG_HEADER_LEN);
    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    try!(msg.write_to_vec(&mut buf));

    // Set payload length here
    let payload_len = (buf.len() - MSG_HEADER_LEN) as u32;
    BigEndian::write_u32(&mut buf[4..8], payload_len);

    try!(w.write(&buf));

    Ok(())
}

// Decodes message with above encoded format, returns message ID.
pub fn decode_message<T: io::Read, M: Message>(r: &mut T, m: &mut M) -> Result<u64> {
    // First read 16 bytes header
    let mut header = [0; MSG_HEADER_LEN];
    // TODO: check exact read bytes number.
    try!(r.read(&mut header));

    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(Error::Other(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(Error::Other(format!("unsupported version {}, we need {} now",
                                        version,
                                        MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let msg_id: u64 = BigEndian::read_u64(&header[8..16]);
    let mut payload = vec![0;payload_len];

    let n = try!(r.read(&mut payload));
    try!(m.merge_from_bytes(&payload));

    Ok(msg_id)
}

#[cfg(test)]
mod tests {
    use bytes::{Buf, ByteBuf, MutByteBuf};

    use raft::codec::{encode_message, decode_message};
    use raft::raftpb::{Message, MessageType};
    use raft::errors::{Result, Error};

    #[test]
    fn test_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_message(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_message(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use array::Array;
use dim4::Dim4;
use defines::{AfError, RandomEngineType};
use error::HANDLE_ERROR;
use self::libc::{uint8_t, c_int, c_uint, c_ulong};
use util::HasAfEnum;

type MutAfArray = *mut self::libc::c_longlong;
type AfArray    = self::libc::c_longlong;
type MutRandEngine = *mut self::libc::c_longlong;
type RandEngine    = self::libc::c_longlong;
type DimT    = self::libc::c_longlong;
type Intl    = self::libc::c_longlong;
type Uintl   = self::libc::c_ulonglong;

#[allow(dead_code)]
extern {
    fn af_set_seed(seed: Uintl) -> c_int;
    fn af_get_seed(seed: *mut Uintl) -> c_int;

    fn af_randu(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int;
    fn af_randn(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int;

    fn af_create_random_engine(engine: MutRandEngine, rtype: uint8_t, seed: Uintl) -> c_int;
    fn af_retain_random_engine(engine: MutRandEngine, inputEngine: RandEngine) -> c_int;
    fn af_random_engine_set_type(engine: MutRandEngine, rtpye: uint8_t) -> c_int;
    fn af_random_engine_get_type(rtype: *mut uint8_t, engine: RandEngine) -> c_int;
    fn af_random_engine_set_seed(engine: MutRandEngine, seed: Uintl) -> c_int;
    fn af_random_engine_get_seed(seed: *mut Uintl, engine: RandEngine) -> c_int;
    fn af_release_random_engine(engine: RandEngine) -> c_int;

    fn af_get_default_random_engine(engine: MutRandEngine) -> c_int;
    fn af_set_default_random_engine_type(rtype: uint8_t) -> c_int;

    fn af_random_uniform(out: MutAfArray, ndims: c_uint, dims: *const DimT,
                         aftype: uint8_t, engine: RandEngine) -> c_int;
    fn af_random_normal(out: MutAfArray, ndims: c_uint, dims: *const DimT,
                        aftype: uint8_t, engine: RandEngine) -> c_int;
}

/// Set seed for random number generation
pub fn set_seed(seed: u64) {
    unsafe {
        let err_val = af_set_seed(seed as Uintl);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the seed of random number generator
#[allow(unused_mut)]
pub fn get_seed() -> u64 {
    unsafe {
        let mut temp: u64 = 0;
        let err_val = af_get_seed(&mut temp as *mut Uintl);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

macro_rules! data_gen_def {
    ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => (
        #[doc=$doc_str]
        ///
        ///# Parameters
        ///
        /// - `dims` is the output dimensions
        ///
        ///# Return Values
        ///
        /// An Array with random values.
        #[allow(unused_mut)]
        pub fn $fn_name<T: HasAfEnum>(dims: Dim4) -> Array {
            unsafe {
                let aftype = T::get_af_dtype();
                let mut temp: i64 = 0;
                let err_val = $ffi_name(&mut temp as MutAfArray,
                                        dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                        aftype as uint8_t);
                HANDLE_ERROR(AfError::from(err_val));
                Array::from(temp)
            }
        }
    )
}

data_gen_def!("Create random numbers from uniform distribution", randu, af_randu);
data_gen_def!("Create random numbers from normal distribution", randn, af_randn);

/// Random number generator engine
///
/// This is a wrapper for ArrayFire's native random number generator engine.
pub struct RandomEngine {
    handle: i64,
}

/// Used for creating RandomEngine object from native resource id
impl From<i64> for RandomEngine {
    fn from(t: i64) -> RandomEngine {
        RandomEngine {handle: t}
    }
}

impl RandomEngine {
    /// Create a new random engine object
    ///
    /// # Parameters
    ///
    /// - `rengine` can be value of [RandomEngineType](./enum.RandomEngineType.html) enum.
    /// - `seed` is the initial seed value
    ///
    /// # Return Values
    ///
    /// A object of type RandomEngine
    pub fn new(rengine: RandomEngineType, seed: Option<u64>) -> RandomEngine {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_create_random_engine(&mut temp as MutRandEngine, rengine as uint8_t,
                                                  match seed {Some(s) => s, None => 0} as Uintl);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngine::from(temp)
        }
    }

    /// Get random engine type
    pub fn get_type(&self) -> RandomEngineType {
        unsafe {
            let mut temp: u8 = 0;
            let err_val = af_random_engine_get_type(&mut temp as *mut uint8_t,
                                                    self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngineType::from(temp as i32)
        }
    }

    /// Get random engine type
    pub fn set_type(&mut self, engine_type: RandomEngineType) {
        unsafe {
            let err_val = af_random_engine_set_type(&mut self.handle as MutRandEngine,
                                                    engine_type as uint8_t);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }

    /// Set seed for random engine
    pub fn set_seed(&mut self, seed: u64) {
        unsafe {
            let err_val = af_random_engine_set_seed(&mut self.handle as MutRandEngine,
                                                    seed as Uintl);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }

    /// Get seed of the random engine
    pub fn get_seed(&self) -> u64 {
        unsafe {
            let mut seed: u64 = 0;
            let err_val = af_random_engine_get_seed(&mut seed as *mut Uintl, self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            seed
        }
    }

    /// Returns the native FFI handle for Rust object `RandomEngine`
    pub fn get(&self) -> i64 {
        self.handle
    }
}

/// Increment reference count of RandomEngine's native resource
impl Clone for RandomEngine {
    fn clone(&self) -> RandomEngine {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_retain_random_engine(&mut temp as MutRandEngine, self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngine::from(temp)
        }
    }
}

/// Free RandomEngine's native resource
impl Drop for RandomEngine {
    fn drop(&mut self) {
        unsafe {
            let err_val = af_release_random_engine(self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }
}

/// Get default random engine
pub fn get_default_random_engine() -> RandomEngine {
    unsafe {
        let mut temp : i64 = 0;
        let mut err_val = af_get_default_random_engine(&mut temp as MutRandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        let mut handle : i64 = 0;
        err_val = af_retain_random_engine(&mut handle as MutRandEngine, temp as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        RandomEngine::from(handle)
    }
}

/// Set the random engine type for default random number generator
///
/// # Parameters
///
/// - `rtype` can take one of the values of enum [RandomEngineType](./enum.RandomEngineType.html)
pub fn set_default_random_engine_type(rtype: RandomEngineType) {
    unsafe {
        let err_val = af_set_default_random_engine_type(rtype as uint8_t);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Generate array of uniform numbers using a random engine
///
/// # Parameters
///
/// - `dims` is output array dimensions
/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html)
///
/// # Return Values
///
/// An Array with uniform numbers generated using random engine
pub fn random_uniform<T: HasAfEnum>(dims: Dim4, engine: RandomEngine) -> Array {
    unsafe {
        let aftype = T::get_af_dtype();
        let mut temp : i64 = 0;
        let err_val = af_random_uniform(&mut temp as MutAfArray,
                                        dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                        aftype as uint8_t, engine.get() as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Generate array of normal numbers using a random engine
///
/// # Parameters
///
/// - `dims` is output array dimensions
/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html)
///
/// # Return Values
///
/// An Array with normal numbers generated using random engine
pub fn random_normal<T: HasAfEnum>(dims: Dim4, engine: RandomEngine) -> Array {
    unsafe {
        let aftype = T::get_af_dtype();
        let mut temp : i64 = 0;
        let err_val = af_random_normal(&mut temp as MutAfArray,
                                       dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                       aftype as uint8_t, engine.get() as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}
<commit_msg>Removed unused imports in random module<commit_after>extern crate libc;

use array::Array;
use dim4::Dim4;
use defines::{AfError, RandomEngineType};
use error::HANDLE_ERROR;
use self::libc::{uint8_t, c_int, c_uint};
use util::HasAfEnum;

type MutAfArray = *mut self::libc::c_longlong;
type AfArray    = self::libc::c_longlong;
type MutRandEngine = *mut self::libc::c_longlong;
type RandEngine    = self::libc::c_longlong;
type DimT    = self::libc::c_longlong;
type Intl    = self::libc::c_longlong;
type Uintl   = self::libc::c_ulonglong;

#[allow(dead_code)]
extern {
    fn af_set_seed(seed: Uintl) -> c_int;
    fn af_get_seed(seed: *mut Uintl) -> c_int;

    fn af_randu(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int;
    fn af_randn(out: MutAfArray, ndims: c_uint, dims: *const DimT, afdtype: uint8_t) -> c_int;

    fn af_create_random_engine(engine: MutRandEngine, rtype: uint8_t, seed: Uintl) -> c_int;
    fn af_retain_random_engine(engine: MutRandEngine, inputEngine: RandEngine) -> c_int;
    fn af_random_engine_set_type(engine: MutRandEngine, rtpye: uint8_t) -> c_int;
    fn af_random_engine_get_type(rtype: *mut uint8_t, engine: RandEngine) -> c_int;
    fn af_random_engine_set_seed(engine: MutRandEngine, seed: Uintl) -> c_int;
    fn af_random_engine_get_seed(seed: *mut Uintl, engine: RandEngine) -> c_int;
    fn af_release_random_engine(engine: RandEngine) -> c_int;

    fn af_get_default_random_engine(engine: MutRandEngine) -> c_int;
    fn af_set_default_random_engine_type(rtype: uint8_t) -> c_int;

    fn af_random_uniform(out: MutAfArray, ndims: c_uint, dims: *const DimT,
                         aftype: uint8_t, engine: RandEngine) -> c_int;
    fn af_random_normal(out: MutAfArray, ndims: c_uint, dims: *const DimT,
                        aftype: uint8_t, engine: RandEngine) -> c_int;
}

/// Set seed for random number generation
pub fn set_seed(seed: u64) {
    unsafe {
        let err_val = af_set_seed(seed as Uintl);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the seed of random number generator
#[allow(unused_mut)]
pub fn get_seed() -> u64 {
    unsafe {
        let mut temp: u64 = 0;
        let err_val = af_get_seed(&mut temp as *mut Uintl);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

macro_rules! data_gen_def {
    ($doc_str: expr, $fn_name:ident, $ffi_name: ident) => (
        #[doc=$doc_str]
        ///
        ///# Parameters
        ///
        /// - `dims` is the output dimensions
        ///
        ///# Return Values
        ///
        /// An Array with random values.
        #[allow(unused_mut)]
        pub fn $fn_name<T: HasAfEnum>(dims: Dim4) -> Array {
            unsafe {
                let aftype = T::get_af_dtype();
                let mut temp: i64 = 0;
                let err_val = $ffi_name(&mut temp as MutAfArray,
                                        dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                        aftype as uint8_t);
                HANDLE_ERROR(AfError::from(err_val));
                Array::from(temp)
            }
        }
    )
}

data_gen_def!("Create random numbers from uniform distribution", randu, af_randu);
data_gen_def!("Create random numbers from normal distribution", randn, af_randn);

/// Random number generator engine
///
/// This is a wrapper for ArrayFire's native random number generator engine.
pub struct RandomEngine {
    handle: i64,
}

/// Used for creating RandomEngine object from native resource id
impl From<i64> for RandomEngine {
    fn from(t: i64) -> RandomEngine {
        RandomEngine {handle: t}
    }
}

impl RandomEngine {
    /// Create a new random engine object
    ///
    /// # Parameters
    ///
    /// - `rengine` can be value of [RandomEngineType](./enum.RandomEngineType.html) enum.
    /// - `seed` is the initial seed value
    ///
    /// # Return Values
    ///
    /// A object of type RandomEngine
    pub fn new(rengine: RandomEngineType, seed: Option<u64>) -> RandomEngine {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_create_random_engine(&mut temp as MutRandEngine, rengine as uint8_t,
                                                  match seed {Some(s) => s, None => 0} as Uintl);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngine::from(temp)
        }
    }

    /// Get random engine type
    pub fn get_type(&self) -> RandomEngineType {
        unsafe {
            let mut temp: u8 = 0;
            let err_val = af_random_engine_get_type(&mut temp as *mut uint8_t,
                                                    self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngineType::from(temp as i32)
        }
    }

    /// Get random engine type
    pub fn set_type(&mut self, engine_type: RandomEngineType) {
        unsafe {
            let err_val = af_random_engine_set_type(&mut self.handle as MutRandEngine,
                                                    engine_type as uint8_t);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }

    /// Set seed for random engine
    pub fn set_seed(&mut self, seed: u64) {
        unsafe {
            let err_val = af_random_engine_set_seed(&mut self.handle as MutRandEngine,
                                                    seed as Uintl);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }

    /// Get seed of the random engine
    pub fn get_seed(&self) -> u64 {
        unsafe {
            let mut seed: u64 = 0;
            let err_val = af_random_engine_get_seed(&mut seed as *mut Uintl, self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            seed
        }
    }

    /// Returns the native FFI handle for Rust object `RandomEngine`
    pub fn get(&self) -> i64 {
        self.handle
    }
}

/// Increment reference count of RandomEngine's native resource
impl Clone for RandomEngine {
    fn clone(&self) -> RandomEngine {
        unsafe {
            let mut temp: i64 = 0;
            let err_val = af_retain_random_engine(&mut temp as MutRandEngine, self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
            RandomEngine::from(temp)
        }
    }
}

/// Free RandomEngine's native resource
impl Drop for RandomEngine {
    fn drop(&mut self) {
        unsafe {
            let err_val = af_release_random_engine(self.handle as RandEngine);
            HANDLE_ERROR(AfError::from(err_val));
        }
    }
}

/// Get default random engine
pub fn get_default_random_engine() -> RandomEngine {
    unsafe {
        let mut temp : i64 = 0;
        let mut err_val = af_get_default_random_engine(&mut temp as MutRandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        let mut handle : i64 = 0;
        err_val = af_retain_random_engine(&mut handle as MutRandEngine, temp as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        RandomEngine::from(handle)
    }
}

/// Set the random engine type for default random number generator
///
/// # Parameters
///
/// - `rtype` can take one of the values of enum [RandomEngineType](./enum.RandomEngineType.html)
pub fn set_default_random_engine_type(rtype: RandomEngineType) {
    unsafe {
        let err_val = af_set_default_random_engine_type(rtype as uint8_t);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Generate array of uniform numbers using a random engine
///
/// # Parameters
///
/// - `dims` is output array dimensions
/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html)
///
/// # Return Values
///
/// An Array with uniform numbers generated using random engine
pub fn random_uniform<T: HasAfEnum>(dims: Dim4, engine: RandomEngine) -> Array {
    unsafe {
        let aftype = T::get_af_dtype();
        let mut temp : i64 = 0;
        let err_val = af_random_uniform(&mut temp as MutAfArray,
                                        dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                        aftype as uint8_t, engine.get() as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}

/// Generate array of normal numbers using a random engine
///
/// # Parameters
///
/// - `dims` is output array dimensions
/// - `engine` is an object of type [RandomEngine](./struct.RandomEngine.html)
///
/// # Return Values
///
/// An Array with normal numbers generated using random engine
pub fn random_normal<T: HasAfEnum>(dims: Dim4, engine: RandomEngine) -> Array {
    unsafe {
        let aftype = T::get_af_dtype();
        let mut temp : i64 = 0;
        let err_val = af_random_normal(&mut temp as MutAfArray,
                                       dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT,
                                       aftype as uint8_t, engine.get() as RandEngine);
        HANDLE_ERROR(AfError::from(err_val));
        Array::from(temp)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MTLClearColor {
    red: f64,
    green: f64,
    blue: f64,
    alpha: f64,
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        Self {
            red,
            green,
            blue,
            alpha,
        }
    }
}

#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
    Sample0 = 0,
    DepthResolvedSample = 1,
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe { msg_send![self, texture] }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe { msg_send![self, setTexture: texture] }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe { msg_send![self, level] }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe { msg_send![self, setLevel: level] }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe { msg_send![self, slice] }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe { msg_send![self, setSlice: slice] }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe { msg_send![self, depthPlane] }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe { msg_send![self, setDepthPlane: depth_plane] }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe { msg_send![self, resolveTexture] }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe { msg_send![self, setResolveTexture: resolve_texture] }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveLevel] }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe { msg_send![self, setResolveLevel: resolve_level] }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveSlice] }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe { msg_send![self, setResolveSlice: resolve_slice] }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveDepthPlane] }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe { msg_send![self, setResolveDepthPlane: resolve_depth_plane] }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe { msg_send![self, loadAction] }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe { msg_send![self, setLoadAction: load_action] }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe { msg_send![self, storeAction] }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe { msg_send![self, setStoreAction: store_action] }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe { msg_send![self, clearColor] }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe { msg_send![self, setClearColor: clear_color] }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe { msg_send![self, clearDepth] }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe { msg_send![self, setClearDepth: clear_depth] }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe { msg_send![self, clearStencil] }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe { msg_send![self, setClearStencil: clear_stencil] }
    }

    pub fn stencil_resolve_filter(&self) -> MTLMultisampleStencilResolveFilter {
        unsafe { msg_send![self, stencilResolveFilter] }
    }

    pub fn set_stencil_resolve_filter(
        &self,
        stencil_resolve_filter: MTLMultisampleStencilResolveFilter,
    ) {
        unsafe { msg_send![self, setStencilResolveFilter: stencil_resolve_filter] }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: NSUInteger) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe { msg_send![self, objectAtIndexedSubscript: index] }
    }

    pub fn set_object_at(
        &self,
        index: NSUInteger,
        attachment: Option<&RenderPassColorAttachmentDescriptorRef>,
    ) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe { msg_send![self, colorAttachments] }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe { msg_send![self, depthAttachment] }
    }

    pub fn set_depth_attachment(
        &self,
        depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>,
    ) {
        unsafe { msg_send![self, setDepthAttachment: depth_attachment] }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe { msg_send![self, stencilAttachment] }
    }

    pub fn set_stencil_attachment(
        &self,
        stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>,
    ) {
        unsafe { msg_send![self, setStencilAttachment: stencil_attachment] }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe { msg_send![self, visibilityResultBuffer] }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe { msg_send![self, setVisibilityResultBuffer: buffer] }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetArrayLength] }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetArrayLength: length] }
    }

    pub fn render_target_width(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetWidth] }
    }

    pub fn set_render_target_width(&self, size: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetWidth: size] }
    }

    pub fn render_target_height(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetHeight] }
    }

    pub fn set_render_target_height(&self, size: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetHeight: size] }
    }

    pub fn default_raster_sample_count(&self) -> NSUInteger {
        unsafe { msg_send![self, defaultRasterSampleCount] }
    }

    pub fn set_default_raster_sample_count(&self, count: NSUInteger) {
        unsafe { msg_send![self, setDefaultRasterSampleCount: count] }
    }
}
<commit_msg>make fields of MTLClearColor pub<commit_after>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MTLClearColor {
    pub red: f64,
    pub green: f64,
    pub blue: f64,
    pub alpha: f64,
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        Self {
            red,
            green,
            blue,
            alpha,
        }
    }
}

#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
    Sample0 = 0,
    DepthResolvedSample = 1,
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe { msg_send![self, texture] }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe { msg_send![self, setTexture: texture] }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe { msg_send![self, level] }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe { msg_send![self, setLevel: level] }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe { msg_send![self, slice] }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe { msg_send![self, setSlice: slice] }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe { msg_send![self, depthPlane] }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe { msg_send![self, setDepthPlane: depth_plane] }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe { msg_send![self, resolveTexture] }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe { msg_send![self, setResolveTexture: resolve_texture] }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveLevel] }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe { msg_send![self, setResolveLevel: resolve_level] }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveSlice] }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe { msg_send![self, setResolveSlice: resolve_slice] }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe { msg_send![self, resolveDepthPlane] }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe { msg_send![self, setResolveDepthPlane: resolve_depth_plane] }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe { msg_send![self, loadAction] }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe { msg_send![self, setLoadAction: load_action] }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe { msg_send![self, storeAction] }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe { msg_send![self, setStoreAction: store_action] }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe { msg_send![self, clearColor] }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe { msg_send![self, setClearColor: clear_color] }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe { msg_send![self, clearDepth] }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe { msg_send![self, setClearDepth: clear_depth] }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe { msg_send![self, clearStencil] }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe { msg_send![self, setClearStencil: clear_stencil] }
    }

    pub fn stencil_resolve_filter(&self) -> MTLMultisampleStencilResolveFilter {
        unsafe { msg_send![self, stencilResolveFilter] }
    }

    pub fn set_stencil_resolve_filter(
        &self,
        stencil_resolve_filter: MTLMultisampleStencilResolveFilter,
    ) {
        unsafe { msg_send![self, setStencilResolveFilter: stencil_resolve_filter] }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: NSUInteger) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe { msg_send![self, objectAtIndexedSubscript: index] }
    }

    pub fn set_object_at(
        &self,
        index: NSUInteger,
        attachment: Option<&RenderPassColorAttachmentDescriptorRef>,
    ) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe { msg_send![self, colorAttachments] }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe { msg_send![self, depthAttachment] }
    }

    pub fn set_depth_attachment(
        &self,
        depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>,
    ) {
        unsafe { msg_send![self, setDepthAttachment: depth_attachment] }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe { msg_send![self, stencilAttachment] }
    }

    pub fn set_stencil_attachment(
        &self,
        stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>,
    ) {
        unsafe { msg_send![self, setStencilAttachment: stencil_attachment] }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe { msg_send![self, visibilityResultBuffer] }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe { msg_send![self, setVisibilityResultBuffer: buffer] }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetArrayLength] }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetArrayLength: length] }
    }

    pub fn render_target_width(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetWidth] }
    }

    pub fn set_render_target_width(&self, size: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetWidth: size] }
    }

    pub fn render_target_height(&self) -> NSUInteger {
        unsafe { msg_send![self, renderTargetHeight] }
    }

    pub fn set_render_target_height(&self, size: NSUInteger) {
        unsafe { msg_send![self, setRenderTargetHeight: size] }
    }

    pub fn default_raster_sample_count(&self) -> NSUInteger {
        unsafe { msg_send![self, defaultRasterSampleCount] }
    }

    pub fn set_default_raster_sample_count(&self, count: NSUInteger) {
        unsafe { msg_send![self, setDefaultRasterSampleCount: count] }
    }
}
<|endoftext|>