<commit_before>extern crate byteorder;
extern crate tempfile;
#[macro_use]
extern crate wayland_client;
extern crate wayland_protocols;
extern crate wayland_window;

use byteorder::{WriteBytesExt, NativeEndian};

use std::fs::File;
use std::io::Write;
use std::os::unix::io::AsRawFd;

use tempfile::tempfile;

use wayland_client::{EventQueueHandle, EnvHandler, Proxy};
use wayland_client::protocol::{wl_shell, wl_surface, wl_shm_pool, wl_buffer, wl_compositor,
                               wl_subcompositor, wl_shm};

use wayland_window::DecoratedSurface;

wayland_env!(WaylandEnv,
    compositor: wl_compositor::WlCompositor,
    subcompositor: wl_subcompositor::WlSubcompositor,
    shm: wl_shm::WlShm
);

struct Window {
    s: wl_surface::WlSurface,
    tmp: File,
    pool: wl_shm_pool::WlShmPool,
    pool_size: usize,
    buf: wl_buffer::WlBuffer,
    newsize: Option<(i32, i32)>
}

impl wayland_window::Handler for Window {
    fn configure(&mut self, _: &mut EventQueueHandle, _conf: wayland_window::Configure, width: i32, height: i32) {
        let w = std::cmp::max(width, 100);
        let h = std::cmp::max(height, 100);
        println!("configure: {:?}", (w, h));
        self.newsize = Some((w, h))
    }
    fn close(&mut self, _: &mut EventQueueHandle) {
        println!("close window");
    }
}

impl Window {
    fn resize(&mut self, width: i32, height: i32) {
        if (width*height*4) as usize > self.pool_size {
            // need to reallocate a bigger buffer
            for _ in 0..((width*height) as usize - self.pool_size / 4) {
                self.tmp.write_u32::<NativeEndian>(0xFF880000).unwrap();
            }
            self.pool.resize(width*height*4);
            self.pool_size = (width*height*4) as usize;
        }
        self.buf.destroy();
        self.buf = self.pool.create_buffer(0, width, height, width*4, wl_shm::Format::Argb8888).expect("Pool should not be dead!");
        self.s.attach(Some(&self.buf), 0, 0);
        self.s.commit();
    }
}

fn main() {
    let (display, mut event_queue) = match wayland_client::default_connect() {
        Ok(ret) => ret,
        Err(e) => panic!("Cannot connect to wayland server: {:?}", e)
    };

    event_queue.add_handler(EnvHandler::<WaylandEnv>::new());
    let registry = display.get_registry();
    event_queue.register::<_, EnvHandler<WaylandEnv>>(&registry, 0);
    event_queue.sync_roundtrip().unwrap();

    // Use `xdg-shell` if its available. Otherwise, fall back to `wl-shell`.
    let (mut xdg_shell, mut wl_shell) = (None, None);
    {
        let state = event_queue.state();
        let env = state.get_handler::<EnvHandler<WaylandEnv>>(0);
        for &(name, ref interface, version) in env.globals() {
            use wayland_protocols::unstable::xdg_shell::client::zxdg_shell_v6::ZxdgShellV6;
            if interface == ZxdgShellV6::interface_name() {
                xdg_shell = Some(registry.bind::<ZxdgShellV6>(version, name));
                break;
            }
        }

        if xdg_shell.is_none() {
            for &(name, ref interface, version) in env.globals() {
                if interface == wl_shell::WlShell::interface_name() {
                    wl_shell = Some(registry.bind::<wl_shell::WlShell>(version, name));
                    break;
                }
            }
        }
    }

    let shell = match (xdg_shell, wl_shell) {
        (Some(shell), _) => {
            wayland_window::Shell::Xdg(shell)
        },
        (_, Some(shell)) => {
            wayland_window::Shell::Wl(shell)
        },
        _ => panic!("No available shell"),
    };

    // create a tempfile to write the contents of the window on
    let mut tmp = tempfile().ok().expect("Unable to create a tempfile.");
    // write the contents to it, lets put everything in dark red
    for _ in 0..16 {
        let _ = tmp.write_u32::<NativeEndian>(0xFF880000);
    }
    let _ = tmp.flush();

    // prepare the decorated surface
    let decorated_surface = {
        // introduce a new scope because .state() borrows the event_queue
        let state = event_queue.state();
        // retrieve the EnvHandler
        let env = state.get_handler::<EnvHandler<WaylandEnv>>(0);
        let surface = env.compositor.create_surface();
        let pool = env.shm.create_pool(tmp.as_raw_fd(), 64);
        let buffer = pool.create_buffer(0, 4, 4, 16, wl_shm::Format::Argb8888).expect("I didn't destroy the pool!");

        // find the seat if any
        let mut seat = None;
        for &(id, ref interface, _) in env.globals() {
            if interface == "wl_seat" {
                seat = Some(registry.bind(1, id));
                break;
            }
        }

        let window = Window {
            s: surface,
            tmp: tmp,
            pool: pool,
            pool_size: 64,
            buf: buffer,
            newsize: Some((256, 128))
        };

        let mut decorated_surface = DecoratedSurface::new(&window.s, 16, 16,
            &env.compositor,
            &env.subcompositor,
            &env.shm,
            &shell,
            seat,
            true
        ).unwrap();

        *(decorated_surface.handler()) = Some(window);
        decorated_surface
    };

    event_queue.add_handler_with_init(decorated_surface);

    loop {
        display.flush().unwrap();
        event_queue.dispatch().unwrap();

        // resize if needed
        let mut state = event_queue.state();
        let mut decorated_surface = state.get_mut_handler::<DecoratedSurface<Window>>(1);
        if let Some((w, h)) = decorated_surface.handler().as_mut().unwrap().newsize.take() {
            decorated_surface.resize(w, h);
            decorated_surface.handler().as_mut().unwrap().resize(w, h);
        }
    }
}
<commit_msg>Handle xdg-shell pings properly in simple_window example<commit_after>extern crate byteorder;
extern crate tempfile;
#[macro_use]
extern crate wayland_client;
extern crate wayland_protocols;
extern crate wayland_window;

use byteorder::{WriteBytesExt, NativeEndian};

use std::fs::File;
use std::io::Write;
use std::os::unix::io::AsRawFd;

use tempfile::tempfile;

use wayland_client::{EventQueueHandle, EnvHandler, Proxy};
use wayland_client::protocol::{wl_shell, wl_surface, wl_shm_pool, wl_buffer, wl_compositor,
                               wl_subcompositor, wl_shm};
use wayland_protocols::unstable::xdg_shell::client::zxdg_shell_v6::{self, ZxdgShellV6};

use wayland_window::DecoratedSurface;

wayland_env!(WaylandEnv,
    compositor: wl_compositor::WlCompositor,
    subcompositor: wl_subcompositor::WlSubcompositor,
    shm: wl_shm::WlShm
);

struct Window {
    s: wl_surface::WlSurface,
    tmp: File,
    pool: wl_shm_pool::WlShmPool,
    pool_size: usize,
    buf: wl_buffer::WlBuffer,
    newsize: Option<(i32, i32)>
}

impl wayland_window::Handler for Window {
    fn configure(&mut self, _: &mut EventQueueHandle, _conf: wayland_window::Configure, width: i32, height: i32) {
        let w = std::cmp::max(width, 100);
        let h = std::cmp::max(height, 100);
        println!("configure: {:?}", (w, h));
        self.newsize = Some((w, h))
    }
    fn close(&mut self, _: &mut EventQueueHandle) {
        println!("close window");
    }
}

impl Window {
    fn resize(&mut self, width: i32, height: i32) {
        if (width*height*4) as usize > self.pool_size {
            // need to reallocate a bigger buffer
            for _ in 0..((width*height) as usize - self.pool_size / 4) {
                self.tmp.write_u32::<NativeEndian>(0xFF880000).unwrap();
            }
            self.pool.resize(width*height*4);
            self.pool_size = (width*height*4) as usize;
        }
        self.buf.destroy();
        self.buf = self.pool.create_buffer(0, width, height, width*4, wl_shm::Format::Argb8888).expect("Pool should not be dead!");
        self.s.attach(Some(&self.buf), 0, 0);
        self.s.commit();
    }
}

fn main() {
    let (display, mut event_queue) = match wayland_client::default_connect() {
        Ok(ret) => ret,
        Err(e) => panic!("Cannot connect to wayland server: {:?}", e)
    };

    let env_id = event_queue.add_handler(EnvHandler::<WaylandEnv>::new());
    let registry = display.get_registry();
    event_queue.register::<_, EnvHandler<WaylandEnv>>(&registry, 0);
    event_queue.sync_roundtrip().unwrap();

    // Use `xdg-shell` if its available. Otherwise, fall back to `wl-shell`.
    let (mut xdg_shell, mut wl_shell) = (None, None);
    {
        let state = event_queue.state();
        let env = state.get_handler::<EnvHandler<WaylandEnv>>(env_id);
        for &(name, ref interface, version) in env.globals() {
            if interface == ZxdgShellV6::interface_name() {
                xdg_shell = Some(registry.bind::<ZxdgShellV6>(version, name));
                break;
            }
        }

        if xdg_shell.is_none() {
            for &(name, ref interface, version) in env.globals() {
                if interface == wl_shell::WlShell::interface_name() {
                    wl_shell = Some(registry.bind::<wl_shell::WlShell>(version, name));
                    break;
                }
            }
        }
    }

    let shell = match (xdg_shell, wl_shell) {
        (Some(shell), _) => {
            // If using xdg-shell, we'll need to answer the pings.
            struct ZxdgShellPingHandler;

            impl zxdg_shell_v6::Handler for ZxdgShellPingHandler {
                fn ping(&mut self, _: &mut EventQueueHandle, proxy: &ZxdgShellV6, serial: u32) {
                    proxy.pong(serial);
                }
            }

            declare_handler!(ZxdgShellPingHandler, zxdg_shell_v6::Handler, ZxdgShellV6);

            let ping_handler_id = event_queue.add_handler(ZxdgShellPingHandler);
            event_queue.register::<_, ZxdgShellPingHandler>(&shell, ping_handler_id);
            wayland_window::Shell::Xdg(shell)
        },
        (_, Some(shell)) => {
            wayland_window::Shell::Wl(shell)
        },

        _ => panic!("No available shell"),
    };

    // create a tempfile to write the contents of the window on
    let mut tmp = tempfile().ok().expect("Unable to create a tempfile.");
    // write the contents to it, lets put everything in dark red
    for _ in 0..16 {
        let _ = tmp.write_u32::<NativeEndian>(0xFF880000);
    }
    let _ = tmp.flush();

    // prepare the decorated surface
    let decorated_surface = {
        // introduce a new scope because .state() borrows the event_queue
        let state = event_queue.state();
        // retrieve the EnvHandler
        let env = state.get_handler::<EnvHandler<WaylandEnv>>(0);
        let surface = env.compositor.create_surface();
        let pool = env.shm.create_pool(tmp.as_raw_fd(), 64);
        let buffer = pool.create_buffer(0, 4, 4, 16, wl_shm::Format::Argb8888).expect("I didn't destroy the pool!");

        // find the seat if any
        let mut seat = None;
        for &(id, ref interface, _) in env.globals() {
            if interface == "wl_seat" {
                seat = Some(registry.bind(1, id));
                break;
            }
        }

        let window = Window {
            s: surface,
            tmp: tmp,
            pool: pool,
            pool_size: 64,
            buf: buffer,
            newsize: Some((256, 128))
        };

        let mut decorated_surface = DecoratedSurface::new(&window.s, 16, 16,
            &env.compositor,
            &env.subcompositor,
            &env.shm,
            &shell,
            seat,
            true
        ).unwrap();

        *(decorated_surface.handler()) = Some(window);
        decorated_surface
    };

    let decorated_surface_id = event_queue.add_handler_with_init(decorated_surface);

    loop {
        display.flush().unwrap();
        event_queue.dispatch().unwrap();

        // resize if needed
        let mut state = event_queue.state();
        let mut decorated_surface = state.get_mut_handler::<DecoratedSurface<Window>>(decorated_surface_id);
        if let Some((w, h)) = decorated_surface.handler().as_mut().unwrap().newsize.take() {
            decorated_surface.resize(w, h);
            decorated_surface.handler().as_mut().unwrap().resize(w, h);
        }
    }
}
<|endoftext|>


<commit_before>// see json_port.erl
#![feature(rustc_private)]
#![feature(collections)]
#![feature(convert)]
extern crate erl_ext;
extern crate serialize;
extern crate num;
extern crate byteorder;

// use std::num::ToPrimitive;
use std::io;
use std::io::Write;

use num::bigint::ToBigInt;
use num::traits::FromPrimitive;
use num::traits::ToPrimitive;
use serialize::json::{self, Json}; // TODO: use rustc-serialize
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use erl_ext::{Eterm, Error};

fn main() {
    let in_f = io::stdin();
    let out_f = io::stdout();
    match read_write_loop(in_f, out_f) {
        Err(Error::ByteorderUnexpectedEOF) => (), // port was closed
        Err(ref err) =>
            panic!("Error: '{}'", err),
        Ok(()) => ()            // unreachable in this example
    };
}

fn read_write_loop<R: io::Read, W: io::Write>(mut r: R, mut w: W) -> Result<(), Error> {
    loop {
        // {packet, 2}
        let _in_packet_size = r.read_u16::<BigEndian>();
        {
            let mut decoder = erl_ext::Decoder::new(&mut r);
            assert!(true == try!(decoder.read_prelude()));
            let term = try!(decoder.decode_term());
            // incoming message should be simple `binary()`
            let response = match term {
                Eterm::Binary(bytes) => {
                    bytes_to_json(bytes)
                },
                _ =>
                    // {error, not_binary}
                    Eterm::Tuple(vec!(
                        Eterm::Atom(String::from_str("error")),
                        Eterm::Atom(String::from_str("not_binary"))
                        ))
            };
            // Temp buffer to calculate response term size
            let mut wrtr = Vec::new();
            {
                // encode response term
                let mut encoder = erl_ext::Encoder::new(&mut wrtr,
                                                    true, true, true);
                try!(encoder.write_prelude());
                try!(encoder.encode_term(response));
                try!(encoder.flush());
            }
            // response packet size
            let out_packet_size = wrtr.len() as u16;
            try!(w.write_u16::<BigEndian>(out_packet_size));
            // response term itself
            try!(w.write(wrtr.as_slice()));
            try!(w.flush());
        }
    }
}

fn bytes_to_json(json_bytes: Vec<u8>) -> erl_ext::Eterm {
    // Vec<u8> to utf-8 String
    let json_string = match String::from_utf8(json_bytes) {
        Ok(s) => s,
        Err(_) =>
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from_str("error")),
                Eterm::Atom(String::from_str("bad_utf8"))))
    };
    // &str to json::Json
    let json_obj = match json::from_str(json_string.as_str()) {
        Ok(o) => o,
        Err(json::ParserError::SyntaxError(err_code, _, _)) => {
            let err_str = json::error_str(err_code);
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from_str("error")),
                Eterm::String(err_str.as_bytes().to_vec())
                    ))
        },
        Err(json::ParserError::IoError(_, err_str)) =>
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from_str("error")),
                Eterm::String(err_str.as_bytes().to_vec())
                    ))
    };
    // json::Json to erl_ext::Eterm
    Eterm::Tuple(vec!(Eterm::Atom(String::from_str("ok")), json_to_erl(json_obj)))
}

fn json_to_erl(json: json::Json) -> erl_ext::Eterm {
    /*
    -type json() :: float() | binary() | bool()
                    | [json()] | #{binary() => json()}.

    Json   | Erlang
    -------+------------------
    -0.23  | -0.23      // float()
    "wasd" | <<"wasd">> // binary()
    true   | true       // bool()
    []     | []         // [json()]
    {}     | {}         // #{binary() => json()}
    null   | 'undefined'
     */
    match json {
        Json::F64(num) => Eterm::Float(num),
        Json::I64(num) if (num <= (i32::max_value() as i64) && num >= (i32::min_value() as i64)) =>
            Eterm::Integer(num as i32),
        Json::I64(num) =>
            Eterm::BigNum(num.to_bigint().unwrap()),
        Json::U64(num) => {
            match num.to_i32() {
                Some(i32_num) => Eterm::Integer(i32_num),
                None => Eterm::BigNum(FromPrimitive::from_u64(num).unwrap())
            }
        },
        Json::String(string) => Eterm::Binary(string.into_bytes()),
        Json::Boolean(true) => Eterm::Atom(String::from_str("true")),
        Json::Boolean(false) => Eterm::Atom(String::from_str("false")),
        Json::Array(lst) => {
            let mut eterm_lst: erl_ext::List =
                lst.into_iter().map(json_to_erl).collect();
            eterm_lst.push(Eterm::Nil);
            Eterm::List(eterm_lst)
        },
        Json::Object(obj) => {
            let eterm_map: erl_ext::Map =
                obj.into_iter().map(
                    |(k, v)| {
                        let ek = Eterm::Binary(k.into_bytes());
                        let ev = json_to_erl(v);
                        (ek, ev)
                    }).collect();
            Eterm::Map(eterm_map)
        },
        Json::Null => Eterm::Atom(String::from_str("undefined")),
    }
}
<commit_msg>Get rid of some more 'feature' attriutes<commit_after>// see json_port.erl
#![feature(rustc_private)]

extern crate erl_ext;
extern crate serialize;
extern crate num;
extern crate byteorder;

// use std::num::ToPrimitive;
use std::io;
use std::io::Write;

use num::bigint::ToBigInt;
use num::traits::FromPrimitive;
use num::traits::ToPrimitive;
use serialize::json::{self, Json}; // TODO: use rustc-serialize
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use erl_ext::{Eterm, Error};

fn main() {
    let in_f = io::stdin();
    let out_f = io::stdout();
    match read_write_loop(in_f, out_f) {
        Err(Error::ByteorderUnexpectedEOF) => (), // port was closed
        Err(ref err) =>
            panic!("Error: '{}'", err),
        Ok(()) => ()            // unreachable in this example
    };
}

fn read_write_loop<R: io::Read, W: io::Write>(mut r: R, mut w: W) -> Result<(), Error> {
    loop {
        // {packet, 2}
        let _in_packet_size = r.read_u16::<BigEndian>();
        {
            let mut decoder = erl_ext::Decoder::new(&mut r);
            assert!(true == try!(decoder.read_prelude()));
            let term = try!(decoder.decode_term());
            // incoming message should be simple `binary()`
            let response = match term {
                Eterm::Binary(bytes) => {
                    bytes_to_json(bytes)
                },
                _ =>
                    // {error, not_binary}
                    Eterm::Tuple(vec!(
                        Eterm::Atom(String::from("error")),
                        Eterm::Atom(String::from("not_binary"))
                        ))
            };
            // Temp buffer to calculate response term size
            let mut wrtr = Vec::new();
            {
                // encode response term
                let mut encoder = erl_ext::Encoder::new(&mut wrtr,
                                                    true, true, true);
                try!(encoder.write_prelude());
                try!(encoder.encode_term(response));
                try!(encoder.flush());
            }
            // response packet size
            let out_packet_size = wrtr.len() as u16;
            try!(w.write_u16::<BigEndian>(out_packet_size));
            // response term itself
            try!(w.write_all(wrtr.as_ref()));
            try!(w.flush());
        }
    }
}

fn bytes_to_json(json_bytes: Vec<u8>) -> erl_ext::Eterm {
    // Vec<u8> to utf-8 String
    let json_string = match String::from_utf8(json_bytes) {
        Ok(s) => s,
        Err(_) =>
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from("error")),
                Eterm::Atom(String::from("bad_utf8"))))
    };
    // &str to json::Json
    let json_obj = match json::from_str(json_string.as_ref()) {
        Ok(o) => o,
        Err(json::ParserError::SyntaxError(err_code, _, _)) => {
            let err_str = json::error_str(err_code);
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from("error")),
                Eterm::String(err_str.as_bytes().to_vec())
                    ))
        },
        Err(json::ParserError::IoError(_, err_str)) =>
            return Eterm::Tuple(vec!(
                Eterm::Atom(String::from("error")),
                Eterm::String(err_str.as_bytes().to_vec())
                    ))
    };
    // json::Json to erl_ext::Eterm
    Eterm::Tuple(vec!(Eterm::Atom(String::from("ok")), json_to_erl(json_obj)))
}

fn json_to_erl(json: json::Json) -> erl_ext::Eterm {
    /*
    -type json() :: float() | binary() | bool()
                    | [json()] | #{binary() => json()}.

    Json   | Erlang
    -------+------------------
    -0.23  | -0.23      // float()
    "wasd" | <<"wasd">> // binary()
    true   | true       // bool()
    []     | []         // [json()]
    {}     | {}         // #{binary() => json()}
    null   | 'undefined'
     */
    match json {
        Json::F64(num) => Eterm::Float(num),
        Json::I64(num) if (num <= (i32::max_value() as i64) && num >= (i32::min_value() as i64)) =>
            Eterm::Integer(num as i32),
        Json::I64(num) =>
            Eterm::BigNum(num.to_bigint().unwrap()),
        Json::U64(num) => {
            match num.to_i32() {
                Some(i32_num) => Eterm::Integer(i32_num),
                None => Eterm::BigNum(FromPrimitive::from_u64(num).unwrap())
            }
        },
        Json::String(string) => Eterm::Binary(string.into_bytes()),
        Json::Boolean(true) => Eterm::Atom(String::from("true")),
        Json::Boolean(false) => Eterm::Atom(String::from("false")),
        Json::Array(lst) => {
            let mut eterm_lst: erl_ext::List =
                lst.into_iter().map(json_to_erl).collect();
            eterm_lst.push(Eterm::Nil);
            Eterm::List(eterm_lst)
        },
        Json::Object(obj) => {
            let eterm_map: erl_ext::Map =
                obj.into_iter().map(
                    |(k, v)| {
                        let ek = Eterm::Binary(k.into_bytes());
                        let ev = json_to_erl(v);
                        (ek, ev)
                    }).collect();
            Eterm::Map(eterm_map)
        },
        Json::Null => Eterm::Atom(String::from("undefined")),
    }
}
<|endoftext|>


<commit_before>extern crate shootr;

extern crate specs;
extern crate chrono;
extern crate serde_json;
extern crate websocket_server;
extern crate dotenv;
extern crate byteorder;

use specs::{DispatcherBuilder, World, Entity};
use chrono::prelude::*;
use websocket_server::{start as start_server, EventHandler, SendChannel, Message};
use dotenv::dotenv;
use byteorder::{BigEndian, ReadBytesExt};

use shootr::util::{read_env_var, elapsed_ms, timestamp, SeqId};
use shootr::model::comp::{Vel, Pos, Bounciness, Connect, Disconnect, Player, Ping, Pong, Actor,
                          ActorKind};
use shootr::model::client::KeyState;
use shootr::model::game::{Vector, Id};
use shootr::system::*;
use shootr::bootstrap;

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;
use std::collections::{HashMap, HashSet};
use std::net::SocketAddr;
use std::io::Cursor;

fn main() {
    dotenv().ok();
    let port = read_env_var("CORE_PORT").parse::<u32>().expect(
        "Specified port is not a valid number",
    );
    start_server::<Handler>("localhost", port);
}

struct Handler {
    id_entity: RwLock<HashMap<Id, Entity>>,
    to_spawn: RwLock<HashMap<Id, SendChannel>>,
    to_despawn: RwLock<HashSet<Id>>,
    inputs: Arc<RwLock<HashMap<Id, Vec<KeyState>>>>,
    pongs: Arc<RwLock<Vec<(Id, SeqId, u64)>>>,
}

impl Handler {
    fn prepare_world(&self, world: &mut World) {
        bootstrap::prepare_world(world);
        world.add_resource(self.inputs.clone());

        // Create ball
        world
            .create_entity()
            .with(Vel::from(Vector { x: 15, y: 10 }))
            .with(Pos::from(Vector { x: 500, y: 500 }))
            .with(Actor {
                id: Id::new_v4(),
                kind: ActorKind::Ball,
            })
            .with(Bounciness {})
            .build();
    }

    fn handle_text(&self, id: Id, msg: &str) {
        if let Ok(key_state) = serde_json::from_str::<KeyState>(&msg) {
            let mut inputs = self.inputs.write().unwrap();
            let has_already_inputs = inputs.get(&id).is_some();
            if has_already_inputs {
                inputs.get_mut(&id).unwrap().push(key_state);
            } else {
                inputs.insert(id, vec![key_state]);
            }
        } else {
            println!("Client {}: Sent invalid message: {}", id, msg);
        }
    }

    fn handle_pong(&self, id: Id, data: &Vec<u8>) {
        let timestamp = timestamp();

        let mut rdr = Cursor::new(data);
        if let Ok(data) = rdr.read_u32::<BigEndian>() {
            let mut pongs = self.pongs.write().unwrap();
            pongs.push((id, data, timestamp));
        } else {
            println!("Client {}: Sent pong with invalid bytes {:?}", id, data);
        }
    }

    fn register_spawns(&self, world: &mut World) {
        let mut id_entity = self.id_entity.write().unwrap();
        let mut to_spawn = self.to_spawn.write().unwrap();
        for (id, send_channel) in to_spawn.drain() {
            let entity = world
                .create_entity()
                .with(Connect {})
                .with(Player::new(send_channel))
                .with(Actor {
                    id,
                    kind: ActorKind::Player,
                })
                .build();
            id_entity.insert(id, entity.clone());
        }

        let mut to_despawn = self.to_despawn.write().unwrap();
        for id in to_despawn.drain() {
            if let Some(entity) = id_entity.remove(&id) {
                world.write::<Disconnect>().insert(entity, Disconnect {});
            }
        }
    }

    fn register_pings(&self, world: &mut World) {
        for (_, entity) in self.id_entity.read().unwrap().iter() {
            world.write::<Ping>().insert(entity.clone(), Ping {});
        }
    }

    fn register_pongs(&self, world: &mut World) {
        let id_entity = self.id_entity.read().unwrap();
        let mut pongs = self.pongs.write().unwrap();
        for pong in pongs.drain(..) {
            let (player_id, ping_id, timestamp) = pong;
            if let Some(entity) = id_entity.get(&player_id) {
                world.write::<Pong>().insert(
                    entity.clone(),
                    Pong { ping_id, timestamp },
                );
            }
        }
    }
}

impl EventHandler for Handler {
    type Id = Id;

    fn new() -> Self {
        Handler {
            id_entity: RwLock::new(HashMap::new()),
            to_spawn: RwLock::new(HashMap::new()),
            to_despawn: RwLock::new(HashSet::new()),
            inputs: Arc::new(RwLock::new(HashMap::new())),
            pongs: Arc::new(RwLock::new(Vec::new())),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        self.prepare_world(&mut world);

        let mut updater = DispatcherBuilder::new()
            .add(InputHandler, "input_handler", &[])
            .add(Physics, "physics", &["input_handler"])
            .add(Bounce, "bounce", &["physics"])
            .add(Spawn, "spawn", &["physics", "bounce"])
            .add(Despawn, "despawn", &["spawn"])
            .build();
        let mut sender = DispatcherBuilder::new()
            .add(Sending, "sending", &[])
            .build();
        let mut delay = DispatcherBuilder::new().add(Delay, "delay", &[]).build();

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let updates_per_sec = read_env_var("CORE_UPDATES_PER_SEC").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );
        let ms_per_update = 1000 / updates_per_sec;
        let mut ping_timer = 0;
        let ping_interval = 1000;
        loop {
            let current = Utc::now();
            let elapsed = elapsed_ms(previous, current).expect("Time went backwards");
            previous = current;
            lag += elapsed;
            ping_timer += elapsed;

            if ping_timer > ping_interval {
                self.register_pings(&mut world);
                delay.dispatch(&mut world.res);
                ping_timer = 0;
            }
            self.register_pongs(&mut world);
            self.register_spawns(&mut world);

            while lag >= ms_per_update {
                updater.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            sender.dispatch(&mut world.res);
            world.maintain();

            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }

    fn on_message(&self, id: Self::Id, msg: Message) {
        match msg {
            Message::Text(ref txt) => self.handle_text(id, txt),
            Message::Pong(ref data) => self.handle_pong(id, data),
            _ => {}
        };
    }
    fn on_connect(&self, _: SocketAddr, send_channel: SendChannel) -> Option<Self::Id> {
        let id = Id::new_v4();
        self.to_spawn.write().unwrap().insert(id, send_channel);
        println!("Client {}: Connected", id);
        Some(id)
    }
    fn on_disconnect(&self, id: Self::Id) {
        println!("Client {}: Disonnected", id);
        self.to_despawn.write().unwrap().insert(id);
    }
}
<commit_msg>Core: Fix typo<commit_after>extern crate shootr;

extern crate specs;
extern crate chrono;
extern crate serde_json;
extern crate websocket_server;
extern crate dotenv;
extern crate byteorder;

use specs::{DispatcherBuilder, World, Entity};
use chrono::prelude::*;
use websocket_server::{start as start_server, EventHandler, SendChannel, Message};
use dotenv::dotenv;
use byteorder::{BigEndian, ReadBytesExt};

use shootr::util::{read_env_var, elapsed_ms, timestamp, SeqId};
use shootr::model::comp::{Vel, Pos, Bounciness, Connect, Disconnect, Player, Ping, Pong, Actor,
                          ActorKind};
use shootr::model::client::KeyState;
use shootr::model::game::{Vector, Id};
use shootr::system::*;
use shootr::bootstrap;

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;
use std::collections::{HashMap, HashSet};
use std::net::SocketAddr;
use std::io::Cursor;

fn main() {
    dotenv().ok();
    let port = read_env_var("CORE_PORT").parse::<u32>().expect(
        "Specified port is not a valid number",
    );
    start_server::<Handler>("localhost", port);
}

struct Handler {
    id_entity: RwLock<HashMap<Id, Entity>>,
    to_spawn: RwLock<HashMap<Id, SendChannel>>,
    to_despawn: RwLock<HashSet<Id>>,
    inputs: Arc<RwLock<HashMap<Id, Vec<KeyState>>>>,
    pongs: Arc<RwLock<Vec<(Id, SeqId, u64)>>>,
}

impl Handler {
    fn prepare_world(&self, world: &mut World) {
        bootstrap::prepare_world(world);
        world.add_resource(self.inputs.clone());

        // Create ball
        world
            .create_entity()
            .with(Vel::from(Vector { x: 15, y: 10 }))
            .with(Pos::from(Vector { x: 500, y: 500 }))
            .with(Actor {
                id: Id::new_v4(),
                kind: ActorKind::Ball,
            })
            .with(Bounciness {})
            .build();
    }

    fn handle_text(&self, id: Id, msg: &str) {
        if let Ok(key_state) = serde_json::from_str::<KeyState>(&msg) {
            let mut inputs = self.inputs.write().unwrap();
            let has_already_inputs = inputs.get(&id).is_some();
            if has_already_inputs {
                inputs.get_mut(&id).unwrap().push(key_state);
            } else {
                inputs.insert(id, vec![key_state]);
            }
        } else {
            println!("Client {}: Sent invalid message: {}", id, msg);
        }
    }

    fn handle_pong(&self, id: Id, data: &Vec<u8>) {
        let timestamp = timestamp();

        let mut rdr = Cursor::new(data);
        if let Ok(data) = rdr.read_u32::<BigEndian>() {
            let mut pongs = self.pongs.write().unwrap();
            pongs.push((id, data, timestamp));
        } else {
            println!("Client {}: Sent pong with invalid bytes {:?}", id, data);
        }
    }

    fn register_spawns(&self, world: &mut World) {
        let mut id_entity = self.id_entity.write().unwrap();
        let mut to_spawn = self.to_spawn.write().unwrap();
        for (id, send_channel) in to_spawn.drain() {
            let entity = world
                .create_entity()
                .with(Connect {})
                .with(Player::new(send_channel))
                .with(Actor {
                    id,
                    kind: ActorKind::Player,
                })
                .build();
            id_entity.insert(id, entity.clone());
        }

        let mut to_despawn = self.to_despawn.write().unwrap();
        for id in to_despawn.drain() {
            if let Some(entity) = id_entity.remove(&id) {
                world.write::<Disconnect>().insert(entity, Disconnect {});
            }
        }
    }

    fn register_pings(&self, world: &mut World) {
        for (_, entity) in self.id_entity.read().unwrap().iter() {
            world.write::<Ping>().insert(entity.clone(), Ping {});
        }
    }

    fn register_pongs(&self, world: &mut World) {
        let id_entity = self.id_entity.read().unwrap();
        let mut pongs = self.pongs.write().unwrap();
        for pong in pongs.drain(..) {
            let (player_id, ping_id, timestamp) = pong;
            if let Some(entity) = id_entity.get(&player_id) {
                world.write::<Pong>().insert(
                    entity.clone(),
                    Pong { ping_id, timestamp },
                );
            }
        }
    }
}

impl EventHandler for Handler {
    type Id = Id;

    fn new() -> Self {
        Handler {
            id_entity: RwLock::new(HashMap::new()),
            to_spawn: RwLock::new(HashMap::new()),
            to_despawn: RwLock::new(HashSet::new()),
            inputs: Arc::new(RwLock::new(HashMap::new())),
            pongs: Arc::new(RwLock::new(Vec::new())),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        self.prepare_world(&mut world);

        let mut updater = DispatcherBuilder::new()
            .add(InputHandler, "input_handler", &[])
            .add(Physics, "physics", &["input_handler"])
            .add(Bounce, "bounce", &["physics"])
            .add(Spawn, "spawn", &["physics", "bounce"])
            .add(Despawn, "despawn", &["spawn"])
            .build();
        let mut sender = DispatcherBuilder::new()
            .add(Sending, "sending", &[])
            .build();
        let mut delay = DispatcherBuilder::new().add(Delay, "delay", &[]).build();

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let updates_per_sec = read_env_var("CORE_UPDATES_PER_SEC").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );
        let ms_per_update = 1000 / updates_per_sec;
        let mut ping_timer = 0;
        let ping_interval = 1000;
        loop {
            let current = Utc::now();
            let elapsed = elapsed_ms(previous, current).expect("Time went backwards");
            previous = current;
            lag += elapsed;
            ping_timer += elapsed;

            if ping_timer > ping_interval {
                self.register_pings(&mut world);
                delay.dispatch(&mut world.res);
                ping_timer = 0;
            }
            self.register_pongs(&mut world);
            self.register_spawns(&mut world);

            while lag >= ms_per_update {
                updater.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            sender.dispatch(&mut world.res);
            world.maintain();

            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }

    fn on_message(&self, id: Self::Id, msg: Message) {
        match msg {
            Message::Text(ref txt) => self.handle_text(id, txt),
            Message::Pong(ref data) => self.handle_pong(id, data),
            _ => {}
        };
    }
    fn on_connect(&self, _: SocketAddr, send_channel: SendChannel) -> Option<Self::Id> {
        let id = Id::new_v4();
        self.to_spawn.write().unwrap().insert(id, send_channel);
        println!("Client {}: Connected", id);
        Some(id)
    }
    fn on_disconnect(&self, id: Self::Id) {
        println!("Client {}: Disconnected", id);
        self.to_despawn.write().unwrap().insert(id);
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ProducerState {
    Started,
    Closed,
}

pub struct Producer {
    func: Box<Fn(ProducerState)>,
    state: Cell<ProducerState>,
}

impl Producer {
    pub fn from_func(func: Box<Fn(ProducerState)>) -> Producer {
        Producer {
            func: func,
            state: Cell::new(ProducerState::Started),
        }
    }

    pub fn new() -> Producer {
        Producer::from_func(Box::new(|_| {}))
    }

    pub fn set_func(&mut self, func: Box<Fn(ProducerState)>) {
        self.func = func;
    }

    pub fn is_closed(&self) -> bool {
        self.state.get() == ProducerState::Closed
    }

    pub fn close(&self) {
        self.state.set(ProducerState::Closed);
    }
}
<commit_msg>fix close not calling function in producer<commit_after>use std::cell::Cell;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ProducerState {
    Started,
    Closed,
}

pub struct Producer {
    func: Box<Fn(ProducerState)>,
    state: Cell<ProducerState>,
}

impl Producer {
    pub fn from_func(func: Box<Fn(ProducerState)>) -> Producer {
        Producer {
            func: func,
            state: Cell::new(ProducerState::Started),
        }
    }

    pub fn new() -> Producer {
        Producer::from_func(Box::new(|_| {}))
    }

    pub fn is_closed(&self) -> bool {
        self.state.get() == ProducerState::Closed
    }

    pub fn close(&self) {
        self.state.set(ProducerState::Closed);
        (self.func)(ProducerState::Closed);
    }
}
<|endoftext|>


<commit_before>extern crate rgtk;

use rgtk::*;

pub fn new_project(state: &mut ::utils::State) {
    let chooser = gtk::FileChooserDialog::new(
        "New Project",
        None,
        gtk::FileChooserAction::CreateFolder).unwrap();
    chooser.run();
    let filename = chooser.get_filename();
    if filename.is_some() {
        state.projects.insert(filename.unwrap());
        ::ui::update_project_tree(state);
        ::utils::write_prefs(state);
    }
    chooser.destroy();
}

pub fn import_project(state: &mut ::utils::State) {
    let chooser = gtk::FileChooserDialog::new(
        "Import",
        None,
        gtk::FileChooserAction::SelectFolder).unwrap();
    chooser.run();
    let filename = chooser.get_filename();
    if filename.is_some() {
        state.projects.insert(filename.unwrap());
        ::ui::update_project_tree(state);
        ::utils::write_prefs(state);
    }
    chooser.destroy();
}

pub fn rename_project(state: &mut ::utils::State) {

}

pub fn remove_project(state: &mut ::utils::State) {

}
<commit_msg>Prevent file dialog from creating folder<commit_after>extern crate rgtk;

use rgtk::*;

pub fn new_project(state: &mut ::utils::State) {
    let chooser = gtk::FileChooserDialog::new(
        "New Project",
        None,
        gtk::FileChooserAction::Save).unwrap();
    chooser.run();
    let filename = chooser.get_filename();
    if filename.is_some() {
        state.projects.insert(filename.unwrap());
        ::ui::update_project_tree(state);
        ::utils::write_prefs(state);
    }
    chooser.destroy();
}

pub fn import_project(state: &mut ::utils::State) {
    let chooser = gtk::FileChooserDialog::new(
        "Import",
        None,
        gtk::FileChooserAction::SelectFolder).unwrap();
    chooser.run();
    let filename = chooser.get_filename();
    if filename.is_some() {
        state.projects.insert(filename.unwrap());
        ::ui::update_project_tree(state);
        ::utils::write_prefs(state);
    }
    chooser.destroy();
}

pub fn rename_project(state: &mut ::utils::State) {

}

pub fn remove_project(state: &mut ::utils::State) {

}
<|endoftext|>


<commit_before>
extern crate time;
extern crate serial;
extern crate plugwise;

use std::io::prelude::*;
use plugwise::protocol::*;
use plugwise::stub;
use std::io;
use time::Duration;
use serial::prelude::*;
use std::rc::Rc;
use std::cell::RefCell;

struct PlugwiseInner<'a, I> {
    protocol: Rc<RefCell<Protocol<'a, I>>>
}

struct CircleInner<'a, I> {
    protocol: Rc<RefCell<Protocol<'a, I>>>,
    mac: u64
}

impl<'a, I: Read+Write+'a> PlugwiseInner<'a, I> {
    fn initialize(port: I) -> io::Result<PlugwiseInner<'a, I>> {
        let plugwise = PlugwiseInner {
            protocol: Rc::new(RefCell::new(Protocol::new(port)))
        };

        let result = try!(plugwise.protocol.borrow_mut().initialize());

        if !result.is_online {
            return Err(io::Error::new(io::ErrorKind::Other, "not online"));
        }

        Ok(plugwise)
    }
}

trait Plugwise<'a> {
    fn create_circle(&self, mac: u64) -> Box<Circle + 'a>;
    fn set_snoop(&self, snoop: ProtocolSnoop<'a>);
}

trait Circle {
    fn switch_on(&self) -> io::Result<()>;
    fn switch_off(&self) -> io::Result<()>;
}

impl<'a, I:Read+Write+'a> Plugwise<'a> for PlugwiseInner<'a, I> {
    fn create_circle(&self, mac: u64) -> Box<Circle+ 'a> {
        //Box::new(CircleInner::new(self.protocol.clone(), mac))
        Box::new(CircleInner {
            protocol: self.protocol.clone(),
            mac: mac
        })
    }

    fn set_snoop(&self, snoop: ProtocolSnoop<'a>) {
        self.protocol.borrow_mut().set_snoop(snoop);
    }
}

impl<'a, I:Read+Write+'a> Circle for CircleInner<'a, I> {
    fn switch_on(&self) -> io::Result<()> {
        try!(self.protocol.borrow_mut().switch(self.mac, true));
        Ok(())
    }

    fn switch_off(&self) -> io::Result<()> {
        try!(self.protocol.borrow_mut().switch(self.mac, false));
        Ok(())
    }
}

fn plugwise_device<'a>(device: &str) -> io::Result<Box<Plugwise<'a>+ 'a>> {
    let mut port = try!(serial::open(device));
    try!(port.configure(|settings| {
        settings.set_baud_rate(serial::Baud115200);
        settings.set_char_size(serial::Bits8);
        settings.set_parity(serial::ParityNone);
        settings.set_stop_bits(serial::Stop1);
    }));

    port.set_timeout(Duration::milliseconds(1000));
    let plugwise = try!(PlugwiseInner::initialize(port));

    Ok(Box::new(plugwise))
}

fn plugwise_simulator<'a>() -> io::Result<Box<Plugwise<'a>+ 'a>> {
    let port = stub::Stub::new();

    let plugwise = try!(PlugwiseInner::initialize(port));

    Ok(Box::new(plugwise))
}

fn main() {
    let mut debug = io::stdout();

    //let plugwise = plugwise_device("/dev/ttyUSB0").unwrap();
    let plugwise = plugwise_simulator().unwrap();
    plugwise.set_snoop(ProtocolSnoop::Debug(&mut debug));
    let circle = plugwise.create_circle(0x0123456789ABCDEF);
    circle.switch_on().unwrap();
    circle.switch_off().unwrap();
}
<commit_msg>add calibration data retrieval when registering a circle<commit_after>
extern crate time;
extern crate serial;
extern crate plugwise;

use std::io::prelude::*;
use plugwise::protocol::*;
use plugwise::stub;
use std::io;
use time::Duration;
use serial::prelude::*;
use std::rc::Rc;
use std::cell::RefCell;

struct PlugwiseInner<'a, I> {
    protocol: Rc<RefCell<Protocol<'a, I>>>
}

struct CircleInner<'a, I> {
    protocol: Rc<RefCell<Protocol<'a, I>>>,
    mac: u64,
    calibration_data: ResCalibration
}

impl<'a, I: Read+Write+'a> PlugwiseInner<'a, I> {
    fn initialize(port: I) -> io::Result<PlugwiseInner<'a, I>> {
        let plugwise = PlugwiseInner {
            protocol: Rc::new(RefCell::new(Protocol::new(port)))
        };

        let result = try!(plugwise.protocol.borrow_mut().initialize());

        if !result.is_online {
            return Err(io::Error::new(io::ErrorKind::Other, "not online"));
        }

        Ok(plugwise)
    }
}

trait Plugwise<'a> {
    fn create_circle(&self, mac: u64) -> io::Result<Box<Circle + 'a>>;
    fn set_snoop(&self, snoop: ProtocolSnoop<'a>);
}

trait Circle {
    fn switch_on(&self) -> io::Result<()>;
    fn switch_off(&self) -> io::Result<()>;
}

impl<'a, I:Read+Write+'a> Plugwise<'a> for PlugwiseInner<'a, I> {
    fn create_circle(&self, mac: u64) -> io::Result<Box<Circle+ 'a>> {
        let calibration_data = try!(self.protocol.borrow_mut().calibrate(mac));
        Ok(Box::new(CircleInner {
            protocol: self.protocol.clone(),
            mac: mac,
            calibration_data: calibration_data
        }))
    }

    fn set_snoop(&self, snoop: ProtocolSnoop<'a>) {
        self.protocol.borrow_mut().set_snoop(snoop);
    }
}

impl<'a, I:Read+Write+'a> Circle for CircleInner<'a, I> {
    fn switch_on(&self) -> io::Result<()> {
        try!(self.protocol.borrow_mut().switch(self.mac, true));
        Ok(())
    }

    fn switch_off(&self) -> io::Result<()> {
        try!(self.protocol.borrow_mut().switch(self.mac, false));
        Ok(())
    }
}

fn plugwise_device<'a>(device: &str) -> io::Result<Box<Plugwise<'a>+ 'a>> {
    let mut port = try!(serial::open(device));
    try!(port.configure(|settings| {
        settings.set_baud_rate(serial::Baud115200);
        settings.set_char_size(serial::Bits8);
        settings.set_parity(serial::ParityNone);
        settings.set_stop_bits(serial::Stop1);
    }));

    port.set_timeout(Duration::milliseconds(1000));
    let plugwise = try!(PlugwiseInner::initialize(port));

    Ok(Box::new(plugwise))
}

fn plugwise_simulator<'a>() -> io::Result<Box<Plugwise<'a>+ 'a>> {
    let port = stub::Stub::new();

    let plugwise = try!(PlugwiseInner::initialize(port));

    Ok(Box::new(plugwise))
}

fn main() {
    let mut debug = io::stdout();

    //let plugwise = plugwise_device("/dev/ttyUSB0").unwrap();
    let plugwise = plugwise_simulator().unwrap();
    plugwise.set_snoop(ProtocolSnoop::Debug(&mut debug));
    let circle = plugwise.create_circle(0x0123456789ABCDEF).unwrap();
    circle.switch_on().unwrap();
    circle.switch_off().unwrap();
}
<|endoftext|>


<commit_before>// This example demonstrates use of the callback-based `Resolver`.
extern crate c_ares;
extern crate c_ares_resolver;

use std::error::Error;
use std::sync::mpsc;

use c_ares_resolver::Resolver;

fn print_a_results(result: &c_ares::Result<c_ares::AResults>) {
    match *result {
        Err(ref e) => {
            println!("Query failed with error '{}'", e.description());
        }
        Ok(ref a_results) => {
            println!("Successful A lookup...");
            for a_result in a_results {
                 println!("IPv4: {}, TTL {}", a_result.ipv4(), a_result.ttl());
            }
        },
    }
}

fn main() {
    // We'll need to be careful while we're waiting for our callback.  Dropping
    // the resolver would cause the outstanding query to fail - and if we
    // exited the main thread too soon we wouldn't see even that happen.
    //
    // Create a channel that the callback will use to tell the main thread that
    // it is done.
    let (tx, rx) = mpsc::channel();

    // Create a resolver and make a query.
    let resolver = Resolver::new().expect("Failed to create resolver");
    resolver.query_a(
        "apple.com",
        move |result| {
            print_a_results(&result);
            tx.send(()).unwrap();
        },
    );

    // Wait to be told that the callback has happened.
    rx.recv().unwrap();
}
<commit_msg>rustfmt<commit_after>// This example demonstrates use of the callback-based `Resolver`.
extern crate c_ares;
extern crate c_ares_resolver;

use std::error::Error;
use std::sync::mpsc;

use c_ares_resolver::Resolver;

fn print_a_results(result: &c_ares::Result<c_ares::AResults>) {
    match *result {
        Err(ref e) => {
            println!("Query failed with error '{}'", e.description());
        }
        Ok(ref a_results) => {
            println!("Successful A lookup...");
            for a_result in a_results {
                println!("IPv4: {}, TTL {}", a_result.ipv4(), a_result.ttl());
            }
        }
    }
}

fn main() {
    // We'll need to be careful while we're waiting for our callback.  Dropping
    // the resolver would cause the outstanding query to fail - and if we
    // exited the main thread too soon we wouldn't see even that happen.
    //
    // Create a channel that the callback will use to tell the main thread that
    // it is done.
    let (tx, rx) = mpsc::channel();

    // Create a resolver and make a query.
    let resolver = Resolver::new().expect("Failed to create resolver");
    resolver.query_a("apple.com", move |result| {
        print_a_results(&result);
        tx.send(()).unwrap();
    });

    // Wait to be told that the callback has happened.
    rx.recv().unwrap();
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let this_crate = make_this_crate(prj)?;
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    eprintln!("\nCXX include path:");
    for header_dir in this_crate.header_dirs {
        build.include(&header_dir.path);
        if header_dir.exported {
            eprintln!("  {}", header_dir.path.display());
        } else {
            eprintln!("  {} (private)", header_dir.path.display());
        }
    }

    Ok(build)
}

fn make_this_crate(prj: &Project) -> Result<Crate> {
    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;

    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });

    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }

    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }

    for krate in deps::direct_dependencies() {
        let is_link_exported = || match &krate.links {
            None => false,
            Some(links_attribute) => CFG
                .exported_header_links
                .iter()
                .any(|exported| links_attribute == *exported),
        };

        let exported = is_link_exported();

        this_crate
            .header_dirs
            .extend(krate.header_dirs.into_iter().map(|dir| HeaderDir {
                exported,
                path: dir.path,
            }));
    }

    Ok(this_crate)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<commit_msg>Implement CFG.exported_header_prefixes<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let this_crate = make_this_crate(prj)?;
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    eprintln!("\nCXX include path:");
    for header_dir in this_crate.header_dirs {
        build.include(&header_dir.path);
        if header_dir.exported {
            eprintln!("  {}", header_dir.path.display());
        } else {
            eprintln!("  {} (private)", header_dir.path.display());
        }
    }

    Ok(build)
}

fn make_this_crate(prj: &Project) -> Result<Crate> {
    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;

    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });

    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }

    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }

    for krate in deps::direct_dependencies() {
        let is_link_exported = || match &krate.links {
            None => false,
            Some(links_attribute) => CFG
                .exported_header_links
                .iter()
                .any(|exported| links_attribute == *exported),
        };

        let is_prefix_exported = || match &krate.include_prefix {
            None => false,
            Some(include_prefix) => CFG
                .exported_header_prefixes
                .iter()
                .any(|exported| include_prefix.starts_with(exported)),
        };

        let exported = is_link_exported() || is_prefix_exported();

        this_crate
            .header_dirs
            .extend(krate.header_dirs.into_iter().map(|dir| HeaderDir {
                exported,
                path: dir.path,
            }));
    }

    Ok(this_crate)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<|endoftext|>