<commit_before>// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
//
// 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 std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};

use futures::stream::{Fuse, Peekable, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver};
use futures::task;
use futures::{Async, Future, Poll};
use rand;
use rand::distributions::{Distribution, Range};
use tokio_udp;

use xfer::{BufStreamHandle, SerialMessage};

/// A UDP stream of DNS binary packets
#[must_use = "futures do nothing unless polled"]
pub struct UdpStream {
    // FIXME: change UdpStream to always select a new Socket for every request
    socket: tokio_udp::UdpSocket,
    outbound_messages: Peekable<Fuse<UnboundedReceiver<SerialMessage>>>,
}

impl UdpStream {
    /// This method is intended for client connections, see `with_bound` for a method better for
    ///  straight listening. It is expected that the resolver wrapper will be responsible for
    ///  creating and managing new UdpStreams such that each new client would have a random port
    ///  (reduce chance of cache poisoning). This will return a randomly assigned local port.
    ///
    /// # Arguments
    ///
    /// * `name_server` - socket address for the remote server (used to determine IPv4 or IPv6)
    ///
    /// # Return
    ///
    /// a tuple of a Future Stream which will handle sending and receiving messsages, and a
    ///  handle which can be used to send messages into the stream.
    pub fn new(
        name_server: SocketAddr,
    ) -> (
        Box<Future<Item = UdpStream, Error = io::Error> + Send>,
        BufStreamHandle,
    ) {
        let (message_sender, outbound_messages) = unbounded();
        let message_sender = BufStreamHandle::new(message_sender);

        // TODO: allow the bind address to be specified...
        // constructs a future for getting the next randomly bound port to a UdpSocket
        let next_socket = Self::next_bound_local_address(&name_server);

        // This set of futures collapses the next udp socket into a stream which can be used for
        //  sending and receiving udp packets.
        let stream = Box::new(next_socket.map(move |socket| UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        }));

        (stream, message_sender)
    }

    /// Initialize the Stream with an already bound socket. Generally this should be only used for
    ///  server listening sockets. See `new` for a client oriented socket. Specifically, this there
    ///  is already a bound socket in this context, whereas `new` makes sure to randomize ports
    ///  for additional cache poison prevention.
    ///
    /// # Arguments
    ///
    /// * `socket` - an already bound UDP socket
    ///
    /// # Return
    ///
    /// a tuple of a Future Stream which will handle sending and receiving messsages, and a
    ///  handle which can be used to send messages into the stream.
    pub fn with_bound(socket: tokio_udp::UdpSocket) -> (Self, BufStreamHandle) {
        let (message_sender, outbound_messages) = unbounded();
        let message_sender = BufStreamHandle::new(message_sender);

        let stream = UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        };

        (stream, message_sender)
    }

    #[allow(unused)]
    pub(crate) fn from_parts(
        socket: tokio_udp::UdpSocket,
        outbound_messages: UnboundedReceiver<SerialMessage>,
    ) -> Self {
        UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        }
    }

    /// Creates a future for randomly binding to a local socket address for client connections.
    fn next_bound_local_address(name_server: &SocketAddr) -> NextRandomUdpSocket {
        let zero_addr: IpAddr = match *name_server {
            SocketAddr::V4(..) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
            SocketAddr::V6(..) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
        };

        NextRandomUdpSocket {
            bind_address: zero_addr,
        }
    }
}

impl Stream for UdpStream {
    type Item = SerialMessage;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // this will not accept incoming data while there is data to send
        //  makes this self throttling.
        loop {
            // first try to send
            if let Async::Ready(Some(ref message)) = self
                .outbound_messages
                .peek()
                .map_err(|()| io::Error::new(io::ErrorKind::Other, "unknown"))?
            {
                // will return if the socket will block
                try_ready!(self.socket.poll_send_to(message.bytes(), &message.addr()));
            }

            // now pop the request and check if we should break or continue.
            match self
                .outbound_messages
                .poll()
                .map_err(|()| io::Error::new(io::ErrorKind::Other, "unknown"))?
            {
                // already handled above, here to make sure the poll() pops the next message
                Async::Ready(Some(_)) => (),
                // now we get to drop through to the receives...
                // TODO: should we also return None if there are no more messages to send?
                Async::NotReady | Async::Ready(None) => break,
            }
        }

        // For QoS, this will only accept one message and output that
        // recieve all inbound messages

        // TODO: this should match edns settings
        let mut buf = [0u8; 2048];

        // TODO: should we drop this packet if it's not from the same src as dest?
        let (len, src) = try_ready!(self.socket.poll_recv_from(&mut buf));
        Ok(Async::Ready(Some(SerialMessage::new(
            buf.iter().take(len).cloned().collect(),
            src,
        ))))
    }
}

#[must_use = "futures do nothing unless polled"]
struct NextRandomUdpSocket {
    bind_address: IpAddr,
}

impl Future for NextRandomUdpSocket {
    type Item = tokio_udp::UdpSocket;
    type Error = io::Error;

    /// polls until there is an available next random UDP port.
    ///
    /// if there is no port available after 10 attempts, returns NotReady
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let between = Range::new(1025_u32, u32::from(u16::max_value()) + 1);
        let mut rand = rand::thread_rng();

        for attempt in 0..10 {
            let port = between.sample(&mut rand) as u16; // the range is [0 ... u16::max] aka [0 .. u16::max + 1)
            let zero_addr = SocketAddr::new(self.bind_address, port);

            // TODO: allow TTL to be adjusted...
            match tokio_udp::UdpSocket::bind(&zero_addr) {
                Ok(socket) => return Ok(Async::Ready(socket)),
                Err(err) => debug!("unable to bind port, attempt: {}: {}", attempt, err),
            }
        }

        warn!("could not get next random port, delaying");

        task::current().notify();
        // returning NotReady here, perhaps the next poll there will be some more socket available.
        Ok(Async::NotReady)
    }
}

#[test]
fn test_next_random_socket() {
    use tokio::runtime::current_thread::Runtime;

    let mut io_loop = Runtime::new().unwrap();
    let (stream, _) = UdpStream::new(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 52));
    drop(
        io_loop
            .block_on(stream)
            .ok()
            .expect("failed to get next socket address"),
    );
}

#[test]
fn test_udp_stream_ipv4() {
    udp_stream_test(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
}

#[test]
#[cfg(not(target_os = "linux"))] // ignored until Travis-CI fixes IPv6
fn test_udp_stream_ipv6() {
    udp_stream_test(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))
}

#[cfg(test)]
fn udp_stream_test(server_addr: IpAddr) {
    use tokio::runtime::current_thread::Runtime;

    use std;
    use std::net::ToSocketAddrs;
    let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
    let succeeded_clone = succeeded.clone();
    std::thread::Builder::new()
        .name("thread_killer".to_string())
        .spawn(move || {
            let succeeded = succeeded_clone.clone();
            for _ in 0..15 {
                std::thread::sleep(std::time::Duration::from_secs(1));
                if succeeded.load(std::sync::atomic::Ordering::Relaxed) {
                    return;
                }
            }

            panic!("timeout");
        })
        .unwrap();

    let server = std::net::UdpSocket::bind(SocketAddr::new(server_addr, 0)).unwrap();
    server
        .set_read_timeout(Some(std::time::Duration::from_secs(5)))
        .unwrap(); // should recieve something within 5 seconds...
    server
        .set_write_timeout(Some(std::time::Duration::from_secs(5)))
        .unwrap(); // should recieve something within 5 seconds...
    let server_addr = server.local_addr().unwrap();

    let test_bytes: &'static [u8; 8] = b"DEADBEEF";
    let send_recv_times = 4;

    // an in and out server
    let server_handle = std::thread::Builder::new()
        .name("test_udp_stream_ipv4:server".to_string())
        .spawn(move || {
            let mut buffer = [0_u8; 512];

            for _ in 0..send_recv_times {
                // wait for some bytes...
                let (len, addr) = server.recv_from(&mut buffer).expect("receive failed");

                assert_eq!(&buffer[0..len], test_bytes);

                // bounce them right back...
                assert_eq!(
                    server.send_to(&buffer[0..len], addr).expect("send failed"),
                    len
                );
            }
        })
        .unwrap();

    // setup the client, which is going to run on the testing thread...
    let mut io_loop = Runtime::new().unwrap();

    // the tests should run within 5 seconds... right?
    // TODO: add timeout here, so that test never hangs...
    let client_addr = match server_addr {
        std::net::SocketAddr::V4(_) => "127.0.0.1:0",
        std::net::SocketAddr::V6(_) => "[::1]:0",
    };

    let socket = tokio_udp::UdpSocket::bind(
        &client_addr.to_socket_addrs().unwrap().next().unwrap(),
    ).expect("could not create socket"); // some random address...
    let (mut stream, sender) = UdpStream::with_bound(socket);
    //let mut stream: UdpStream = io_loop.block_on(stream).ok().unwrap();

    for _ in 0..send_recv_times {
        // test once
        sender
            .unbounded_send(SerialMessage::new(test_bytes.to_vec(), server_addr))
            .unwrap();
        let (buffer_and_addr, stream_tmp) = io_loop.block_on(stream.into_future()).ok().unwrap();
        stream = stream_tmp;
        let message = buffer_and_addr.expect("no buffer received");
        assert_eq!(message.bytes(), test_bytes);
        assert_eq!(message.addr(), server_addr);
    }

    succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
    server_handle.join().expect("server thread failed");
}
<commit_msg>Fix the loss of UDP packets to be sent at high load condition.<commit_after>// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
//
// 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 std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};

use futures::stream::{Fuse, Peekable, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver};
use futures::task;
use futures::{Async, Future, Poll};
use rand;
use rand::distributions::{Distribution, Range};
use tokio_udp;

use xfer::{BufStreamHandle, SerialMessage};

/// A UDP stream of DNS binary packets
#[must_use = "futures do nothing unless polled"]
pub struct UdpStream {
    // FIXME: change UdpStream to always select a new Socket for every request
    socket: tokio_udp::UdpSocket,
    outbound_messages: Peekable<Fuse<UnboundedReceiver<SerialMessage>>>,
}

impl UdpStream {
    /// This method is intended for client connections, see `with_bound` for a method better for
    ///  straight listening. It is expected that the resolver wrapper will be responsible for
    ///  creating and managing new UdpStreams such that each new client would have a random port
    ///  (reduce chance of cache poisoning). This will return a randomly assigned local port.
    ///
    /// # Arguments
    ///
    /// * `name_server` - socket address for the remote server (used to determine IPv4 or IPv6)
    ///
    /// # Return
    ///
    /// a tuple of a Future Stream which will handle sending and receiving messsages, and a
    ///  handle which can be used to send messages into the stream.
    pub fn new(
        name_server: SocketAddr,
    ) -> (
        Box<Future<Item = UdpStream, Error = io::Error> + Send>,
        BufStreamHandle,
    ) {
        let (message_sender, outbound_messages) = unbounded();
        let message_sender = BufStreamHandle::new(message_sender);

        // TODO: allow the bind address to be specified...
        // constructs a future for getting the next randomly bound port to a UdpSocket
        let next_socket = Self::next_bound_local_address(&name_server);

        // This set of futures collapses the next udp socket into a stream which can be used for
        //  sending and receiving udp packets.
        let stream = Box::new(next_socket.map(move |socket| UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        }));

        (stream, message_sender)
    }

    /// Initialize the Stream with an already bound socket. Generally this should be only used for
    ///  server listening sockets. See `new` for a client oriented socket. Specifically, this there
    ///  is already a bound socket in this context, whereas `new` makes sure to randomize ports
    ///  for additional cache poison prevention.
    ///
    /// # Arguments
    ///
    /// * `socket` - an already bound UDP socket
    ///
    /// # Return
    ///
    /// a tuple of a Future Stream which will handle sending and receiving messsages, and a
    ///  handle which can be used to send messages into the stream.
    pub fn with_bound(socket: tokio_udp::UdpSocket) -> (Self, BufStreamHandle) {
        let (message_sender, outbound_messages) = unbounded();
        let message_sender = BufStreamHandle::new(message_sender);

        let stream = UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        };

        (stream, message_sender)
    }

    #[allow(unused)]
    pub(crate) fn from_parts(
        socket: tokio_udp::UdpSocket,
        outbound_messages: UnboundedReceiver<SerialMessage>,
    ) -> Self {
        UdpStream {
            socket: socket,
            outbound_messages: outbound_messages.fuse().peekable(),
        }
    }

    /// Creates a future for randomly binding to a local socket address for client connections.
    fn next_bound_local_address(name_server: &SocketAddr) -> NextRandomUdpSocket {
        let zero_addr: IpAddr = match *name_server {
            SocketAddr::V4(..) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
            SocketAddr::V6(..) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
        };

        NextRandomUdpSocket {
            bind_address: zero_addr,
        }
    }
}

impl Stream for UdpStream {
    type Item = SerialMessage;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // this will not accept incoming data while there is data to send
        //  makes this self throttling.
        loop {
            // first try to send
            match self
                .outbound_messages
                .peek()
                .map_err(|()| io::Error::new(io::ErrorKind::Other, "unknown"))?
            {
                Async::Ready(Some(ref message)) => {
                    // will return if the socket will block
                    try_ready!(self.socket.poll_send_to(message.bytes(), &message.addr()));},
                // now we get to drop through to the receives...
                // TODO: should we also return None if there are no more messages to send?
                Async::NotReady | Async::Ready(None) => break,
            }

            // now pop the request which is already sent
            // If it were an Err, it was returned on peeking.
            self.outbound_messages.poll().expect("Impossible");
        }

        // For QoS, this will only accept one message and output that
        // recieve all inbound messages

        // TODO: this should match edns settings
        let mut buf = [0u8; 2048];

        // TODO: should we drop this packet if it's not from the same src as dest?
        let (len, src) = try_ready!(self.socket.poll_recv_from(&mut buf));
        Ok(Async::Ready(Some(SerialMessage::new(
            buf.iter().take(len).cloned().collect(),
            src,
        ))))
    }
}

#[must_use = "futures do nothing unless polled"]
struct NextRandomUdpSocket {
    bind_address: IpAddr,
}

impl Future for NextRandomUdpSocket {
    type Item = tokio_udp::UdpSocket;
    type Error = io::Error;

    /// polls until there is an available next random UDP port.
    ///
    /// if there is no port available after 10 attempts, returns NotReady
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let between = Range::new(1025_u32, u32::from(u16::max_value()) + 1);
        let mut rand = rand::thread_rng();

        for attempt in 0..10 {
            let port = between.sample(&mut rand) as u16; // the range is [0 ... u16::max] aka [0 .. u16::max + 1)
            let zero_addr = SocketAddr::new(self.bind_address, port);

            // TODO: allow TTL to be adjusted...
            match tokio_udp::UdpSocket::bind(&zero_addr) {
                Ok(socket) => return Ok(Async::Ready(socket)),
                Err(err) => debug!("unable to bind port, attempt: {}: {}", attempt, err),
            }
        }

        warn!("could not get next random port, delaying");

        task::current().notify();
        // returning NotReady here, perhaps the next poll there will be some more socket available.
        Ok(Async::NotReady)
    }
}

#[test]
fn test_next_random_socket() {
    use tokio::runtime::current_thread::Runtime;

    let mut io_loop = Runtime::new().unwrap();
    let (stream, _) = UdpStream::new(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 52));
    drop(
        io_loop
            .block_on(stream)
            .ok()
            .expect("failed to get next socket address"),
    );
}

#[test]
fn test_udp_stream_ipv4() {
    udp_stream_test(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
}

#[test]
#[cfg(not(target_os = "linux"))] // ignored until Travis-CI fixes IPv6
fn test_udp_stream_ipv6() {
    udp_stream_test(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))
}

#[cfg(test)]
fn udp_stream_test(server_addr: IpAddr) {
    use tokio::runtime::current_thread::Runtime;

    use std;
    use std::net::ToSocketAddrs;
    let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
    let succeeded_clone = succeeded.clone();
    std::thread::Builder::new()
        .name("thread_killer".to_string())
        .spawn(move || {
            let succeeded = succeeded_clone.clone();
            for _ in 0..15 {
                std::thread::sleep(std::time::Duration::from_secs(1));
                if succeeded.load(std::sync::atomic::Ordering::Relaxed) {
                    return;
                }
            }

            panic!("timeout");
        })
        .unwrap();

    let server = std::net::UdpSocket::bind(SocketAddr::new(server_addr, 0)).unwrap();
    server
        .set_read_timeout(Some(std::time::Duration::from_secs(5)))
        .unwrap(); // should recieve something within 5 seconds...
    server
        .set_write_timeout(Some(std::time::Duration::from_secs(5)))
        .unwrap(); // should recieve something within 5 seconds...
    let server_addr = server.local_addr().unwrap();

    let test_bytes: &'static [u8; 8] = b"DEADBEEF";
    let send_recv_times = 4;

    // an in and out server
    let server_handle = std::thread::Builder::new()
        .name("test_udp_stream_ipv4:server".to_string())
        .spawn(move || {
            let mut buffer = [0_u8; 512];

            for _ in 0..send_recv_times {
                // wait for some bytes...
                let (len, addr) = server.recv_from(&mut buffer).expect("receive failed");

                assert_eq!(&buffer[0..len], test_bytes);

                // bounce them right back...
                assert_eq!(
                    server.send_to(&buffer[0..len], addr).expect("send failed"),
                    len
                );
            }
        })
        .unwrap();

    // setup the client, which is going to run on the testing thread...
    let mut io_loop = Runtime::new().unwrap();

    // the tests should run within 5 seconds... right?
    // TODO: add timeout here, so that test never hangs...
    let client_addr = match server_addr {
        std::net::SocketAddr::V4(_) => "127.0.0.1:0",
        std::net::SocketAddr::V6(_) => "[::1]:0",
    };

    let socket = tokio_udp::UdpSocket::bind(
        &client_addr.to_socket_addrs().unwrap().next().unwrap(),
    ).expect("could not create socket"); // some random address...
    let (mut stream, sender) = UdpStream::with_bound(socket);
    //let mut stream: UdpStream = io_loop.block_on(stream).ok().unwrap();

    for _ in 0..send_recv_times {
        // test once
        sender
            .unbounded_send(SerialMessage::new(test_bytes.to_vec(), server_addr))
            .unwrap();
        let (buffer_and_addr, stream_tmp) = io_loop.block_on(stream.into_future()).ok().unwrap();
        stream = stream_tmp;
        let message = buffer_and_addr.expect("no buffer received");
        assert_eq!(message.bytes(), test_bytes);
        assert_eq!(message.addr(), server_addr);
    }

    succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
    server_handle.join().expect("server thread failed");
}
<|endoftext|>


<commit_before>use base::{
    AbstractCFTypeRef,
    Boolean,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault
};
use libc::{c_int, c_void};

pub type CFNumberType = u32;

// members of enum CFNumberType
const kCFNumberSInt8Type:     CFNumberType = 1;
const kCFNumberSInt16Type:    CFNumberType = 2;
const kCFNumberSInt32Type:    CFNumberType = 3;
const kCFNumberSInt64Type:    CFNumberType = 4;
const kCFNumberFloat32Type:   CFNumberType = 5;
const kCFNumberFloat64Type:   CFNumberType = 6;
const kCFNumberCharType:      CFNumberType = 7;
const kCFNumberShortType:     CFNumberType = 8;
const kCFNumberIntType:       CFNumberType = 9;
const kCFNumberLongType:      CFNumberType = 10;
const kCFNumberLongLongType:  CFNumberType = 11;
const kCFNumberFloatType:     CFNumberType = 12;
const kCFNumberDoubleType:    CFNumberType = 13;
const kCFNumberCFIndexType:   CFNumberType = 14;
const kCFNumberNSIntegerType: CFNumberType = 15;
const kCFNumberCGFloatType:   CFNumberType = 16;
const kCFNumberMaxType:       CFNumberType = 16;

struct __CFNumber { private: () }
pub type CFNumberRef = *__CFNumber;

pub impl CFNumberRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    static pure fn type_id() -> CFTypeID unsafe { CFNumberGetTypeID() }
}

pub impl CFNumberRef {
    static fn type_id() -> CFTypeID { CFNumberGetTypeID() }
}

pub type CFNumber = CFWrapper<CFNumberRef, (), ()>;

pub impl CFNumber {
    static fn new<T:Copy ConvertibleToCFNumber>(n: T) -> CFNumber {
        let objref = unsafe { CFNumberCreate(kCFAllocatorDefault, n.cf_number_type(), cast::transmute(&n)) };
        CFWrapper::wrap_owned(objref)
    }

    pure fn to_i8() -> i8 {
        let ty = kCFNumberSInt8Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i8 = 0i8;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i8";
            }
            return val;
        }
    }

    pure fn to_i16() -> i16 {
        let ty = kCFNumberSInt16Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i16 = 0i16;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i16";
            }
            return val;
        }
    }

    pure fn to_i32() -> i32 {
        let ty = kCFNumberSInt32Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i32 = 0i32;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i32";
            }
            return val;
        }
    }

    pure fn to_float() -> float unsafe {
        assert self.has_float_type();
        let ty = CFNumberGetType(self.obj);
        if ty == kCFNumberFloat32Type || ty == kCFNumberFloatType {
            let mut val: libc::c_float = 0.0f as libc::c_float;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to libc::c_float";
            }
            return val as float;
        }
        else if ty == kCFNumberFloat64Type || ty == kCFNumberDoubleType {
            let mut val: libc::c_double = 0.0f as libc::c_double;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                    fail ~"Error in unwrapping CFNumber to libc::c_double";
                }
            return val as float;
        }

        fail fmt!("Unable to wrap CFNumber into float: with type tag=%?", ty)
    }

    priv pure fn has_float_type() -> bool unsafe { CFNumberIsFloatType(self.obj) as bool }

    priv pure fn has_number_type(ty: CFNumberType) -> bool {
        unsafe { CFNumberGetType(self.obj) == ty }
    }
}

pub trait ConvertibleToCFNumber {
    // FIXME: Should be static, but that breaks.
    pure fn cf_number_type(&self) -> CFNumberType;
}

impl i8 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt8Type as CFNumberType }
}

impl i16 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt16Type as CFNumberType }
}

impl i32 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt32Type as CFNumberType }
}

impl i64 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt64Type as CFNumberType }
}

impl float : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberFloatType as CFNumberType }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFNumber.h
     */

    const kCFNumberNaN: CFNumberRef;
    const kCFNumberNegativeInfinity: CFNumberRef;
    const kCFNumberPositiveInfinity: CFNumberRef;

    fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *c_void)
                   -> CFNumberRef;
    //fn CFNumberGetByteSize
    fn CFNumberGetType(number: CFNumberRef) -> CFNumberType;
    fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *c_void) -> bool;
    fn CFNumberIsFloatType(number: CFNumberRef) -> Boolean;
    //fn CFNumberCompare
    fn CFNumberGetTypeID() -> CFTypeID;
}

fn should_fail_on_bad_downcast() {
    #[test];
    #[should_fail];

    use boolean::CFBooleanRef;

    let one = CFWrapper::to_CFType(CFNumber::new(1_i32));
    let casted = base::downcast::<CFBooleanRef>(*one.borrow_ref());
}<commit_msg>Remove duplicate type_id() implementation for CFNumber<commit_after>use base::{
    AbstractCFTypeRef,
    Boolean,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault
};
use libc::{c_int, c_void};

pub type CFNumberType = u32;

// members of enum CFNumberType
const kCFNumberSInt8Type:     CFNumberType = 1;
const kCFNumberSInt16Type:    CFNumberType = 2;
const kCFNumberSInt32Type:    CFNumberType = 3;
const kCFNumberSInt64Type:    CFNumberType = 4;
const kCFNumberFloat32Type:   CFNumberType = 5;
const kCFNumberFloat64Type:   CFNumberType = 6;
const kCFNumberCharType:      CFNumberType = 7;
const kCFNumberShortType:     CFNumberType = 8;
const kCFNumberIntType:       CFNumberType = 9;
const kCFNumberLongType:      CFNumberType = 10;
const kCFNumberLongLongType:  CFNumberType = 11;
const kCFNumberFloatType:     CFNumberType = 12;
const kCFNumberDoubleType:    CFNumberType = 13;
const kCFNumberCFIndexType:   CFNumberType = 14;
const kCFNumberNSIntegerType: CFNumberType = 15;
const kCFNumberCGFloatType:   CFNumberType = 16;
const kCFNumberMaxType:       CFNumberType = 16;

struct __CFNumber { private: () }
pub type CFNumberRef = *__CFNumber;

pub impl CFNumberRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    static pure fn type_id() -> CFTypeID unsafe { CFNumberGetTypeID() }
}

pub type CFNumber = CFWrapper<CFNumberRef, (), ()>;

pub impl CFNumber {
    static fn new<T:Copy ConvertibleToCFNumber>(n: T) -> CFNumber {
        let objref = unsafe { CFNumberCreate(kCFAllocatorDefault, n.cf_number_type(), cast::transmute(&n)) };
        CFWrapper::wrap_owned(objref)
    }

    pure fn to_i8() -> i8 {
        let ty = kCFNumberSInt8Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i8 = 0i8;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i8";
            }
            return val;
        }
    }

    pure fn to_i16() -> i16 {
        let ty = kCFNumberSInt16Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i16 = 0i16;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i16";
            }
            return val;
        }
    }

    pure fn to_i32() -> i32 {
        let ty = kCFNumberSInt32Type;
        assert self.has_number_type(ty);
        unsafe {
            let val: i32 = 0i32;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to i32";
            }
            return val;
        }
    }

    pure fn to_float() -> float unsafe {
        assert self.has_float_type();
        let ty = CFNumberGetType(self.obj);
        if ty == kCFNumberFloat32Type || ty == kCFNumberFloatType {
            let mut val: libc::c_float = 0.0f as libc::c_float;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                fail ~"Error in unwrapping CFNumber to libc::c_float";
            }
            return val as float;
        }
        else if ty == kCFNumberFloat64Type || ty == kCFNumberDoubleType {
            let mut val: libc::c_double = 0.0f as libc::c_double;
            if !CFNumberGetValue(self.obj, ty, cast::transmute(&val)) {
                    fail ~"Error in unwrapping CFNumber to libc::c_double";
                }
            return val as float;
        }

        fail fmt!("Unable to wrap CFNumber into float: with type tag=%?", ty)
    }

    priv pure fn has_float_type() -> bool unsafe { CFNumberIsFloatType(self.obj) as bool }

    priv pure fn has_number_type(ty: CFNumberType) -> bool {
        unsafe { CFNumberGetType(self.obj) == ty }
    }
}

pub trait ConvertibleToCFNumber {
    // FIXME: Should be static, but that breaks.
    pure fn cf_number_type(&self) -> CFNumberType;
}

impl i8 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt8Type as CFNumberType }
}

impl i16 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt16Type as CFNumberType }
}

impl i32 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt32Type as CFNumberType }
}

impl i64 : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberSInt64Type as CFNumberType }
}

impl float : ConvertibleToCFNumber {
    pure fn cf_number_type(&self) -> CFNumberType { kCFNumberFloatType as CFNumberType }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFNumber.h
     */

    const kCFNumberNaN: CFNumberRef;
    const kCFNumberNegativeInfinity: CFNumberRef;
    const kCFNumberPositiveInfinity: CFNumberRef;

    fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *c_void)
                   -> CFNumberRef;
    //fn CFNumberGetByteSize
    fn CFNumberGetType(number: CFNumberRef) -> CFNumberType;
    fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *c_void) -> bool;
    fn CFNumberIsFloatType(number: CFNumberRef) -> Boolean;
    //fn CFNumberCompare
    fn CFNumberGetTypeID() -> CFTypeID;
}

fn should_fail_on_bad_downcast() {
    #[test];
    #[should_fail];

    use boolean::CFBooleanRef;

    let one = CFWrapper::to_CFType(CFNumber::new(1_i32));
    let casted = base::downcast::<CFBooleanRef>(*one.borrow_ref());
}<|endoftext|>


<commit_before>use player::Next;
use db::enums;

/// The standard arena is based on the default 1v1 fight.

impl<'a> super::Arena<'a> {
    /// Simulating a fight. This function is called on a arena and uses the next_move variables of
    /// the players to know what to do in this round.
    /// Important: All next_move variables must contain a Some() entry. If the function is called
    /// and atleast one variable is holding a None, this function will panic!
    pub fn fight(&mut self) {
        // This flag is used to show that the round is "over" earlier as aspected.
        // This can be happen if pursuit was used or both pokemons are swapped.
        let mut end_of_fight = false;
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Setting the switched flag in the Player structs to false and reset if a swap will be done
        ////////////////////////////////////////////////////////////////////////////////////////////
        self.get_player_one().set_switched(false);
        self.get_player_two().set_switched(false);

        ////////////////////////////////////////////////////////////////////////////////////////////
        // Handle the pursuit(ID: 228) attack
        ////////////////////////////////////////////////////////////////////////////////////////////
        match self.get_player_one()
            .get_next_move()
            .expect("Unexpected error! This field of player one shouldn`t be None at this point.") {
            Next::Move(technique) => {
                if technique.get_id() == 228 {
                    match self.get_player_one()
                        .get_next_move()
                        .expect("Unexpected error! This field of player one shouldn`t be None \
                                 at this point.") {
                        Next::Switch(_) => {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 2);
                            // let slot =
                            //     self.get_player_one().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_one().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_one().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_one().set_last_action(old_move);
                            self.get_player_one().set_next_move(None);

                        }
                        _ => {}
                    }
                }
            }
            Next::Switch(_) => {
                match self.get_player_one()
                    .get_next_move()
                    .expect("Unexpected error! This field of player one shouldn`t be None at \
                             this point.") {
                    Next::Move(technique) => {
                        if technique.get_id() == 228 {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 1);
                            // let slot =
                            //     self.get_player_two().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_two().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_two().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_two().set_last_action(old_move);
                            self.get_player_two().set_next_move(None);
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player One if he wants to
        ////////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_one().get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_one().set_current(pkmn.get_int());
                    self.get_player_one().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_one().get_next_move().unwrap().clone();
                    self.get_player_one().set_last_action(old_move);
                    self.get_player_one().set_next_move(None);
                }
                _ => {}
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player Two if he wants to
        ////////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_two().get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_two().set_current(pkmn.get_int());
                    self.get_player_two().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_two().get_next_move().unwrap().clone();
                    self.get_player_two().set_last_action(old_move);
                    self.get_player_two().set_next_move(None);
                }
                _ => {}
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // If player one doesnt need to make a move anymore, only resolve attack of player two
        ////////////////////////////////////////////////////////////////////////////////////////////
        if self.get_player_one().get_next_move().is_none() &&
           self.get_player_two().get_next_move().is_some() {
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 2),
                _ => {}
            }
            end_of_fight = true;
            ////////////////////////////////////////////////////////////////////////////////////////
            // If player two doesnt need to make a move anymore, only resolve attack of player one
            ////////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 1),
                _ => {}
            }
            end_of_fight = true;
            ////////////////////////////////////////////////////////////////////////////////////////
            // If both player dont have a move go out of fight
            ////////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            end_of_fight = true;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////
        // If both player want to perform an attack Priority and Speed of Pokemon will be used to
        // decide which pokemon strikes first
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Variables for faster comparison. x_prio is the priority of the pokemon of player x and
        // x_speed is the attackspeed of the pokemon of player x
        if !end_of_fight {
            let one_prio;
            let one_attack;
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(attack, _) => {
                    one_prio = attack.get_priority();
                    one_attack = attack.clone();
                }
                _ => unreachable!(),
            };
            let two_prio;
            let two_attack;
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(attack, _) => {
                    two_prio = attack.get_priority();
                    two_attack = attack.clone();
                }
                _ => unreachable!(),
            };
            let mut current = self.get_player_one().get_current();
            let one_speed = self.get_player_one().get_pokemon_list()[current]
                .get_current()
                .get_stat(&enums::Stats::Speed);
            current = self.get_player_two().get_current();
            let two_speed = self.get_player_two().get_pokemon_list()[current]
                .get_current()
                .get_stat(&enums::Stats::Speed);
            ////////////////////////////////////////////////////////////////////////////////////////
            // The attack with the higher Priority starts
            ////////////////////////////////////////////////////////////////////////////////////////
            if one_prio > two_prio {
                one_attack.resolve(self, 1);
                two_attack.resolve(self, 2);
            } else if one_prio < two_prio {
                two_attack.resolve(self, 2);
                one_attack.resolve(self, 1);
            } else {
                ////////////////////////////////////////////////////////////////////////////////////
                // If the attack priority is the same the pokemon with the higher attackspeed starts
                // If the attack speed is the same, the pokemon of player one will strike first
                ////////////////////////////////////////////////////////////////////////////////////
                if one_speed >= two_speed {
                    one_attack.resolve(self, 1);
                    two_attack.resolve(self, 2);
                } else {
                    two_attack.resolve(self, 2);
                    one_attack.resolve(self, 1);
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // End of Turn moves like validate the weather and effects, handle poison etc.
        ////////////////////////////////////////////////////////////////////////////////////////////
        self.validate_effects_and_weather();
        // TODO: All kind of effect like sleep, paralysis, poison... arent handled yet.
    }
}
<commit_msg>resolve enum conflicts #2<commit_after>use player::Next;
use db::enums;

/// The standard arena is based on the default 1v1 fight.

impl<'a> super::Arena<'a> {
    /// Simulating a fight. This function is called on a arena and uses the next_move variables of
    /// the players to know what to do in this round.
    /// Important: All next_move variables must contain a Some() entry. If the function is called
    /// and atleast one variable is holding a None, this function will panic!
    pub fn fight(&mut self) {
        // This flag is used to show that the round is "over" earlier as aspected.
        // This can be happen if pursuit was used or both pokemons are swapped.
        let mut end_of_fight = false;
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Setting the switched flag in the Player structs to false and reset if a swap will be done
        ////////////////////////////////////////////////////////////////////////////////////////////
        self.get_player_one().set_switched(false);
        self.get_player_two().set_switched(false);

        ////////////////////////////////////////////////////////////////////////////////////////////
        // Handle the pursuit(ID: 228) attack
        ////////////////////////////////////////////////////////////////////////////////////////////
        match self.get_player_one()
            .get_next_move()
            .expect("Unexpected error! This field of player one shouldn`t be None at this point.") {
            Next::Move(technique) => {
                if technique.get_id() == 228 {
                    match self.get_player_one()
                        .get_next_move()
                        .expect("Unexpected error! This field of player one shouldn`t be None \
                                 at this point.") {
                        Next::Switch(_) => {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 2);
                            // let slot =
                            //     self.get_player_one().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_one().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_one().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_one().set_last_action(old_move);
                            self.get_player_one().set_next_move(None);

                        }
                        _ => {}
                    }
                }
            }
            Next::Switch(_) => {
                match self.get_player_one()
                    .get_next_move()
                    .expect("Unexpected error! This field of player one shouldn`t be None at \
                             this point.") {
                    Next::Move(technique) => {
                        if technique.get_id() == 228 {
                            // Resolving pursuit, updating last action and last move
                            // and setting the next move to None
                            technique.resolve(self, 1);
                            // let slot =
                            //     self.get_player_two().get_attack_slot(technique.clone())
                            //         .unwrap();
                            // self.get_player_two().set_last_move(Some((technique, slot)));
                            // let old_move = self.get_player_two().get_next_move().unwrap()
                            //         .clone();
                            // self.get_player_two().set_last_action(old_move);
                            self.get_player_two().set_next_move(None);
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player One if he wants to
        ////////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_one().get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_one().set_current(pkmn.get_int());
                    self.get_player_one().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_one().get_next_move().unwrap().clone();
                    self.get_player_one().set_last_action(old_move);
                    self.get_player_one().set_next_move(None);
                }
                _ => {}
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Switch Pokemon of Player Two if he wants to
        ////////////////////////////////////////////////////////////////////////////////////////////
        if let Some(x) = self.get_player_two().get_next_move() {
            match x {
                Next::Switch(pkmn) => {
                    // Switch of the current pokemon + setting flag
                    self.get_player_two().set_current(pkmn.get_int());
                    self.get_player_two().set_switched(true);
                    // Updating last action and setting next move to None. Last Move isnt updated
                    // because the last action wasnt a move
                    let old_move = self.get_player_two().get_next_move().unwrap().clone();
                    self.get_player_two().set_last_action(old_move);
                    self.get_player_two().set_next_move(None);
                }
                _ => {}
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // If player one doesnt need to make a move anymore, only resolve attack of player two
        ////////////////////////////////////////////////////////////////////////////////////////////
        if self.get_player_one().get_next_move().is_none() &&
           self.get_player_two().get_next_move().is_some() {
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 2),
                _ => {}
            }
            end_of_fight = true;
            ////////////////////////////////////////////////////////////////////////////////////////
            // If player two doesnt need to make a move anymore, only resolve attack of player one
            ////////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(x, _) => x.resolve(self, 1),
                _ => {}
            }
            end_of_fight = true;
            ////////////////////////////////////////////////////////////////////////////////////////
            // If both player dont have a move go out of fight
            ////////////////////////////////////////////////////////////////////////////////////////
        } else if self.get_player_two().get_next_move().is_none() &&
                  self.get_player_one().get_next_move().is_some() {
            end_of_fight = true;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////
        // If both player want to perform an attack Priority and Speed of Pokemon will be used to
        // decide which pokemon strikes first
        ////////////////////////////////////////////////////////////////////////////////////////////
        // Variables for faster comparison. x_prio is the priority of the pokemon of player x and
        // x_speed is the attackspeed of the pokemon of player x
        if !end_of_fight {
            let one_prio;
            let one_attack;
            match self.get_player_one().get_next_move().unwrap() {
                Next::Move(attack) => {
                    one_prio = attack.get_priority();
                    one_attack = attack.clone();
                }
                _ => unreachable!(),
            };
            let two_prio;
            let two_attack;
            match self.get_player_two().get_next_move().unwrap() {
                Next::Move(attack) => {
                    two_prio = attack.get_priority();
                    two_attack = attack.clone();
                }
                _ => unreachable!(),
            };
            let mut current = self.get_player_one().get_current();
            let one_speed = self.get_player_one().get_pokemon_list()[current]
                .get_current()
                .get_stat(&enums::Stats::Speed);
            current = self.get_player_two().get_current();
            let two_speed = self.get_player_two().get_pokemon_list()[current]
                .get_current()
                .get_stat(&enums::Stats::Speed);
            ////////////////////////////////////////////////////////////////////////////////////////
            // The attack with the higher Priority starts
            ////////////////////////////////////////////////////////////////////////////////////////
            if one_prio > two_prio {
                one_attack.resolve(self, 1);
                two_attack.resolve(self, 2);
            } else if one_prio < two_prio {
                two_attack.resolve(self, 2);
                one_attack.resolve(self, 1);
            } else {
                ////////////////////////////////////////////////////////////////////////////////////
                // If the attack priority is the same the pokemon with the higher attackspeed starts
                // If the attack speed is the same, the pokemon of player one will strike first
                ////////////////////////////////////////////////////////////////////////////////////
                if one_speed >= two_speed {
                    one_attack.resolve(self, 1);
                    two_attack.resolve(self, 2);
                } else {
                    two_attack.resolve(self, 2);
                    one_attack.resolve(self, 1);
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////
        // End of Turn moves like validate the weather and effects, handle poison etc.
        ////////////////////////////////////////////////////////////////////////////////////////////
        self.validate_effects_and_weather();
        // TODO: All kind of effect like sleep, paralysis, poison... arent handled yet.
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::{self, Library, Face};

mod list_fonts;

use self::list_fonts::fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    keys: HashMap<::std::path::PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey, size: Size) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let scale_size = self.dpr as f64 * size.as_f32_pts() as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Ok(Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = self.get_face(desc)?;
        let key = FontKey::next();
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key, false)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            println!("got font path={:?}", path);
            return Ok(self.library.new_face(path, index)?);
        }
        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool)
                          -> Result<RasterizedGlyph, Error> {
        let faces = self.faces.clone();
        let face = faces
            .get(&glyph_key.font_key)
            .ok_or(Error::FontNotLoaded)?;

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
        let index = face.get_char_index(c as usize);

        if index == 0 && have_recursed == false {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            let new_glyph_key = GlyphKey {
                c: glyph_key.c,
                font_key: key,
                size: glyph_key.size
            };

            return self.get_rendered_glyph(&new_glyph_key, true);
        }

        face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        Ok(RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        })
    }

    fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
                    match self.keys.get(&path.to_path_buf()) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            return Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let pathbuf = path.to_path_buf();
                            let face = self.library.new_face(path, index)?;
                            let key = FontKey::next();
                            self.keys.insert(pathbuf, key);
                            self.faces.insert(key, face);
                            return Ok(key)
                        }
                    }
                }

                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))
                ))
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<commit_msg>font::ft: misc style cleanup.<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::{self, Library, Face};

mod list_fonts;

use self::list_fonts::fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    keys: HashMap<::std::path::PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey, size: Size) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let scale_size = self.dpr as f64 * size.as_f32_pts() as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Ok(Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = self.get_face(desc)?;
        let key = FontKey::next();
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key, false)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
            println!("got font path={:?}", path);
            Ok(self.library.new_face(path, index)?)
        }
        else {
            Err(Error::MissingFont(desc.to_owned()))
        }
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool)
                          -> Result<RasterizedGlyph, Error> {
        let faces = self.faces.clone();
        let face = faces
            .get(&glyph_key.font_key)
            .ok_or(Error::FontNotLoaded)?;

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
        let index = face.get_char_index(c as usize);

        if index == 0 && have_recursed == false {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            let new_glyph_key = GlyphKey {
                c: glyph_key.c,
                font_key: key,
                size: glyph_key.size
            };

            return self.get_rendered_glyph(&new_glyph_key, true);
        }

        face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        Ok(RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        })
    }

    fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
                    match self.keys.get(&path) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let face = self.library.new_face(path.clone(), index)?;
                            let key = FontKey::next();
                            self.faces.insert(key, face);
                            self.keys.insert(path, key);
                            Ok(key)
                        }
                    }
                }
                else {
                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))))
                }
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;

use syn::{parse_quote, FnArg, PatType, Type, TypePtr};

use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability};
use crate::conversion::analysis::pod::PodPhase;
use crate::conversion::api::{
    CppVisibility, FuncToConvert, Provenance, RustSubclassFnDetails, SubclassConstructorDetails,
    SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness,
};
use crate::conversion::apivec::ApiVec;
use crate::{
    conversion::{
        analysis::fun::function_wrapper::{
            CppFunction, CppFunctionBody, CppFunctionKind, TypeConversionPolicy,
        },
        api::{Api, ApiName},
    },
    types::{make_ident, Namespace, QualifiedName},
};

use super::{FnAnalysis, FnPrePhase};

pub(super) fn subclasses_by_superclass(
    apis: &ApiVec<PodPhase>,
) -> HashMap<QualifiedName, Vec<SubclassName>> {
    let mut subclasses_per_superclass: HashMap<QualifiedName, Vec<SubclassName>> = HashMap::new();

    for api in apis.iter() {
        if let Api::Subclass { name, superclass } = api {
            subclasses_per_superclass
                .entry(superclass.clone())
                .or_default()
                .push(name.clone());
        }
    }
    subclasses_per_superclass
}

pub(super) fn create_subclass_fn_wrapper(
    sub: SubclassName,
    super_fn_name: &QualifiedName,
    fun: &FuncToConvert,
) -> Box<FuncToConvert> {
    let self_ty = Some(sub.cpp());
    Box::new(FuncToConvert {
        synthesized_this_type: self_ty.clone(),
        self_ty,
        ident: super_fn_name.get_final_ident(),
        doc_attr: fun.doc_attr.clone(),
        inputs: fun.inputs.clone(),
        output: fun.output.clone(),
        vis: fun.vis.clone(),
        virtualness: Virtualness::None,
        cpp_vis: CppVisibility::Public,
        special_member: None,
        unused_template_param: fun.unused_template_param,
        original_name: None,
        references: fun.references.clone(),
        add_to_trait: fun.add_to_trait.clone(),
        is_deleted: fun.is_deleted,
        synthetic_cpp: None,
        provenance: Provenance::SynthesizedOther,
    })
}

pub(super) fn create_subclass_trait_item(
    name: ApiName,
    analysis: &FnAnalysis,
    receiver_mutability: &ReceiverMutability,
    receiver: QualifiedName,
    is_pure_virtual: bool,
) -> Api<FnPrePhase> {
    let param_names = analysis
        .param_details
        .iter()
        .map(|pd| pd.name.clone())
        .collect();
    Api::SubclassTraitItem {
        name,
        details: SuperclassMethod {
            name: make_ident(&analysis.rust_name),
            params: analysis.params.clone(),
            ret_type: analysis.ret_type.clone(),
            param_names,
            receiver_mutability: receiver_mutability.clone(),
            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
            is_pure_virtual,
            receiver,
        },
    }
}

pub(super) fn create_subclass_function(
    sub: &SubclassName,
    analysis: &super::FnAnalysis,
    name: &ApiName,
    receiver_mutability: &ReceiverMutability,
    superclass: &QualifiedName,
    dependencies: Vec<QualifiedName>,
) -> Api<FnPrePhase> {
    let cpp = sub.cpp();
    let holder_name = sub.holder();
    let rust_call_name = make_ident(format!(
        "{}_{}",
        sub.0.name.get_final_item(),
        name.name.get_final_item()
    ));
    let params = std::iter::once(parse_quote! {
        me: & #holder_name
    })
    .chain(analysis.params.iter().skip(1).cloned())
    .collect();
    let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
        CppFunctionKind::Method
    } else {
        CppFunctionKind::ConstMethod
    };
    let argument_conversion = analysis
        .param_details
        .iter()
        .skip(1)
        .map(|p| p.conversion.clone())
        .collect();
    Api::RustSubclassFn {
        name: ApiName::new_in_root_namespace(rust_call_name.clone()),
        subclass: sub.clone(),
        details: Box::new(RustSubclassFnDetails {
            params,
            ret: analysis.ret_type.clone(),
            method_name: make_ident(&analysis.rust_name),
            cpp_impl: CppFunction {
                payload: CppFunctionBody::FunctionCall(Namespace::new(), rust_call_name),
                wrapper_function_name: name.name.get_final_ident(),
                original_cpp_name: name.cpp_name(),
                return_conversion: analysis.ret_conversion.clone(),
                argument_conversion,
                kind,
                pass_obs_field: true,
                qualification: Some(cpp),
            },
            superclass: superclass.clone(),
            receiver_mutability: receiver_mutability.clone(),
            dependencies,
            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
            is_pure_virtual: matches!(
                analysis.kind,
                FnKind::Method(_, MethodKind::PureVirtual(..))
            ),
        }),
    }
}

pub(super) fn create_subclass_constructor(
    sub: SubclassName,
    analysis: &FnAnalysis,
    sup: &QualifiedName,
    fun: &FuncToConvert,
) -> (Box<FuncToConvert>, ApiName) {
    let holder = sub.holder();
    let cpp = sub.cpp();
    let wrapper_function_name = cpp.get_final_ident();
    let initial_arg = TypeConversionPolicy::new_unconverted(parse_quote! {
        rust::Box< #holder >
    });
    let args = std::iter::once(initial_arg).chain(
        analysis
            .param_details
            .iter()
            .skip(1) // skip placement new destination
            .map(|aa| aa.conversion.clone()),
    );
    let cpp_impl = CppFunction {
        payload: CppFunctionBody::ConstructSuperclass(sup.to_cpp_name()),
        wrapper_function_name,
        return_conversion: None,
        argument_conversion: args.collect(),
        kind: CppFunctionKind::SynthesizedConstructor,
        pass_obs_field: false,
        qualification: Some(cpp.clone()),
        original_cpp_name: cpp.to_cpp_name(),
    };
    let subclass_constructor_details = Box::new(SubclassConstructorDetails {
        subclass: sub.clone(),
        is_trivial: analysis.param_details.len() == 1, // just placement new
        // destination, no other parameters
        cpp_impl,
    });
    let subclass_constructor_name =
        make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
    let mut existing_params = fun.inputs.clone();
    if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
        if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
            *elem = Box::new(Type::Path(sub.cpp().to_type_path()));
        } else {
            panic!("Unexpected self type parameter when creating subclass constructor");
        }
    } else {
        panic!("Unexpected self type parameter when creating subclass constructor");
    }
    let mut existing_params = existing_params.into_iter();
    let self_param = existing_params.next();
    let boxed_holder_param: FnArg = parse_quote! {
        peer: rust::Box<#holder>
    };
    let inputs = self_param
        .into_iter()
        .chain(std::iter::once(boxed_holder_param))
        .chain(existing_params)
        .collect();
    let maybe_wrap = Box::new(FuncToConvert {
        ident: subclass_constructor_name.clone(),
        doc_attr: fun.doc_attr.clone(),
        inputs,
        output: fun.output.clone(),
        vis: fun.vis.clone(),
        virtualness: Virtualness::None,
        cpp_vis: CppVisibility::Public,
        special_member: fun.special_member.clone(),
        original_name: None,
        unused_template_param: fun.unused_template_param,
        references: fun.references.clone(),
        synthesized_this_type: Some(cpp.clone()),
        self_ty: Some(cpp),
        add_to_trait: None,
        is_deleted: fun.is_deleted,
        synthetic_cpp: None,
        provenance: Provenance::SynthesizedSubclassConstructor(subclass_constructor_details),
    });
    let subclass_constructor_name = ApiName::new_with_cpp_name(
        &Namespace::new(),
        subclass_constructor_name,
        Some(sub.cpp().get_final_item().to_string()),
    );
    (maybe_wrap, subclass_constructor_name)
}
<commit_msg>Subclass function names are unique.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;

use syn::{parse_quote, FnArg, PatType, Type, TypePtr};

use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability};
use crate::conversion::analysis::pod::PodPhase;
use crate::conversion::api::{
    CppVisibility, FuncToConvert, Provenance, RustSubclassFnDetails, SubclassConstructorDetails,
    SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness,
};
use crate::conversion::apivec::ApiVec;
use crate::{
    conversion::{
        analysis::fun::function_wrapper::{
            CppFunction, CppFunctionBody, CppFunctionKind, TypeConversionPolicy,
        },
        api::{Api, ApiName},
    },
    types::{make_ident, Namespace, QualifiedName},
};

use super::{FnAnalysis, FnPrePhase};

pub(super) fn subclasses_by_superclass(
    apis: &ApiVec<PodPhase>,
) -> HashMap<QualifiedName, Vec<SubclassName>> {
    let mut subclasses_per_superclass: HashMap<QualifiedName, Vec<SubclassName>> = HashMap::new();

    for api in apis.iter() {
        if let Api::Subclass { name, superclass } = api {
            subclasses_per_superclass
                .entry(superclass.clone())
                .or_default()
                .push(name.clone());
        }
    }
    subclasses_per_superclass
}

pub(super) fn create_subclass_fn_wrapper(
    sub: &SubclassName,
    super_fn_name: &QualifiedName,
    fun: &FuncToConvert,
) -> Box<FuncToConvert> {
    let self_ty = Some(sub.cpp());
    Box::new(FuncToConvert {
        synthesized_this_type: self_ty.clone(),
        self_ty,
        ident: super_fn_name.get_final_ident(),
        doc_attr: fun.doc_attr.clone(),
        inputs: fun.inputs.clone(),
        output: fun.output.clone(),
        vis: fun.vis.clone(),
        virtualness: Virtualness::None,
        cpp_vis: CppVisibility::Public,
        special_member: None,
        unused_template_param: fun.unused_template_param,
        original_name: None,
        references: fun.references.clone(),
        add_to_trait: fun.add_to_trait.clone(),
        is_deleted: fun.is_deleted,
        synthetic_cpp: None,
        provenance: Provenance::SynthesizedOther,
    })
}

pub(super) fn create_subclass_trait_item(
    name: ApiName,
    analysis: &FnAnalysis,
    receiver_mutability: &ReceiverMutability,
    receiver: QualifiedName,
    is_pure_virtual: bool,
) -> Api<FnPrePhase> {
    let param_names = analysis
        .param_details
        .iter()
        .map(|pd| pd.name.clone())
        .collect();
    Api::SubclassTraitItem {
        name,
        details: SuperclassMethod {
            name: make_ident(&analysis.rust_name),
            params: analysis.params.clone(),
            ret_type: analysis.ret_type.clone(),
            param_names,
            receiver_mutability: receiver_mutability.clone(),
            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
            is_pure_virtual,
            receiver,
        },
    }
}

pub(super) fn create_subclass_function(
    sub: &SubclassName,
    analysis: &super::FnAnalysis,
    name: &ApiName,
    receiver_mutability: &ReceiverMutability,
    superclass: &QualifiedName,
    dependencies: Vec<QualifiedName>,
) -> Api<FnPrePhase> {
    let cpp = sub.cpp();
    let holder_name = sub.holder();
    let rust_call_name = make_ident(format!(
        "{}_{}",
        sub.0.name.get_final_item(),
        name.name.get_final_item()
    ));
    let params = std::iter::once(parse_quote! {
        me: & #holder_name
    })
    .chain(analysis.params.iter().skip(1).cloned())
    .collect();
    let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
        CppFunctionKind::Method
    } else {
        CppFunctionKind::ConstMethod
    };
    let argument_conversion = analysis
        .param_details
        .iter()
        .skip(1)
        .map(|p| p.conversion.clone())
        .collect();
    Api::RustSubclassFn {
        name: ApiName::new_in_root_namespace(rust_call_name.clone()),
        subclass: sub.clone(),
        details: Box::new(RustSubclassFnDetails {
            params,
            ret: analysis.ret_type.clone(),
            method_name: make_ident(&analysis.rust_name),
            cpp_impl: CppFunction {
                payload: CppFunctionBody::FunctionCall(Namespace::new(), rust_call_name),
                wrapper_function_name: make_ident(&analysis.rust_name),
                original_cpp_name: name.cpp_name(),
                return_conversion: analysis.ret_conversion.clone(),
                argument_conversion,
                kind,
                pass_obs_field: true,
                qualification: Some(cpp),
            },
            superclass: superclass.clone(),
            receiver_mutability: receiver_mutability.clone(),
            dependencies,
            requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
            is_pure_virtual: matches!(
                analysis.kind,
                FnKind::Method(_, MethodKind::PureVirtual(..))
            ),
        }),
    }
}

pub(super) fn create_subclass_constructor(
    sub: SubclassName,
    analysis: &FnAnalysis,
    sup: &QualifiedName,
    fun: &FuncToConvert,
) -> (Box<FuncToConvert>, ApiName) {
    let holder = sub.holder();
    let cpp = sub.cpp();
    let wrapper_function_name = cpp.get_final_ident();
    let initial_arg = TypeConversionPolicy::new_unconverted(parse_quote! {
        rust::Box< #holder >
    });
    let args = std::iter::once(initial_arg).chain(
        analysis
            .param_details
            .iter()
            .skip(1) // skip placement new destination
            .map(|aa| aa.conversion.clone()),
    );
    let cpp_impl = CppFunction {
        payload: CppFunctionBody::ConstructSuperclass(sup.to_cpp_name()),
        wrapper_function_name,
        return_conversion: None,
        argument_conversion: args.collect(),
        kind: CppFunctionKind::SynthesizedConstructor,
        pass_obs_field: false,
        qualification: Some(cpp.clone()),
        original_cpp_name: cpp.to_cpp_name(),
    };
    let subclass_constructor_details = Box::new(SubclassConstructorDetails {
        subclass: sub.clone(),
        is_trivial: analysis.param_details.len() == 1, // just placement new
        // destination, no other parameters
        cpp_impl,
    });
    let subclass_constructor_name =
        make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
    let mut existing_params = fun.inputs.clone();
    if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
        if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
            *elem = Box::new(Type::Path(sub.cpp().to_type_path()));
        } else {
            panic!("Unexpected self type parameter when creating subclass constructor");
        }
    } else {
        panic!("Unexpected self type parameter when creating subclass constructor");
    }
    let mut existing_params = existing_params.into_iter();
    let self_param = existing_params.next();
    let boxed_holder_param: FnArg = parse_quote! {
        peer: rust::Box<#holder>
    };
    let inputs = self_param
        .into_iter()
        .chain(std::iter::once(boxed_holder_param))
        .chain(existing_params)
        .collect();
    let maybe_wrap = Box::new(FuncToConvert {
        ident: subclass_constructor_name.clone(),
        doc_attr: fun.doc_attr.clone(),
        inputs,
        output: fun.output.clone(),
        vis: fun.vis.clone(),
        virtualness: Virtualness::None,
        cpp_vis: CppVisibility::Public,
        special_member: fun.special_member.clone(),
        original_name: None,
        unused_template_param: fun.unused_template_param,
        references: fun.references.clone(),
        synthesized_this_type: Some(cpp.clone()),
        self_ty: Some(cpp),
        add_to_trait: None,
        is_deleted: fun.is_deleted,
        synthetic_cpp: None,
        provenance: Provenance::SynthesizedSubclassConstructor(subclass_constructor_details),
    });
    let subclass_constructor_name = ApiName::new_with_cpp_name(
        &Namespace::new(),
        subclass_constructor_name,
        Some(sub.cpp().get_final_item().to_string()),
    );
    (maybe_wrap, subclass_constructor_name)
}
<|endoftext|>