<commit_before>use mio::*;
use mio::tcp::TcpStream;
use mio::channel::channel;
use mio::channel::{Sender, Receiver};
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::io::{Read, Write};
use std::io;
use std::error::Error;
use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;

use wire::handler::{ServerHandler, BasicHandler, PeerHandler, PeerAction, PeerStreamAction};
use wire::data::{PeerMsg, parse_peermsg};
use wire::protocol_handler::PeerServer;

const OUTSIDE_MSG: Token = Token(0);
type StreamId = u32;

pub struct Protocol {
    streams: HashMap<StreamId, (TcpStream, PeerStream)>,
    handler: PeerServer,
    poll: Poll,
    sender: Sender<ChanMsg>,
    receiver: Receiver<ChanMsg>,
    info: MetaInfo,
    info_hash: SHA1Hash20b,
    pending_actions: Vec<PeerAction>,
    stats: Stats,
    next_peer_id: usize,
}

struct PeerStream {
    id: StreamId,
    bytes_in: Vec<u8>,
    bytes_out: Vec<u8>,
    handshake_sent: bool,
    handshake_received: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct Stats {
    pub uploaded: usize,
    pub downloaded: usize,
    pub peer_count: usize,
}

impl Stats {
    pub fn new() -> Stats {
        Stats {
            uploaded: 0,
            downloaded: 0,
            peer_count: 0,
        }
    }
}

impl PeerStream {
    fn new(id: StreamId) -> PeerStream {
        PeerStream {
            id: id,
            bytes_in: Vec::new(),
            bytes_out: Vec::new(),
            handshake_sent: false,
            handshake_received: false,
        }
    }

    fn write_in(&mut self, mut bytes: Vec<u8>) {
        self.bytes_in.append(&mut bytes);
    }

    fn write_out(&mut self, mut bytes: Vec<u8>) {
        self.bytes_out.append(&mut bytes);
    }

    fn message(&mut self) -> Option<PeerMsg> {
        if self.bytes_in.len() == 0 {
            return None;
        }

        match parse_peermsg(&self.bytes_in) {
            Ok((msg, offset)) => {
                if offset < self.bytes_in.len() {
                    self.bytes_in.split_off(offset);
                } else {
                    self.bytes_in = Vec::new();
                }
                Some(msg)
            }
            Err(_) => {
                // TODO It needs to distinguish between recoverable and non-recoverable
                None
            }
        }
    }

    fn take(&mut self, out: &mut Write) -> io::Result<usize> {
        const MAX_BYTES_WRITE: usize = 1024 * 128;
        info!("Attempting to write {} bytes", self.bytes_out.len());
        out.write(&self.bytes_out)
    }
}

#[derive(Debug)]
pub enum ChanMsg {
    NewPeer(IpAddr, u16),
    StatsRequest,
    StatsResponse(Stats),
}

impl Protocol {
    pub fn new(info: &MetaInfo,
               hash: SHA1Hash20b,
               our_peer_id: &str)
               -> (Protocol, Sender<ChanMsg>, Receiver<ChanMsg>) {
        let poll = Poll::new().unwrap();

        match (channel(), channel()) {
            ((to_inside, from_outside), (to_outside, from_inside)) => {

                poll.register(&from_outside,
                              OUTSIDE_MSG,
                              Ready::readable(),
                              PollOpt::level())
                    .unwrap();

                let proto = Protocol {
                    streams: HashMap::new(),
                    poll: poll,
                    sender: to_outside,
                    receiver: from_outside,
                    info: info.clone(),
                    info_hash: hash.clone(),
                    pending_actions: Vec::new(),
                    stats: Stats::new(),
                    handler: ServerHandler::new(info.clone(), hash.clone(), our_peer_id),
                    next_peer_id: 1,
                };

                (proto, to_inside, from_inside)
            }
        }
    }

    pub fn run(&mut self) {
        const EVENT_CAPACITY: usize = 32;
        let mut events = Events::with_capacity(EVENT_CAPACITY);
        loop {
            self.poll.poll(&mut events, None).unwrap();
            for event in events.iter() {
                match event.token() {
                    OUTSIDE_MSG => {
                        loop {
                            match self.receiver.try_recv() {
                                Ok(msg) => self._handle_outside_msg(msg),
                                _ => break,
                            }
                        }
                    }
                    _ => self._handle_socket_event(event),
                }
            }
            self.handler.on_loop();
        }
    }

    fn _get_stream_id(&self, token: Token) -> Option<StreamId> {
        Some(match token {
            Token(id) => id as StreamId,
        })
    }

    fn _perform_action(&mut self, action: PeerAction) {
        let id = action.0;
        match action.1 {
            PeerStreamAction::Nothing => (),
            PeerStreamAction::SendMessages(msgs) => {
                for msg in msgs {
                    info!("Writing message {:?}", msg);
                    let bytes: Vec<u8> = msg.into();
                    match self.streams.get_mut(&id) {
                        Some(&mut (_, ref mut peer)) => {
                            peer.write_out(bytes);
                        }
                        None => {
                            // this peer already disconnected
                        }
                    }
                }
            }
            PeerStreamAction::Disconnect => {
                self.streams.remove(&id);
            }
        }
    }

    fn _handle_socket_event(&mut self, event: Event) {
        let kind = event.kind();
        let peer_id: StreamId = match self._get_stream_id(event.token()) {
            Some(p_id) => p_id,
            None => return,
        };

        if let Some((mut tcp_stream, mut peer_stream)) = self.streams.remove(&peer_id) {
            info!("Got event {:?} from peer id {}", event, peer_id);
            let read_result =
                Protocol::_handle_read(&mut tcp_stream, &mut peer_stream, &mut self.handler);

            match read_result.0 {
                Some(action) => self._perform_action(action),
                None => (),
            }

            self.stats.uploaded += read_result.1;

            let mut fatal_error_happened = false;
            if kind.is_writable() {
                // write pending messages
                let write_result =
                    Protocol::_handle_write(&mut tcp_stream, &mut peer_stream, &mut self.handler);

                if write_result.is_err() {
                    fatal_error_happened = true;
                }
            }

            if kind.is_hup() || kind.is_error() || fatal_error_happened {
                info!("Disconnected from peer id {}", peer_stream.id);
                self.poll.deregister(&tcp_stream);
                Protocol::_handle_hup(&mut tcp_stream, &mut peer_stream, &mut self.handler);

                // do not return socket to collection
                return;
            }

            self.streams.insert(peer_stream.id, (tcp_stream, peer_stream));
        }

    }

    fn _handle_read(socket: &mut TcpStream,
                    peer: &mut PeerStream,
                    handler: &mut PeerServer)
                    -> (Option<PeerAction>, usize) {
        let mut buf = Vec::new();
        let bytes_read = match socket.read(&mut buf) {
            Ok(bytes_read) => {
                peer.write_in(buf);
                info!("Read {} bytes from {}", bytes_read, peer.id);//, socket.peer_addr());
                bytes_read
            }
            _ => 0,
        };

        let action = match peer.message() {
            Some(msg) => {
                info!("Received from peer {:?}", msg);
                Some(handler.on_message_receive(peer.id, msg))
            }
            _ => return (None, bytes_read),
        };

        info!("Read {} bytes", bytes_read);

        (action, bytes_read)
    }

    fn _handle_write(socket: &mut TcpStream,
                     peer: &mut PeerStream,
                     handler: &mut PeerServer)
                     -> io::Result<usize> {
        peer.take(socket)
    }

    fn _handle_hup(socket: &mut TcpStream, peer: &mut PeerStream, handler: &mut PeerServer) {
        handler.on_peer_disconnect(peer.id);
    }

    fn _handle_outside_msg(&mut self, msg: ChanMsg) {
        match msg {
            ChanMsg::NewPeer(ip, port) => self._handle_new_peer(ip, port),
            ChanMsg::StatsRequest => {
                self.sender.send(ChanMsg::StatsResponse(self.stats));
            }
            _ => (),
        }
    }

    fn _handle_new_peer(&mut self, addr: IpAddr, port: u16) {
        for (id, &(ref socket, _)) in &self.streams {
            match (socket.peer_addr(), addr) {
                (Ok(SocketAddr::V4(peer)), IpAddr::V4(p)) => {
                    if peer.port() == port && peer.ip().octets() == p.octets() {
                        return;
                    }
                }
                (Ok(SocketAddr::V6(peer)), IpAddr::V6(p)) => unimplemented!(),
                (Err(e), _) => {
                    continue;
                }
                _ => continue,
            }
        }

        match self._connect_to_peer(addr, port) {
            Some(sock) => {
                let id = self.next_peer_id as u32;
                self.streams.insert(id, (sock, PeerStream::new(id)));
                let action = self.handler.on_peer_connect(id);
                self._perform_action(action);
                self.next_peer_id += 1;
            }
            None => (),
        }
    }

    fn _connect_to_peer(&mut self, addr: IpAddr, port: u16) -> Option<TcpStream> {
        let sock_addr = SocketAddr::new(addr, port);
        info!("Trying to connect to {} on port {}", addr, port);
        match TcpStream::connect(&sock_addr) {
            Ok(sock) => {
                self.poll
                    .register(&sock,
                              Token(self.next_peer_id),
                              Ready::all(),
                              PollOpt::edge());
                return Some(sock);
            },
            Err(e) => {
                info!("Could not connect: {}", e);
                return None;
            }
        }
    }
}
<commit_msg>Add some logging<commit_after>use mio::*;
use mio::tcp::TcpStream;
use mio::channel::channel;
use mio::channel::{Sender, Receiver};
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::SocketAddr;
use std::io::{Read, Write};
use std::io;
use std::error::Error;
use metainfo::MetaInfo;
use metainfo::SHA1Hash20b;

use wire::handler::{ServerHandler, BasicHandler, PeerHandler, PeerAction, PeerStreamAction};
use wire::data::{PeerMsg, parse_peermsg};
use wire::protocol_handler::PeerServer;

const OUTSIDE_MSG: Token = Token(0);
type StreamId = u32;

pub struct Protocol {
    streams: HashMap<StreamId, (TcpStream, PeerStream)>,
    handler: PeerServer,
    poll: Poll,
    sender: Sender<ChanMsg>,
    receiver: Receiver<ChanMsg>,
    info: MetaInfo,
    info_hash: SHA1Hash20b,
    pending_actions: Vec<PeerAction>,
    stats: Stats,
    next_peer_id: usize,
}

struct PeerStream {
    id: StreamId,
    bytes_in: Vec<u8>,
    bytes_out: Vec<u8>,
    handshake_sent: bool,
    handshake_received: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct Stats {
    pub uploaded: usize,
    pub downloaded: usize,
    pub peer_count: usize,
}

impl Stats {
    pub fn new() -> Stats {
        Stats {
            uploaded: 0,
            downloaded: 0,
            peer_count: 0,
        }
    }
}

impl PeerStream {
    fn new(id: StreamId) -> PeerStream {
        PeerStream {
            id: id,
            bytes_in: Vec::new(),
            bytes_out: Vec::new(),
            handshake_sent: false,
            handshake_received: false,
        }
    }

    fn write_in(&mut self, mut bytes: Vec<u8>) {
        self.bytes_in.append(&mut bytes);
    }

    fn write_out(&mut self, mut bytes: Vec<u8>) {
        println!("This goes out {:?}", bytes);
        self.bytes_out.append(&mut bytes);
    }

    fn message(&mut self) -> Option<PeerMsg> {
        if self.bytes_in.len() == 0 {
            return None;
        }

        match parse_peermsg(&self.bytes_in) {
            Ok((msg, offset)) => {
                if offset < self.bytes_in.len() {
                    self.bytes_in.split_off(offset);
                } else {
                    self.bytes_in = Vec::new();
                }
                Some(msg)
            }
            Err(_) => {
                // TODO It needs to distinguish between recoverable and non-recoverable
                None
            }
        }
    }

    fn take(&mut self, out: &mut Write) -> io::Result<usize> {
        const MAX_BYTES_WRITE: usize = 1024 * 128;
        info!("Attempting to write {} bytes", self.bytes_out.len());
        let result = out.write(&self.bytes_out);
        match result {
            Ok(offset) => {
                info!("Wrote {} bytes", offset);
                self.bytes_out = self.bytes_out.split_off(offset);
            }
            Err(ref err) => {
                info!("Writing failed: {}", err);
            }
        };
        result
    }
}

#[derive(Debug)]
pub enum ChanMsg {
    NewPeer(IpAddr, u16),
    StatsRequest,
    StatsResponse(Stats),
}

impl Protocol {
    pub fn new(info: &MetaInfo,
               hash: SHA1Hash20b,
               our_peer_id: &str)
               -> (Protocol, Sender<ChanMsg>, Receiver<ChanMsg>) {
        let poll = Poll::new().unwrap();

        match (channel(), channel()) {
            ((to_inside, from_outside), (to_outside, from_inside)) => {

                poll.register(&from_outside,
                              OUTSIDE_MSG,
                              Ready::readable(),
                              PollOpt::level())
                    .unwrap();

                let proto = Protocol {
                    streams: HashMap::new(),
                    poll: poll,
                    sender: to_outside,
                    receiver: from_outside,
                    info: info.clone(),
                    info_hash: hash.clone(),
                    pending_actions: Vec::new(),
                    stats: Stats::new(),
                    handler: ServerHandler::new(info.clone(), hash.clone(), our_peer_id),
                    next_peer_id: 1,
                };

                (proto, to_inside, from_inside)
            }
        }
    }

    pub fn run(&mut self) {
        const EVENT_CAPACITY: usize = 32;
        let mut events = Events::with_capacity(EVENT_CAPACITY);
        loop {
            self.poll.poll(&mut events, None).unwrap();
            for event in events.iter() {
                match event.token() {
                    OUTSIDE_MSG => {
                        loop {
                            match self.receiver.try_recv() {
                                Ok(msg) => self._handle_outside_msg(msg),
                                _ => break,
                            }
                        }
                    }
                    _ => self._handle_socket_event(event),
                }
            }
            self.handler.on_loop();
        }
    }

    fn _get_stream_id(&self, token: Token) -> Option<StreamId> {
        Some(match token {
            Token(id) => id as StreamId,
        })
    }

    fn _perform_action(&mut self, action: PeerAction) {
        let id = action.0;
        match action.1 {
            PeerStreamAction::Nothing => (),
            PeerStreamAction::SendMessages(msgs) => {
                for msg in msgs {
                    info!("Writing message {:?}", msg);
                    let bytes: Vec<u8> = msg.into();
                    match self.streams.get_mut(&id) {
                        Some(&mut (_, ref mut peer)) => {
                            peer.write_out(bytes);
                        }
                        None => {
                            // this peer already disconnected
                        }
                    }
                }
            }
            PeerStreamAction::Disconnect => {
                self.streams.remove(&id);
            }
        }
    }

    fn _handle_socket_event(&mut self, event: Event) {
        let kind = event.kind();
        let peer_id: StreamId = match self._get_stream_id(event.token()) {
            Some(p_id) => p_id,
            None => return,
        };

        if let Some((mut tcp_stream, mut peer_stream)) = self.streams.remove(&peer_id) {
            info!("Got event {:?} from peer id {}", event, peer_id);
            let read_result =
                Protocol::_handle_read(&mut tcp_stream, &mut peer_stream, &mut self.handler);

            match read_result.0 {
                Some(action) => self._perform_action(action),
                None => (),
            }

            self.stats.uploaded += read_result.1;

            let mut fatal_error_happened = false;
            if kind.is_writable() {
                // write pending messages
                let write_result =
                    Protocol::_handle_write(&mut tcp_stream, &mut peer_stream, &mut self.handler);

                if write_result.is_err() {
                    fatal_error_happened = true;
                }
            }

            if kind.is_hup() || kind.is_error() || fatal_error_happened {
                info!("Disconnected from peer id {}", peer_stream.id);
                self.poll.deregister(&tcp_stream);
                Protocol::_handle_hup(&mut tcp_stream, &mut peer_stream, &mut self.handler);

                // do not return socket to collection
                return;
            }

            self.streams.insert(peer_stream.id, (tcp_stream, peer_stream));
        }

    }

    fn _handle_read(socket: &mut TcpStream,
                    peer: &mut PeerStream,
                    handler: &mut PeerServer)
                    -> (Option<PeerAction>, usize) {
        let mut buf = Vec::new();
        let bytes_read = match socket.read(&mut buf) {
            Ok(bytes_read) => {
                peer.write_in(buf);
                info!("Read {} bytes from {}", bytes_read, peer.id);//, socket.peer_addr());
                bytes_read
            }
            _ => 0,
        };

        let action = match peer.message() {
            Some(msg) => {
                info!("Received from peer {:?}", msg);
                Some(handler.on_message_receive(peer.id, msg))
            }
            _ => return (None, bytes_read),
        };

        info!("Read {} bytes", bytes_read);

        (action, bytes_read)
    }

    fn _handle_write(socket: &mut TcpStream,
                     peer: &mut PeerStream,
                     handler: &mut PeerServer)
                     -> io::Result<usize> {
        peer.take(socket)
    }

    fn _handle_hup(socket: &mut TcpStream, peer: &mut PeerStream, handler: &mut PeerServer) {
        handler.on_peer_disconnect(peer.id);
    }

    fn _handle_outside_msg(&mut self, msg: ChanMsg) {
        match msg {
            ChanMsg::NewPeer(ip, port) => self._handle_new_peer(ip, port),
            ChanMsg::StatsRequest => {
                self.sender.send(ChanMsg::StatsResponse(self.stats));
            }
            _ => (),
        }
    }

    fn _handle_new_peer(&mut self, addr: IpAddr, port: u16) {
        for (id, &(ref socket, _)) in &self.streams {
            match (socket.peer_addr(), addr) {
                (Ok(SocketAddr::V4(peer)), IpAddr::V4(p)) => {
                    if peer.port() == port && peer.ip().octets() == p.octets() {
                        return;
                    }
                }
                (Ok(SocketAddr::V6(peer)), IpAddr::V6(p)) => unimplemented!(),
                (Err(e), _) => {
                    continue;
                }
                _ => continue,
            }
        }

        match self._connect_to_peer(addr, port) {
            Some(sock) => {
                let id = self.next_peer_id as u32;
                self.streams.insert(id, (sock, PeerStream::new(id)));
                let action = self.handler.on_peer_connect(id);
                self._perform_action(action);
                self.next_peer_id += 1;
            }
            None => (),
        }
    }

    fn _connect_to_peer(&mut self, addr: IpAddr, port: u16) -> Option<TcpStream> {
        let sock_addr = SocketAddr::new(addr, port);
        info!("Trying to connect to {} on port {}", addr, port);
        match TcpStream::connect(&sock_addr) {
            Ok(sock) => {
                self.poll
                    .register(&sock,
                              Token(self.next_peer_id),
                              Ready::all(),
                              PollOpt::edge());
                return Some(sock);
            },
            Err(e) => {
                info!("Could not connect: {}", e);
                return None;
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::Duration;

fn main() {
    let simulated_user_specified_value = 3;
    let simulated_random_number = 4;

    generate_workout(simulated_user_specified_value, simulated_random_number);
}

fn simulated_expensive_calculation(intensity: i32) -> i32 {
    println!("Very expensive calculation...");
    thread::sleep(Duration::from_secs(2));
    intensity
}

fn generate_workout(intensity: i32, random_number: i32) {
    let expensive_result = simulated_expensive_calculation(intensity);

    if intensity < 25 {
        println!("Do {} pushups!", expensive_result);
        println!("Next, do {} situps!", expensive_result);
    } else {
        if random_number == 3 {
            println!("Take a break!");
        } else {
            println!("Run for {} minutes!", expensive_result);
        }
    }
}<commit_msg>Refactor to closure<commit_after>use std::thread;
use std::time::Duration;

fn main() {
    let simulated_user_specified_value = 3;
    let simulated_random_number = 4;

    generate_workout(simulated_user_specified_value, simulated_random_number);
}

fn simulated_expensive_calculation(intensity: i32) -> i32 {
    println!("Very expensive calculation...");
    thread::sleep(Duration::from_secs(2));
    intensity
}

fn generate_workout(intensity: i32, random_number: i32) {
    let expensive_closure = |num| {
        println!("Very expensive calculation...");
        thread::sleep(Duration::from_secs(2));
        num
    };

    if intensity < 25 {
        println!("Do {} pushups!", expensive_closure(intensity));
        println!("Next, do {} situps!", expensive_closure(intensity));
    } else {
        if random_number == 3 {
            println!("Take a break!");
        } else {
            println!("Run for {} minutes!", expensive_closure(intensity));
        }
    }
}
<|endoftext|>


<commit_before>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

extern mod std;
extern mod extra;
extern mod zmq;

use std::comm;
use std::io;
use std::os;
use std::task;
use std::uint;

fn server(ctx: zmq::Context, ch: &comm::Chan<()>, workers: uint) {
    let mut workers = workers;

    let mut pull_socket = match ctx.socket(zmq::PULL) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    let mut push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match pull_socket.bind("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    match push_socket.bind("tcp://127.0.0.1:3457") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    // Let the main thread know we're ready.
    ch.send(());

    let mut count = 0u;
    while workers != 0 {
        match unsafe { pull_socket.recv(0) } {
            Err(e) => fail!(e.to_str()),
            Ok(msg) => {
                do msg.with_str |s| {
                    if s == "" {
                        workers -= 1;
                    } else {
                        count += uint::from_str(s).get();
                    }
                }
            }
        }
    }

    match push_socket.send_str(count.to_str(), 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    pull_socket.close();
    push_socket.close();

    ch.send(());
}

fn worker(ctx: zmq::Context, count: uint) {
    let mut push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match push_socket.connect("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    for count.times {
        match push_socket.send_str(100u.to_str(), 0) {
          Ok(()) => { }
          Err(e) => fail!(e.to_str()),
        }
    }

    // Let the server know we're done.
    match push_socket.send_str("", 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    push_socket.close();
}

fn run(ctx: zmq::Context, size: uint, workers: uint) {
    // Spawn the server.
    let (po, ch) = comm::stream();
    do task::spawn_sched(task::SingleThreaded) {
        server(ctx, &ch, workers);
    }

    // Wait for the server to start.
    po.recv();

    // Create some command/control sockets.
    let push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match push_socket.connect("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    let pull_socket = match ctx.socket(zmq::PULL) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match pull_socket.connect("tcp://127.0.0.1:3457") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    let start = extra::time::precise_time_s();

    // Spawn all the workers.
    let mut worker_results = ~[];

    for workers.times {
        let (po, ch) = comm::stream();

        worker_results.push(po);

        do task::spawn_sched(task::SingleThreaded) {
            worker(ctx, size / workers);
            ch.send(());
        }
    }

    // Block until all the workers finish.
    for worker_results.each |po| { po.recv(); }

    /*
    // Shut down the server.
    push_socket.send_str("stop", 0);
    match push_socket.close() {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }
    */

    po.recv();

    // Receive the final count.
    let result = match unsafe { pull_socket.recv(0) } {
        Ok(msg) => msg.with_str(|s| uint::from_str(s).get()),
        Err(e) => fail!(e.to_str()),
    };

    let end = extra::time::precise_time_s();
    let elapsed = end - start;

    io::println(fmt!("Count is %?", result));
    io::println(fmt!("Test took %? seconds", elapsed));
    let thruput = ((size / workers * workers) as float) / (elapsed as float);
    io::println(fmt!("Throughput=%f per sec", thruput));
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        ~[~"", ~"1000000", ~"10000"]
    } else if args.len() <= 1u {
        ~[~"", ~"10000", ~"4"]
    } else {
        args
    };

    let size = uint::from_str(args[1]).get();
    let workers = uint::from_str(args[2]).get();

    let ctx = match zmq::init(1) {
        Ok(ctx) => ctx,
        Err(e) => fail!(e.to_str()),
    };

    run(ctx, size, workers);

    match ctx.term() {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    };
}
<commit_msg>Update example<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

extern mod std;
extern mod extra;
extern mod zmq;

use std::comm;
use std::io;
use std::os;
use std::task;
use std::uint;

fn server(ctx: zmq::Context, ch: &comm::Chan<()>, workers: uint) {
    let mut workers = workers;

    let mut pull_socket = match ctx.socket(zmq::PULL) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    let mut push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match pull_socket.bind("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    match push_socket.bind("tcp://127.0.0.1:3457") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    // Let the main thread know we're ready.
    ch.send(());

    let mut count = 0u;
    while workers != 0 {
        match unsafe { pull_socket.recv(0) } {
            Err(e) => fail!(e.to_str()),
            Ok(msg) => {
                do msg.with_str |s| {
                    if s == "" {
                        workers -= 1;
                    } else {
                        count += uint::from_str(s).get();
                    }
                }
            }
        }
    }

    match push_socket.send_str(count.to_str(), 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    pull_socket.close();
    push_socket.close();

    ch.send(());
}

fn worker(ctx: zmq::Context, count: uint) {
    let mut push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match push_socket.connect("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    for count.times {
        match push_socket.send_str(100u.to_str(), 0) {
          Ok(()) => { }
          Err(e) => fail!(e.to_str()),
        }
    }

    // Let the server know we're done.
    match push_socket.send_str("", 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    push_socket.close();
}

fn run(ctx: zmq::Context, size: uint, workers: uint) {
    // Spawn the server.
    let (po, ch) = comm::stream();
    do task::spawn_sched(task::SingleThreaded) {
        server(ctx, &ch, workers);
    }

    // Wait for the server to start.
    po.recv();

    // Create some command/control sockets.
    let push_socket = match ctx.socket(zmq::PUSH) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match push_socket.connect("tcp://127.0.0.1:3456") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    let pull_socket = match ctx.socket(zmq::PULL) {
        Ok(socket) => socket,
        Err(e) => fail!(e.to_str()),
    };

    match pull_socket.connect("tcp://127.0.0.1:3457") {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }

    let start = extra::time::precise_time_s();

    // Spawn all the workers.
    let mut worker_results = ~[];

    for workers.times {
        let (po, ch) = comm::stream();

        worker_results.push(po);

        do task::spawn_sched(task::SingleThreaded) {
            worker(ctx, size / workers);
            ch.send(());
        }
    }

    // Block until all the workers finish.
    for worker_results.iter().advance |po| { po.recv(); }

    /*
    // Shut down the server.
    push_socket.send_str("stop", 0);
    match push_socket.close() {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }
    */

    po.recv();

    // Receive the final count.
    let result = match unsafe { pull_socket.recv(0) } {
        Ok(msg) => msg.with_str(|s| uint::from_str(s).get()),
        Err(e) => fail!(e.to_str()),
    };

    let end = extra::time::precise_time_s();
    let elapsed = end - start;

    io::println(fmt!("Count is %?", result));
    io::println(fmt!("Test took %? seconds", elapsed));
    let thruput = ((size / workers * workers) as float) / (elapsed as float);
    io::println(fmt!("Throughput=%f per sec", thruput));
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        ~[~"", ~"1000000", ~"10000"]
    } else if args.len() <= 1u {
        ~[~"", ~"10000", ~"4"]
    } else {
        args
    };

    let size = uint::from_str(args[1]).get();
    let workers = uint::from_str(args[2]).get();

    let ctx = match zmq::init(1) {
        Ok(ctx) => ctx,
        Err(e) => fail!(e.to_str()),
    };

    run(ctx, size, workers);

    match ctx.term() {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    };
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use core::mem;
use core::marker;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<T> {
    mb: MailboxRaw,
    data_type_marker: marker::PhantomData<T>,
}

impl<T> Default for Mailbox<T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link (name = "mouros")]
extern "C" {
    fn os_mailbox_init(mb: *mut MailboxRaw,
                       msg_buf: *mut CVoid,
                       msg_buf_len: u32,
                       msg_size: u32,
                       data_added_callback: Option<extern "C" fn()>);

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<T> Mailbox<T> {
    pub fn new(buf: &mut [T]) -> Mailbox<T> {
        let mut mb = Mailbox::default();

        unsafe {
            os_mailbox_init(&mut mb.mb,
                            buf.as_mut_ptr() as *mut CVoid,
                            buf.len() as u32,
                            mem::size_of::<T>() as u32,
                            None);
        }

        mb
    }

    pub fn write(&mut self, msg: T) -> bool {
        unsafe { os_mailbox_write(&mut self.mb, &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&mut self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(&mut self.mb,
                                      msgs.as_ptr() as *const CVoid,
                                      msgs.len() as u32)
        }
    }

    pub fn read(&mut self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(&mut self.mb, &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&mut self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(&mut self.mb,
                                     out_buf.as_mut_ptr() as *mut CVoid,
                                     out_buf.len() as u32)
        }
    }

    pub unsafe fn get_raw_mb_struct(&mut self) -> *mut MailboxRaw {
        &mut self.mb
    }
}
<commit_msg>Added SPSC Rust channels<commit_after>#![allow(dead_code)]

use core::mem;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::CVoid;

#[repr(C)]
#[derive(Debug)]
pub struct MailboxRaw {
    msg_buf: *mut u8,
    msg_buf_len: u32,
    msg_size: u32,
    read_pos: u32,
    write_pos: u32,
    data_added: Option<extern "C" fn()>,
}

impl Default for MailboxRaw {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[repr(C)]
#[derive(Debug)]
pub struct Mailbox<'mem, T: 'mem> {
    mb: UnsafeCell<MailboxRaw>,
    _data: PhantomData<&'mem mut [T]>,
}

impl<'mem, T> Default for Mailbox<'mem, T> {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[link(name = "mouros")]
extern "C" {
    fn os_mailbox_init(
        mb: *mut MailboxRaw,
        msg_buf: *mut CVoid,
        msg_buf_len: u32,
        msg_size: u32,
        data_added_callback: Option<extern "C" fn()>,
    );

    fn os_mailbox_write(mb: *mut MailboxRaw, msg: *const CVoid) -> u8;

    fn os_mailbox_write_multiple(mb: *mut MailboxRaw, msgs: *const CVoid, msg_num: u32) -> u32;

    fn os_mailbox_read(mb: *mut MailboxRaw, out: *mut CVoid) -> u8;

    fn os_mailbox_read_multiple(mb: *mut MailboxRaw, out: *mut CVoid, out_msg_num: u32) -> u32;
}

impl<'mem, T> Mailbox<'mem, T> {
    pub fn new(buf: &'mem mut [T]) -> Mailbox<T> {
        let mut mb = Mailbox::default();

        unsafe {
            os_mailbox_init(
                mb.mb.get(),
                buf.as_mut_ptr() as *mut CVoid,
                buf.len() as u32,
                mem::size_of::<T>() as u32,
                None,
            );
        }

        mb
    }

    pub fn write(&self, msg: T) -> bool {
        unsafe { os_mailbox_write(self.mb.get(), &msg as *const T as *const CVoid) != 0 }
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        unsafe {
            os_mailbox_write_multiple(
                self.mb.get(),
                msgs.as_ptr() as *const CVoid,
                msgs.len() as u32,
            )
        }
    }

    pub fn read(&self) -> Option<T> {
        unsafe {
            let mut tmp = mem::zeroed();

            if os_mailbox_read(self.mb.get(), &mut tmp as *mut T as *mut CVoid) != 0 {
                Some(tmp)
            } else {
                None
            }
        }
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        unsafe {
            os_mailbox_read_multiple(
                self.mb.get(),
                out_buf.as_mut_ptr() as *mut CVoid,
                out_buf.len() as u32,
            )
        }
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get()
    }
}

pub struct RxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> RxChannelSpsc<'mb, 'mem, T> {
    pub fn read(&self) -> Option<T> {
        self.mb.read()
    }

    pub fn read_multiple(&self, out_buf: &mut [T]) -> u32 {
        self.mb.read_multiple(out_buf)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub struct TxChannelSpsc<'mb, 'mem: 'mb, T: 'mem> {
    mb: &'mb Mailbox<'mem, T>,
    _lifetime_marker: PhantomData<&'mb mut Mailbox<'mem, T>>,
}

impl<'mb, 'mem, T> TxChannelSpsc<'mb, 'mem, T> {
    pub fn write(&self, msg: T) -> bool {
        self.mb.write(msg)
    }

    pub fn write_multiple(&self, msgs: &[T]) -> u32 {
        self.mb.write_multiple(msgs)
    }

    pub unsafe fn get_raw_mailbox(&self) -> *mut MailboxRaw {
        self.mb.get_raw_mailbox()
    }
}

pub fn channel_spsc<'mb, 'mem, T>(
    mailbox: &'mb mut Mailbox<'mem, T>,
) -> (RxChannelSpsc<'mb, 'mem, T>, TxChannelSpsc<'mb, 'mem, T>) {
    (
        RxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
        TxChannelSpsc {
            mb: mailbox,
            _lifetime_marker: PhantomData,
        },
    )
}
<|endoftext|>


<commit_before>

use slice_parsers::*;
use regex::{Captures, Regex};
use std::rc::Rc;

/// A string Parser that attempts to consume the given regex
#[derive(Clone)]
pub struct RegexLiteralParser<T: Clone> {
  pub regex: Regex,
  literal: T,
}

impl<T: Clone> SliceParser for RegexLiteralParser<T> {
  type I = str;
  type O = T;

  fn parse<'a>(&self, data: &'a str) -> ParseResult<&'a str, Self::O>{
    self.regex.find(data).map(|(_, e)| (self.literal.clone(), &data[e..])).ok_or(format!("regex literal match fail"))
  }
}

impl<T: Clone> ParserCombinator for RegexLiteralParser<T> {}

pub struct RegexCapturesParser<T, F: Fn(Captures) -> T> {
  pub regex: Regex,
  f: Rc<Box<F>>
}

impl<T, F: Fn(Captures) -> T> SliceParser for RegexCapturesParser<T, F> {

  type I = str;
  type O = T;

  fn parse<'a>(&self, data: &'a str) -> ParseResult<&'a str, T> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok(((self.f)(caps), &data[e..])),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

impl<T, F: Fn(Captures) -> T> ParserCombinator for RegexCapturesParser<T, F> {}

pub fn rlit<T: Clone>(r: Regex, l: T) -> RegexLiteralParser<T> {
  RegexLiteralParser{regex: r, literal: l}
}
pub fn str_lit<T: Clone>(s: &str, l: T) -> RegexLiteralParser<T> {
  let r = format!("^{}", s);
  let regex = Regex::new(r.as_str()).unwrap();
  RegexLiteralParser{regex: regex, literal: l}
}

pub fn capture<T, F: 'static + Fn(Captures) -> T>(reg: &str, f: F) -> RegexCapturesParser<T, F> {
  let regex = Regex::new(reg).unwrap();

  RegexCapturesParser{regex: regex, f: Rc::new(Box::new(f))}
}

<commit_msg>fixing capture<commit_after>

use slice_parsers::*;
use regex::{Captures, Regex};
use std::rc::Rc;

/// A string Parser that attempts to consume the given regex
#[derive(Clone)]
pub struct RegexLiteralParser<T: Clone> {
  pub regex: Regex,
  literal: T,
}

impl<T: Clone> SliceParser for RegexLiteralParser<T> {
  type I = str;
  type O = T;

  fn parse<'a>(&self, data: &'a str) -> ParseResult<&'a str, Self::O>{
    self.regex.find(data).map(|(_, e)| (self.literal.clone(), &data[e..])).ok_or(format!("regex literal match fail"))
  }
}

impl<T: Clone> ParserCombinator for RegexLiteralParser<T> {}

pub struct RegexCapturesParser<T, F: Fn(Captures) -> T> {
  pub regex: Regex,
  f: Rc<Box<F>>
}

impl<T, F: Fn(Captures) -> T> SliceParser for RegexCapturesParser<T, F> {

  type I = str;
  type O = T;

  fn parse<'a>(&self, data: &'a str) -> ParseResult<&'a str, T> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok(((self.f)(caps), &data[e..])),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

impl<T: Clone, F: Fn(Captures) -> T> ParserCombinator for RegexCapturesParser<T, F> {}

impl<T: Clone, F: Fn(Captures) -> T> Clone for RegexCapturesParser<T, F> {

  fn clone(&self) -> Self {
    RegexCapturesParser{regex: self.regex.clone(), f: self.f.clone()}
  }
}

pub fn rlit<T: Clone>(r: Regex, l: T) -> RegexLiteralParser<T> {
  RegexLiteralParser{regex: r, literal: l}
}
pub fn str_lit<T: Clone>(s: &str, l: T) -> RegexLiteralParser<T> {
  let r = format!("^{}", s);
  let regex = Regex::new(r.as_str()).unwrap();
  RegexLiteralParser{regex: regex, literal: l}
}

pub fn capture<T, F: 'static + Fn(Captures) -> T>(reg: &str, f: F) -> RegexCapturesParser<T, F> {
  let regex = Regex::new(reg).unwrap();

  RegexCapturesParser{regex: regex, f: Rc::new(Box::new(f))}
}

<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Gamma and derived distributions.

use num::Real;
use num;
use rand::{Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::task_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
pub enum Gamma {
    priv Large(GammaLargeShape),
    priv One(Exp),
    priv Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaLargeShape {
    shape: f64,
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Fails if `shape <= 0` or `scale <= 0`.
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        match shape {
            1.0        => One(Exp::new(1.0 / scale)),
            0.0 .. 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
            _          => Large(GammaLargeShape::new_raw(shape, scale))
        }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            shape: shape,
            scale: scale,
            c: 1. / num::sqrt(9. * d),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * num::pow(u, self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                num::ln(u) < 0.5 * x_sqr + self.d * (1.0 - v + num::ln(v)) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::task_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
pub enum ChiSquared {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    priv DoFExactlyOne,
    priv DoFAnythingElse(Gamma)
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Fails if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::task_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
pub struct FisherF {
    priv numer: ChiSquared,
    priv denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    priv dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Fails if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::task_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
pub struct StudentT {
    priv chi: ChiSquared,
    priv dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Fails if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

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

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_log_normal_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}

#[cfg(test)]
mod bench {
    use extra::test::BenchHarness;
    use mem::size_of;
    use prelude::*;
    use rand::distributions::IndependentSample;
    use rand::{StdRng, RAND_BENCH_N};
    use super::*;

    #[bench]
    fn bench_gamma_large_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(10., 1.0);
        let mut rng = StdRng::new();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }

    #[bench]
    fn bench_gamma_small_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(0.1, 1.0);
        let mut rng = StdRng::new();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }
}
<commit_msg>auto merge of #11503 : FlaPer87/rust/master, r=huonw<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Gamma and derived distributions.

use num::Real;
use num;
use rand::{Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::task_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
pub enum Gamma {
    priv Large(GammaLargeShape),
    priv One(Exp),
    priv Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaLargeShape {
    shape: f64,
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Fails if `shape <= 0` or `scale <= 0`.
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        match shape {
            1.0        => One(Exp::new(1.0 / scale)),
            0.0 .. 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
            _          => Large(GammaLargeShape::new_raw(shape, scale))
        }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            shape: shape,
            scale: scale,
            c: 1. / num::sqrt(9. * d),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * num::powf(u, self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                num::ln(u) < 0.5 * x_sqr + self.d * (1.0 - v + num::ln(v)) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::task_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
pub enum ChiSquared {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    priv DoFExactlyOne,
    priv DoFAnythingElse(Gamma)
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Fails if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::task_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
pub struct FisherF {
    priv numer: ChiSquared,
    priv denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    priv dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Fails if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::task_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
pub struct StudentT {
    priv chi: ChiSquared,
    priv dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Fails if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

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

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_log_normal_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}

#[cfg(test)]
mod bench {
    use extra::test::BenchHarness;
    use mem::size_of;
    use prelude::*;
    use rand::distributions::IndependentSample;
    use rand::{StdRng, RAND_BENCH_N};
    use super::*;

    #[bench]
    fn bench_gamma_large_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(10., 1.0);
        let mut rng = StdRng::new();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }

    #[bench]
    fn bench_gamma_small_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(0.1, 1.0);
        let mut rng = StdRng::new();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

extern crate gurobi_sys as ffi;

pub use ffi::{IntAttr, DoubleAttr, CharAttr, StringAttr};
pub use ffi::IntAttr::*;
pub use ffi::DoubleAttr::*;
pub use ffi::CharAttr::*;
pub use ffi::StringAttr::*;

use error::{Error, Result};

/// provides function to query/set the value of attributes.
pub trait HasAttr<A, Output>
  where A: HasAttrAPI<Output>
{
  fn get(&self, attr: A) -> Result<Output> {
    Err(Error::NotImplemented)
    // let mut value: ffi::c_int = 0;
    // let mut value = null();

    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error =
    //   unsafe { ffi::GRBgetintattr(self.model, attrname.as_ptr(), &mut value) };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }

    // Ok(value as i32)
    // Ok(unsafe { from_c_str(value).to_owned() })
  }

  fn set(&mut self, attr: A, value: Output) -> Result<()> {
    Err(Error::NotImplemented)
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error =
    //   unsafe { ffi::GRBsetintattr(self.model, attrname.as_ptr(), value) };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(())
  }

  fn get_element(&self, attr: A, element: i32) -> Result<Output> {
    Err(Error::NotImplemented)
    // let mut value: ffi::c_int = 0;
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBgetintattrelement(self.model,
    //                             attrname.as_ptr(),
    //                             element,
    //                             &mut value)
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(value as i32)
  }

  fn set_element(&mut self,
                 attr: A,
                 element: i32,
                 value: Output)
                 -> Result<()> {
    Err(Error::NotImplemented)
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBsetintattrelement(self.model, attrname.as_ptr(), element, value)
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(())
  }

  fn get_array(&self,
               attr: A,
               first: usize,
               len: usize)
               -> Result<Vec<Output>> {
    Err(Error::NotImplemented)
    // let mut values = Vec::with_capacity(len);
    // values.resize(len, 0);
    // / values.resize(len, null());
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBgetintattrarray(self.model,
    //                           attrname.as_ptr(),
    //                           first as ffi::c_int,
    //                           len as ffi::c_int,
    //                           values.as_mut_ptr())
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(values)
    // / Ok(values.into_iter()
    // /   .map(|s| unsafe { from_c_str(s).to_owned() })
    // /   .collect())
  }

  fn set_array(&mut self,
               attr: A,
               first: usize,
               values: &[Output])
               -> Result<()> {
    Err(Error::NotImplemented)
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBsetintattrarray(self.model,
    //                           attrname.as_ptr(),
    //                           first as ffi::c_int,
    //                           values.len() as ffi::c_int,
    //                           values.as_ptr())
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(())
  }
  //     let values = values.into_iter().map(|s| make_c_str(s)).collect::<Vec<_>>();
  //     if values.iter().any(|ref s| s.is_err()) {
  //       return Err(Error::StringConversion);
  //     }
  //     let values =
  //       values.into_iter().map(|s| s.unwrap().as_ptr()).collect::<Vec<_>>();

  fn get_list(&self, attr: A, ind: &[i32]) -> Result<Vec<Output>> {
    Err(Error::NotImplemented)
    // let mut values = Vec::with_capacity(ind.len());
    // values.resize(ind.len(), 0);
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBgetintattrlist(self.model,
    //                          attrname.as_ptr(),
    //                          ind.len() as ffi::c_int,
    //                          ind.as_ptr(),
    //                          values.as_mut_ptr())
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(values)
  }

  fn set_list(&mut self, attr: A, ind: &[i32], value: &[Output]) -> Result<()> {
    Err(Error::NotImplemented)
    // if ind.len() != values.len() {
    //   return Err(Error::InconsitentDims);
    // }
    // let attrname = try!(make_c_str(format!("{:?}", attr).as_str()));
    // let error = unsafe {
    //   ffi::GRBsetintattrlist(self.model,
    //                          attrname.as_ptr(),
    //                          ind.len() as ffi::c_int,
    //                          ind.as_ptr(),
    //                          values.as_ptr())
    // };
    // if error != 0 {
    //   return Err(self.error_from_api(error));
    // }
    // Ok(())
  }
}

pub trait HasModelAPI {
  unsafe fn get_model(&self) -> *mut ffi::GRBmodel;

  // make an instance of error object related to C API.
  fn error_from_api(&self, errcode: ffi::c_int) -> Error;
}

pub trait HasAttrAPI<Output> {}

impl HasAttrAPI<i32> for IntAttr {}
impl HasAttrAPI<i8> for CharAttr {}
impl HasAttrAPI<f64> for DoubleAttr {}
impl HasAttrAPI<String> for StringAttr {}
<commit_msg>WIP: impl trait<commit_after>#![allow(unused_variables)]

extern crate gurobi_sys as ffi;

pub use ffi::{IntAttr, DoubleAttr, CharAttr, StringAttr};
pub use ffi::IntAttr::*;
pub use ffi::DoubleAttr::*;
pub use ffi::CharAttr::*;
pub use ffi::StringAttr::*;

use error::{Error, Result};

/// provides function to query/set the value of attributes.
pub trait HasAttr<A, Output>
  where A: HasAttrAPI<Output>
{
  fn get(&self, attr: A) -> Result<Output> {
    let mut value: A::init();

    let error = unsafe {
      A::get_attr(self.model,
                  CString::from(attr).as_ptr(),
                  A::as_rawget(&mut value))
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(A::to_out(value))
  }

  fn set(&mut self, attr: A, value: Output) -> Result<()> {
    let error = unsafe {
      A::set_attr(self.model,
                  CString::from(attr).as_ptr(),
                  A::to_rawset(value))
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(())
  }

  fn get_element(&self, attr: A, element: i32) -> Result<Output> {
    let mut value = A::init();

    let error = unsafe {
      A::get_attrelement(self.model,
                         CString::from(attr).as_ptr(),
                         element,
                         A::as_rawget(&mut value))
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(A::to_out(value))
  }

  fn set_element(&mut self,
                 attr: A,
                 element: i32,
                 value: Output)
                 -> Result<()> {
    let error = unsafe {
      A::set_attrelement(self.model,
                         CString::from(attr).as_ptr(),
                         element,
                         A::to_rawset(value))
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(())
  }

  fn get_array(&self,
               attr: A,
               first: usize,
               len: usize)
               -> Result<Vec<Output>> {
    let mut values = A::init_array(len);

    let error = unsafe {
      A::get_attrarray(self.model,
                       CString::from(attr).as_ptr(),
                       first as ffi::c_int,
                       len as ffi::c_int,
                       values.as_mut_ptr())
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(values.into_iter()
      .map(|s| A::to_out(s))
      .collect())
  }

  fn set_array(&mut self,
               attr: A,
               first: usize,
               values: &[Output])
               -> Result<()> {
    let values = A::to_rawsets(values);

    let error = unsafe {
      A::set_attrarray(self.model,
                       CString::from(attr).as_ptr(),
                       first as ffi::c_int,
                       values.len() as ffi::c_int,
                       values.as_ptr())
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(())
  }

  fn get_list(&self, attr: A, ind: &[i32]) -> Result<Vec<Output>> {
    let mut values = A::init_array();

    let error = unsafe {
      A::get_attrlist(self.model,
                      CString::from(attr).as_ptr(),
                      ind.len() as ffi::c_int,
                      ind.as_ptr(),
                      values.as_mut_ptr())
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(values.into_iter()
      .map(|s| A::to_out(s))
      .collect())
  }

  fn set_list(&mut self,
              attr: A,
              ind: &[i32],
              values: &[Output])
              -> Result<()> {
    if ind.len() != values.len() {
      return Err(Error::InconsitentDims);
    }

    let values = A::to_rawsets(values);

    let error = unsafe {
      A::set_attrlist(self.model,
                      attrname.as_ptr(),
                      ind.len() as ffi::c_int,
                      ind.as_ptr(),
                      values.as_ptr())
    };
    if error != 0 {
      return Err(self.error_from_api(error));
    }

    Ok(())
  }
}

pub trait HasModelAPI {
  unsafe fn get_model(&self) -> *mut ffi::GRBmodel;

  // make an instance of error object related to C API.
  fn error_from_api(&self, errcode: ffi::c_int) -> Error;
}

pub trait HasAttrAPI<Output> {
  type Init;
  type RawGet;
  type RawSet;

  fn get_attr(model: *mut ffi::GRBmodel,
              attrname: ffi::c_str,
              value: *mut Self::RawGet)
              -> ffi::c_int;

  fn set_attr(model: *mut ffi::GRBmodel,
              attrname: ffi::c_str,
              value: Self::RawSet)
              -> ffi::c_int;

  fn get_attrelement(model: *mut ffi::GRBmodel,
              attrname: ffi::c_str,
              element: ffi::c_int,
              value: *mut Self::RawGet)
              -> ffi::c_int;

  fn set_attrelement(model: *mut ffi::GRBmodel,
              attrname: ffi::c_str,
              element: ffi::c_int,
              value: Self::RawSet)
              -> ffi::c_int;

  fn init() -> Self::Init;
  // fn init() -> ffi::c_int { 0 }
  // fn init() -> ffi::c_str { null() }

  fn to_out(val: Self::Init) -> Output;
  // fn to_out(val: ffi::c_int) -> i32 { val as ffi::c_int }
  // fn to_out(val: ffi::c_str) -> String { unsafe { util::from_c_str(val).to_owned() } }

  fn as_rawget(val: &mut Self::Init) -> Self::RawGet;
  fn to_rawset(val: Output) -> Self::RawSet;

  fn init_array(len: i32) -> Vec<Self::Init> {
    std::iter::repeat(Self::init()).take(len).collect()
  }

  fn to_rawsets(values: Vec<Output>) -> Vec<Self::RawSet> {
    values
  }
  // fn to_rawsets(values: Vec<String>) -> Vec<ffi::c_str> {
  //     let values = values.into_iter().map(|s| make_c_str(s)).collect::<Vec<_>>();
  //     if values.iter().any(|ref s| s.is_err()) {
  //       return Err(Error::StringConversion);
  //     }
  //     values.into_iter().map(|s| s.unwrap().as_ptr()).collect()
  // }
}

impl HasAttrAPI<i32> for IntAttr {}
impl HasAttrAPI<i8> for CharAttr {}
impl HasAttrAPI<f64> for DoubleAttr {}
impl HasAttrAPI<String> for StringAttr {}
<|endoftext|>


<commit_before>#![cfg(test)]

use glib::translate::*;
use libc;
use std::env;
use std::path::PathBuf;
use std::sync::Once;

#[cfg(have_pangoft2)]

/// Given a filename from `test_generator::test_resources`, computes the correct fixture filename.
///
/// The `test_resources` procedural macro works by running a filename glob starting on
/// the toplevel of the Cargo workspace.  However, when a test function gets run,
/// its $cwd is the test crate's toplevel.  This function fixes the pathname generated
/// by `test_resources` so that it has the correct path.
pub fn fixture_path(filename_from_test_resources: &str) -> PathBuf {
    let crate_toplevel = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    );

    let workspace_toplevel = crate_toplevel.parent().unwrap();

    workspace_toplevel.join(filename_from_test_resources)
}

#[cfg(have_pangoft2)]
mod pango_ft2 {
    use fontconfig_sys::fontconfig;
    use glib::prelude::*;
    use pangocairo::FontMap;
    use super::*;

    extern "C" {
        // pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
	//                               FcConfig       *fcconfig);
        // This is not bound in gtk-rs, and PangoFcFontMap is not even exposed, so we'll bind it by hand.
        fn pango_fc_font_map_set_config(
            font_map: *mut libc::c_void,
            config: *mut fontconfig::FcConfig,
        );
    }

    pub unsafe fn load_test_fonts() {
        let font_paths = [
            "tests/resources/Roboto-Regular.ttf",
            "tests/resources/Roboto-Italic.ttf",
            "tests/resources/Roboto-Bold.ttf",
            "tests/resources/Roboto-BoldItalic.ttf",
        ];

        let config = fontconfig::FcConfigCreate();

        for path in &font_paths {
            let path = fixture_path(path);
            let str = path.to_str().unwrap();

            if fontconfig::FcConfigAppFontAddFile(config, str.as_ptr()) == 0 {
                panic!("Could not load font file {} for tests; aborting", str);
            }
        }

        let font_map = FontMap::new_for_font_type(cairo::FontType::FontTypeFt).unwrap();
        let raw_font_map: *mut pango_sys::PangoFontMap = font_map.to_glib_none().0;

        pango_fc_font_map_set_config (raw_font_map as *mut _, config);
        fontconfig::FcConfigDestroy(config);

        FontMap::set_default(Some(font_map.downcast::<pangocairo::FontMap>().unwrap()));
    }
}

#[cfg(have_pangoft2)]
pub fn setup_font_map() {
    static ONCE: Once = Once::new();

    ONCE.call_once(|| unsafe {
        self::pango_ft2::load_test_fonts();
    });
}

#[cfg(not(have_pangoft2))]
pub fn setup_font_map() {}
<commit_msg>Use a proper C string to pass to FcConfigAppFontAddFile<commit_after>#![cfg(test)]

use glib::translate::*;
use libc;
use std::env;
use std::ffi::CString;
use std::path::PathBuf;
use std::sync::Once;

#[cfg(have_pangoft2)]

/// Given a filename from `test_generator::test_resources`, computes the correct fixture filename.
///
/// The `test_resources` procedural macro works by running a filename glob starting on
/// the toplevel of the Cargo workspace.  However, when a test function gets run,
/// its $cwd is the test crate's toplevel.  This function fixes the pathname generated
/// by `test_resources` so that it has the correct path.
pub fn fixture_path(filename_from_test_resources: &str) -> PathBuf {
    let crate_toplevel = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    );

    let workspace_toplevel = crate_toplevel.parent().unwrap();

    workspace_toplevel.join(filename_from_test_resources)
}

#[cfg(have_pangoft2)]
mod pango_ft2 {
    use fontconfig_sys::fontconfig;
    use glib::prelude::*;
    use pangocairo::FontMap;
    use super::*;

    extern "C" {
        // pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
	//                               FcConfig       *fcconfig);
        // This is not bound in gtk-rs, and PangoFcFontMap is not even exposed, so we'll bind it by hand.
        fn pango_fc_font_map_set_config(
            font_map: *mut libc::c_void,
            config: *mut fontconfig::FcConfig,
        );
    }

    pub unsafe fn load_test_fonts() {
        let font_paths = [
            "tests/resources/Roboto-Regular.ttf",
            "tests/resources/Roboto-Italic.ttf",
            "tests/resources/Roboto-Bold.ttf",
            "tests/resources/Roboto-BoldItalic.ttf",
        ];

        let config = fontconfig::FcConfigCreate();

        for path in &font_paths {
            let path = fixture_path(path);
            let path_str = path.to_str().unwrap();
            let path_cstring = CString::new(path_str).unwrap();

            if fontconfig::FcConfigAppFontAddFile(config, path_cstring.as_ptr() as *const _) == 0 {
                panic!("Could not load font file {:?} for tests; aborting", path_str);
            }
        }

        let font_map = FontMap::new_for_font_type(cairo::FontType::FontTypeFt).unwrap();
        let raw_font_map: *mut pango_sys::PangoFontMap = font_map.to_glib_none().0;

        pango_fc_font_map_set_config (raw_font_map as *mut _, config);
        fontconfig::FcConfigDestroy(config);

        FontMap::set_default(Some(font_map.downcast::<pangocairo::FontMap>().unwrap()));
    }
}

#[cfg(have_pangoft2)]
pub fn setup_font_map() {
    static ONCE: Once = Once::new();

    ONCE.call_once(|| unsafe {
        self::pango_ft2::load_test_fonts();
    });
}

#[cfg(not(have_pangoft2))]
pub fn setup_font_map() {}
<|endoftext|>


<commit_before>//! Macro input conditioning.

use syntax::{
    ast::{self, AttrsOwner},
    AstNode, SyntaxNode,
};

use crate::{db::AstDatabase, name::AsName, AttrId, LazyMacroId, MacroCallKind, MacroCallLoc};

pub(crate) fn process_macro_input(
    db: &dyn AstDatabase,
    node: SyntaxNode,
    id: LazyMacroId,
) -> SyntaxNode {
    let loc: MacroCallLoc = db.lookup_intern_macro(id);

    match loc.kind {
        MacroCallKind::FnLike { .. } => node,
        MacroCallKind::Derive { derive_attr, .. } => {
            let item = match ast::Item::cast(node.clone()) {
                Some(item) => item,
                None => return node,
            };

            remove_derives_up_to(item, derive_attr).syntax().clone()
        }
    }
}

/// Removes `#[derive]` attributes from `item`, up to `attr`.
fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item {
    let item = item.clone_for_update();
    let idx = attr.0 as usize;
    for attr in item.attrs().take(idx + 1) {
        if let Some(name) =
            attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref())
        {
            if name.as_name().to_string() == "derive" {
                attr.syntax().detach();
            }
        }
    }
    item
}

#[cfg(test)]
mod tests {
    use base_db::fixture::WithFixture;
    use base_db::SourceDatabase;
    use expect_test::{expect, Expect};

    use crate::test_db::TestDB;

    use super::*;

    fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) {
        let (db, file_id) = TestDB::with_single_file(&ra_fixture);
        let parsed = db.parse(file_id);

        let mut items: Vec<_> =
            parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
        assert_eq!(items.len(), 1);

        let item = remove_derives_up_to(items.pop().unwrap(), attr);
        expect.assert_eq(&item.to_string());
    }

    #[test]
    fn remove_derive() {
        test_remove_derives_up_to(
            AttrId(2),
            r#"
#[allow(unused)]
#[derive(Copy)]
#[derive(Hello)]
#[derive(Clone)]
struct A {
    bar: u32
}
        "#,
            expect![[r#"
#[allow(unused)]

#[derive(Clone)]
struct A {
    bar: u32
}"#]],
        );
    }
}
<commit_msg>Revert "Use `pub(crate)`"<commit_after>//! Macro input conditioning.

use syntax::{
    ast::{self, AttrsOwner},
    AstNode, SyntaxNode,
};

use crate::{db::AstDatabase, name::AsName, AttrId, LazyMacroId, MacroCallKind, MacroCallLoc};

pub fn process_macro_input(db: &dyn AstDatabase, node: SyntaxNode, id: LazyMacroId) -> SyntaxNode {
    let loc: MacroCallLoc = db.lookup_intern_macro(id);

    match loc.kind {
        MacroCallKind::FnLike { .. } => node,
        MacroCallKind::Derive { derive_attr, .. } => {
            let item = match ast::Item::cast(node.clone()) {
                Some(item) => item,
                None => return node,
            };

            remove_derives_up_to(item, derive_attr).syntax().clone()
        }
    }
}

/// Removes `#[derive]` attributes from `item`, up to `attr`.
fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item {
    let item = item.clone_for_update();
    let idx = attr.0 as usize;
    for attr in item.attrs().take(idx + 1) {
        if let Some(name) =
            attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref())
        {
            if name.as_name().to_string() == "derive" {
                attr.syntax().detach();
            }
        }
    }
    item
}

#[cfg(test)]
mod tests {
    use base_db::fixture::WithFixture;
    use base_db::SourceDatabase;
    use expect_test::{expect, Expect};

    use crate::test_db::TestDB;

    use super::*;

    fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) {
        let (db, file_id) = TestDB::with_single_file(&ra_fixture);
        let parsed = db.parse(file_id);

        let mut items: Vec<_> =
            parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
        assert_eq!(items.len(), 1);

        let item = remove_derives_up_to(items.pop().unwrap(), attr);
        expect.assert_eq(&item.to_string());
    }

    #[test]
    fn remove_derive() {
        test_remove_derives_up_to(
            AttrId(2),
            r#"
#[allow(unused)]
#[derive(Copy)]
#[derive(Hello)]
#[derive(Clone)]
struct A {
    bar: u32
}
        "#,
            expect![[r#"
#[allow(unused)]

#[derive(Clone)]
struct A {
    bar: u32
}"#]],
        );
    }
}
<|endoftext|>


<commit_before>//! KDE Window decoration manager
//!
//! This interface allows a compositor to announce support for KDE's legacy server-side decorations.
//!
//! A client can use this protocol to request being decorated by a supporting compositor.
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::delegate_kde_decoration;
//! use smithay::wayland::shell::kde::decoration::{KdeDecorationHandler, KdeDecorationState};
//!
//! # struct State { kde_decoration_state: KdeDecorationState };
//! # let mut display = wayland_server::Display::<State>::new().unwrap();
//!
//! // Create the new KdeDecorationState.
//! let state = KdeDecorationState::new::<State, _>(&display.handle(), None);
//!
//! // Insert KdeDecorationState into your compositor state.
//! // …
//!
//! // Implement KDE server decoration handlers.
//! impl KdeDecorationHandler for State {
//!     fn kde_decoration_state(&self) -> &KdeDecorationState {
//!         &self.kde_decoration_state
//!     }
//! }
//!
//! delegate_kde_decoration!(State);
//! ```

use slog::Logger;
use wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::{
    Mode, OrgKdeKwinServerDecoration,
};
use wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager;
use wayland_server::backend::GlobalId;
use wayland_server::protocol::wl_surface::WlSurface;
use wayland_server::{Dispatch, DisplayHandle, GlobalDispatch, WEnum};

/// KDE server decoration handler.
pub trait KdeDecorationHandler {
    /// Return the KDE server decoration state.
    fn kde_decoration_state(&self) -> &KdeDecorationState;

    /// Handle decoration manager creation.
    ///
    /// Allows setting up the decoration manager, like setting the default decoration mode using
    /// [`OrgKdeKwinServerDecorationManager::default_mode`].
    fn setup(&mut self, _kde_decoration_manager: &OrgKdeKwinServerDecorationManager) {}

    /// Handle new decoration object creation.
    ///
    /// Called whenever a new decoration object is created, usually this happens when a new window
    /// is opened.
    fn new_decoration(&mut self, _surface: &WlSurface, _decoration: &OrgKdeKwinServerDecoration) {}

    /// Handle surface decoration mode requests.
    ///
    /// Called when a surface requests a specific decoration mode or acknowledged the compositor's
    /// decoration request.
    ///
    /// **It is up to the compositor to prevent feedback loops**, a client is free to ignore modes
    /// suggested by [`OrgKdeKwinServerDecoration::mode`] and instead keep requesting their
    /// preferred mode instead.
    fn request_mode(
        &mut self,
        _surface: &WlSurface,
        _decoration: &OrgKdeKwinServerDecoration,
        _mode: WEnum<Mode>,
    ) {
    }

    /// Handle decoration object removal for a surface.
    fn release(&mut self, _surface: &WlSurface) {}
}

/// KDE server decoration state.
#[derive(Debug)]
pub struct KdeDecorationState {
    pub(crate) logger: Logger,
    kde_decoration_manager: GlobalId,
}

impl KdeDecorationState {
    /// Create a new KDE server decoration global.
    pub fn new<D, L>(display: &DisplayHandle, logger: L) -> Self
    where
        D: GlobalDispatch<OrgKdeKwinServerDecorationManager, ()>
            + Dispatch<OrgKdeKwinServerDecorationManager, ()>
            + Dispatch<OrgKdeKwinServerDecoration, WlSurface>
            + KdeDecorationHandler
            + 'static,
        L: Into<Option<Logger>>,
    {
        let kde_decoration_manager = display.create_global::<D, OrgKdeKwinServerDecorationManager, _>(1, ());
        let logger =
            crate::slog_or_fallback(logger).new(slog::o!("smithay_module" => "kde_decoration_handler"));

        Self {
            kde_decoration_manager,
            logger,
        }
    }

    /// Returns the id of the [`OrgKdeKwinServerDecorationManager`] global.
    pub fn global(&self) -> GlobalId {
        self.kde_decoration_manager.clone()
    }
}

#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_kde_decoration {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager: ()
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager: ()
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::OrgKdeKwinServerDecoration: $crate::reexports::wayland_server::protocol::wl_surface::WlSurface
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);
    };
}
<commit_msg>Confirm all mode requests by default<commit_after>//! KDE Window decoration manager
//!
//! This interface allows a compositor to announce support for KDE's legacy server-side decorations.
//!
//! A client can use this protocol to request being decorated by a supporting compositor.
//!
//! ```
//! extern crate wayland_server;
//! extern crate smithay;
//!
//! use smithay::delegate_kde_decoration;
//! use smithay::wayland::shell::kde::decoration::{KdeDecorationHandler, KdeDecorationState};
//!
//! # struct State { kde_decoration_state: KdeDecorationState };
//! # let mut display = wayland_server::Display::<State>::new().unwrap();
//!
//! // Create the new KdeDecorationState.
//! let state = KdeDecorationState::new::<State, _>(&display.handle(), None);
//!
//! // Insert KdeDecorationState into your compositor state.
//! // …
//!
//! // Implement KDE server decoration handlers.
//! impl KdeDecorationHandler for State {
//!     fn kde_decoration_state(&self) -> &KdeDecorationState {
//!         &self.kde_decoration_state
//!     }
//! }
//!
//! delegate_kde_decoration!(State);
//! ```

use slog::Logger;
use wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::{
    Mode, OrgKdeKwinServerDecoration,
};
use wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager;
use wayland_server::backend::GlobalId;
use wayland_server::protocol::wl_surface::WlSurface;
use wayland_server::{Dispatch, DisplayHandle, GlobalDispatch, WEnum};

/// KDE server decoration handler.
pub trait KdeDecorationHandler {
    /// Return the KDE server decoration state.
    fn kde_decoration_state(&self) -> &KdeDecorationState;

    /// Handle decoration manager creation.
    ///
    /// Allows setting up the decoration manager, like setting the default decoration mode using
    /// [`OrgKdeKwinServerDecorationManager::default_mode`].
    fn setup(&mut self, _kde_decoration_manager: &OrgKdeKwinServerDecorationManager) {}

    /// Handle new decoration object creation.
    ///
    /// Called whenever a new decoration object is created, usually this happens when a new window
    /// is opened.
    fn new_decoration(&mut self, _surface: &WlSurface, _decoration: &OrgKdeKwinServerDecoration) {}

    /// Handle surface decoration mode requests.
    ///
    /// Called when a surface requests a specific decoration mode or acknowledged the compositor's
    /// decoration request.
    ///
    /// **It is up to the compositor to prevent feedback loops**, a client is free to ignore modes
    /// suggested by [`OrgKdeKwinServerDecoration::mode`] and instead request their preferred mode
    /// instead.
    fn request_mode(
        &mut self,
        _surface: &WlSurface,
        decoration: &OrgKdeKwinServerDecoration,
        mode: WEnum<Mode>,
    ) {
        if let WEnum::Value(mode) = mode {
            decoration.mode(mode);
        }
    }

    /// Handle decoration object removal for a surface.
    fn release(&mut self, _surface: &WlSurface) {}
}

/// KDE server decoration state.
#[derive(Debug)]
pub struct KdeDecorationState {
    pub(crate) logger: Logger,
    kde_decoration_manager: GlobalId,
}

impl KdeDecorationState {
    /// Create a new KDE server decoration global.
    pub fn new<D, L>(display: &DisplayHandle, logger: L) -> Self
    where
        D: GlobalDispatch<OrgKdeKwinServerDecorationManager, ()>
            + Dispatch<OrgKdeKwinServerDecorationManager, ()>
            + Dispatch<OrgKdeKwinServerDecoration, WlSurface>
            + KdeDecorationHandler
            + 'static,
        L: Into<Option<Logger>>,
    {
        let kde_decoration_manager = display.create_global::<D, OrgKdeKwinServerDecorationManager, _>(1, ());
        let logger =
            crate::slog_or_fallback(logger).new(slog::o!("smithay_module" => "kde_decoration_handler"));

        Self {
            kde_decoration_manager,
            logger,
        }
    }

    /// Returns the id of the [`OrgKdeKwinServerDecorationManager`] global.
    pub fn global(&self) -> GlobalId {
        self.kde_decoration_manager.clone()
    }
}

#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_kde_decoration {
    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager: ()
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::OrgKdeKwinServerDecorationManager: ()
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);

        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
            $crate::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::OrgKdeKwinServerDecoration: $crate::reexports::wayland_server::protocol::wl_surface::WlSurface
        ] => $crate::wayland::shell::kde::decoration::KdeDecorationState);
    };
}
<|endoftext|>