<commit_before>use conrod::{Positionable, Sizeable, Labelable, Widget, Colorable};
use conrod::widget;
use conrod::backend::glium::{glium, Renderer};
use conrod::backend::winit;
use conrod::backend::glium::glium::{DisplayBuild, Surface};
use ::game::{GameConfig, Game};
use color::*;

// struct `EventLoop` copied from Conrod example
struct EventLoop {
    ui_needs_update: bool,
    last_update: ::std::time::Instant,
}
impl EventLoop {
    pub fn new() -> Self {
        EventLoop {
            last_update: ::std::time::Instant::now(),
            ui_needs_update: true,
        }
    }

    // Produce an iterator yielding all available events.
    pub fn next(&mut self, display: &glium::Display) -> Vec<glium::glutin::Event> {
        // We don't want to loop any faster than 60 FPS, so wait until it has been at least 16ms
        // since the last yield.
        let last_update = self.last_update;
        let sixteen_ms = ::std::time::Duration::from_millis(16);
        let duration_since_last_update = ::std::time::Instant::now().duration_since(last_update);
        if duration_since_last_update < sixteen_ms {
            ::std::thread::sleep(sixteen_ms - duration_since_last_update);
        }

        // Collect all pending events.
        let mut events = Vec::new();
        events.extend(display.poll_events());

        // If there are no events and the `Ui` does not need updating, wait for the next event.
        if events.is_empty() && !self.ui_needs_update {
            events.extend(display.wait_events().next());
        }

        self.ui_needs_update = false;
        self.last_update = ::std::time::Instant::now();

        events
    }

    // Notifies the event loop that the `Ui` requires another update whether or not there are any
    // pending events.
    //
    // This is primarily used on the occasion that some part of the `Ui` is still animating and
    // requires further updates to do so.
    pub fn needs_update(&mut self) {
        self.ui_needs_update = true;
    }
}

// Display a GUI to configs and start the game
// Return a handle to the thread where the game's running
// Return `None` if user want to exit
// NOTE This funtion will change the value of game config
fn start_game(config: &mut GameConfig, first_time: bool) -> Option<::std::thread::JoinHandle<()>> {
    let (ui_width, ui_height) = (320, 240);
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(ui_width, ui_height)
        .with_title(config.title.as_ref())
        .build_glium()
        .expect("UI: Cannot build window");
    let mut ui = ::conrod::UiBuilder::new([ui_width as f64, ui_height as f64]).build();
    ui.fonts.insert_from_file("resources/Ubuntu-R.ttf").expect("UI: cannot load font");
    let mut renderer = Renderer::new(&display).expect("UI: cannot load renderer");
    let image_map = ::conrod::image::Map::<glium::texture::Texture2d>::new();
    let mut event_loop = EventLoop::new();

    widget_ids!(struct Ids {
        canvas,
        button,
        w_label, h_label,
        w_text_box, h_text_box,
    });
    let ids = Ids::new(ui.widget_id_generator());
    let mut screen_w = config.screen_size.w.to_string();
    let mut screen_h = config.screen_size.h.to_string();
    loop {
        for event in event_loop.next(&display) {
            if let Some(event) = winit::convert(event.clone(), &display) {
                ui.handle_event(event);
                event_loop.needs_update();
            }
            if let glium::glutin::Event::Closed = event { return None; }

            { // Setup all elements of UI
                let ui = &mut ui.set_widgets();
                let _canvas = widget::Canvas::new()
                    .color(GRAY.into())
                    .set(ids.canvas, ui);
                let w_text_box = widget::TextBox::new(&screen_w)
                    .mid_top_of(ids.canvas)
                    .w_h(120., 30.)
                    .font_size(14)
                    .set(ids.w_text_box, ui);
                let h_text_box = widget::TextBox::new(&screen_h)
                    .down_from(ids.w_text_box, 2.)
                    .w_h(120., 30.)
                    .font_size(14)
                    .set(ids.h_text_box, ui);
                let _w_label = widget::Text::new("Width: ")
                    .left_from(ids.w_text_box, 0.).align_middle_y_of(ids.w_text_box)
                    .font_size(14).color(WHITE.into())
                    .set(ids.w_label, ui);
                let _h_label = widget::Text::new("Height: ")
                    .left_from(ids.h_text_box, 0.).align_middle_y_of(ids.h_text_box)
                    .font_size(14).color(WHITE.into())
                    .set(ids.h_label, ui);
                let button = widget::Button::new()
                    .down_from(ids.h_text_box, 2.)
                    .w_h(120., 30.)
                    .label(if first_time {"Start game"} else {"Restart game"})
                    .label_font_size(14)
                    .set(ids.button, ui);

                // Bind events for our widgets
                for e in h_text_box {
                    if let widget::text_box::Event::Update(s) = e {
                        if s.is_empty() || s.parse::<u32>().is_ok() {
                            screen_h = s;
                        }
                    }
                }
                for e in w_text_box {
                    if let widget::text_box::Event::Update(s) = e {
                        if s.is_empty() || s.parse::<u32>().is_ok() {
                            screen_w = s;
                        }
                    }
                }
                for _click in button {
                    config.screen_size.w = screen_w.parse().unwrap_or(config.screen_size.w);
                    config.screen_size.h = screen_h.parse().unwrap_or(config.screen_size.h);
                    let config = config.clone();
                    return Some(::std::thread::spawn(|| Game::new(config).run()));
                }
            }

            // Draw the GUI
            if let Some(whatever) = ui.draw_if_changed() {
                renderer.fill(&display, whatever, &image_map);
                let mut target = display.draw();
                target.clear_color(0., 0., 0., 1.);
                renderer.draw(&display, &mut target, &image_map).expect("UI draw error");
                target.finish().expect("UI 'finish' error");
            }
        }
    }
}

pub fn main(config: &mut GameConfig) {
    let mut first_time = true;
    while let Some(game_thread) = start_game(config, first_time) {
        game_thread.join().expect("Unexpected thread error");
        first_time = false;
    }
}
<commit_msg>fix bugs<commit_after>use conrod::{Positionable, Sizeable, Labelable, Widget, Colorable};
use conrod::widget;
use conrod::backend::glium::{glium, Renderer};
use conrod::backend::winit;
use conrod::backend::glium::glium::{DisplayBuild, Surface};
use ::game::{GameConfig, Game};
use color::*;

// struct `EventLoop` copied from Conrod example
struct EventLoop {
    ui_needs_update: bool,
    last_update: ::std::time::Instant,
}
impl EventLoop {
    pub fn new() -> Self {
        EventLoop {
            last_update: ::std::time::Instant::now(),
            ui_needs_update: true,
        }
    }

    // Produce an iterator yielding all available events.
    pub fn next(&mut self, display: &glium::Display) -> Vec<glium::glutin::Event> {
        // We don't want to loop any faster than 60 FPS, so wait until it has been at least 16ms
        // since the last yield.
        let last_update = self.last_update;
        let sixteen_ms = ::std::time::Duration::from_millis(16);
        let duration_since_last_update = ::std::time::Instant::now().duration_since(last_update);
        if duration_since_last_update < sixteen_ms {
            ::std::thread::sleep(sixteen_ms - duration_since_last_update);
        }

        // Collect all pending events.
        let mut events = Vec::new();
        events.extend(display.poll_events());

        // If there are no events and the `Ui` does not need updating, wait for the next event.
        if events.is_empty() && !self.ui_needs_update {
            events.extend(display.wait_events().next());
        }

        self.ui_needs_update = false;
        self.last_update = ::std::time::Instant::now();

        events
    }

    // Notifies the event loop that the `Ui` requires another update whether or not there are any
    // pending events.
    //
    // This is primarily used on the occasion that some part of the `Ui` is still animating and
    // requires further updates to do so.
    pub fn needs_update(&mut self) {
        self.ui_needs_update = true;
    }
}

// Display a GUI to configs and start the game
// Return a handle to the thread where the game's running
// Return `None` if user want to exit
// NOTE This funtion will change the value of game config
fn start_game(config: &mut GameConfig, first_time: bool) -> Option<::std::thread::JoinHandle<()>> {
    let (ui_width, ui_height) = (320, 240);
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(ui_width, ui_height)
        .with_title(config.title.as_ref())
        .build_glium()
        .expect("UI: Cannot build window");
    let mut ui = ::conrod::UiBuilder::new([ui_width as f64, ui_height as f64]).build();
    ui.fonts.insert_from_file("resources/Ubuntu-R.ttf").expect("UI: cannot load font");
    let mut renderer = Renderer::new(&display).expect("UI: cannot load renderer");
    let image_map = ::conrod::image::Map::<glium::texture::Texture2d>::new();
    let mut event_loop = EventLoop::new();

    widget_ids!(struct Ids {
        canvas,
        button,
        w_label, h_label,
        w_text_box, h_text_box,
    });
    let ids = Ids::new(ui.widget_id_generator());
    let mut screen_w = config.screen_size.w.to_string();
    let mut screen_h = config.screen_size.h.to_string();
    loop {
        for event in event_loop.next(&display) {
            if let Some(event) = winit::convert(event.clone(), &display) {
                ui.handle_event(event);
                event_loop.needs_update();
            }
            if let glium::glutin::Event::Closed = event { return None; }

            { // Setup all elements of UI
                let ui = &mut ui.set_widgets();
                let _canvas = widget::Canvas::new()
                    .color(GRAY.into())
                    .set(ids.canvas, ui);
                let w_text_box = widget::TextBox::new(&screen_w)
                    .mid_top_of(ids.canvas)
                    .w_h(120., 30.)
                    .font_size(14)
                    .set(ids.w_text_box, ui);
                let h_text_box = widget::TextBox::new(&screen_h)
                    .down_from(ids.w_text_box, 2.)
                    .w_h(120., 30.)
                    .font_size(14)
                    .set(ids.h_text_box, ui);
                let _w_label = widget::Text::new("Width: ")
                    .left_from(ids.w_text_box, 0.).align_middle_y_of(ids.w_text_box)
                    .font_size(14).color(WHITE.into())
                    .set(ids.w_label, ui);
                let _h_label = widget::Text::new("Height: ")
                    .left_from(ids.h_text_box, 0.).align_middle_y_of(ids.h_text_box)
                    .font_size(14).color(WHITE.into())
                    .set(ids.h_label, ui);
                let button = widget::Button::new()
                    .down_from(ids.h_text_box, 2.)
                    .w_h(120., 30.)
                    .label(if first_time {"Start game"} else {"Restart game"})
                    .label_font_size(14)
                    .set(ids.button, ui);

                // Bind events for our widgets
                for e in h_text_box {
                    if let widget::text_box::Event::Update(s) = e {
                        if s.is_empty() || s.parse::<u32>().is_ok() {
                            screen_h = s;
                        }
                    }
                }
                for e in w_text_box {
                    if let widget::text_box::Event::Update(s) = e {
                        if s.is_empty() || s.parse::<u32>().is_ok() {
                            screen_w = s;
                        }
                    }
                }
                for _click in button {
                    config.screen_size.w = screen_w.parse().unwrap_or(config.screen_size.w);
                    config.screen_size.h = screen_h.parse().unwrap_or(config.screen_size.h);
                    let config = config.clone();
                    return Some(::std::thread::spawn(|| Game::new(config).run()));
                }
            }
            // Hot-fix for a bug: window does not redraw after
            // minimized and maximized again.
            if let glium::glutin::Event::Focused(true) = event {
                ui.needs_redraw();
            }
            // Draw the GUI
            if let Some(whatever) = ui.draw_if_changed() {
                renderer.fill(&display, whatever, &image_map);
                let mut target = display.draw();
                target.clear_color(0., 0., 0., 1.);
                renderer.draw(&display, &mut target, &image_map).expect("UI draw error");
                target.finish().expect("UI 'finish' error");
            }
        }
    }
}

pub fn main(config: &mut GameConfig) {
    let mut first_time = true;
    while let Some(game_thread) = start_game(config, first_time) {
        game_thread.join().expect("Unexpected thread error");
        first_time = false;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! TCP based DNS client

use std::net::SocketAddr;
use std::io;
use std::mem;
use std::fmt;

use mio::tcp::TcpStream;
use mio::{Token, EventLoop, Handler, EventSet, PollOpt}; // not * b/c don't want confusion with std::net

use ::error::*;
use ::client::ClientConnection;
use ::tcp::{TcpHandler, TcpState};

const RESPONSE: Token = Token(0);

/// TCP based DNS client
pub struct TcpClientConnection {
  handler: Option<TcpHandler>,
  event_loop: EventLoop<ClientHandler>,
  error: Option<ClientError>,
}

impl TcpClientConnection {
  /// Creates a new client connection.
  ///
  /// *Note* this has side affects of establishing the connection to the specified DNS server and
  ///        starting the event_loop. Expect this to change in the future.
  ///
  /// # Arguments
  ///
  /// * `name_server` - address of the name server to use for queries
  pub fn new(name_server: SocketAddr) -> ClientResult<Self> {
    // TODO: randomize local port binding issue #23
    //  probably not necessary for TCP...
    debug!("connecting to {:?}", name_server);
    let stream = try!(TcpStream::connect(&name_server));

    let mut event_loop: EventLoop<ClientHandler> = try!(EventLoop::new());
    // TODO make the timeout configurable, 5 seconds is the dig default
    // TODO the error is private to mio, which makes this awkward...
    if event_loop.timeout_ms((), 5000).is_err() { return Err(ClientErrorKind::Message("error setting timer").into()) };
    // TODO: Linux requires a register before a reregister, reregister is needed b/c of OSX later
    //  ideally this would not be added to the event loop until the client connection request.
    try!(event_loop.register(&stream, RESPONSE, EventSet::all(), PollOpt::all()));

    Ok(TcpClientConnection{ handler: Some(TcpHandler::new_client_handler(stream)), event_loop: event_loop, error: None })
  }
}

impl ClientConnection for TcpClientConnection {
  fn send(&mut self, buffer: Vec<u8> ) -> ClientResult<Vec<u8>> {
    self.error = None;
    // TODO: b/c of OSX this needs to be a reregister (since deregister is not working)
    // ideally it should be a register with the later deregister...
    try!(self.event_loop.reregister(self.handler.as_ref().expect("never none").get_stream(), RESPONSE, EventSet::all(), PollOpt::all()));
    // this is the request message, needs to be set each time
    // TODO: it would be cool to reuse this buffer.
    let mut handler = mem::replace(&mut self.handler, None).expect("never none");
    handler.set_buffer(buffer);
    let mut client_handler = ClientHandler{ handler: handler, error: None };
    let result = self.event_loop.run(&mut client_handler);
    self.handler = Some(client_handler.handler);

    try!(result);

    if self.error.is_some() { return Err(mem::replace(&mut self.error, None).unwrap()) }
    Ok(self.handler.as_mut().expect("never none").remove_buffer())
    //debug!("client deregistering");
    // TODO: when this line is added OSX starts failing, but we should have it...
//    try!(self.event_loop.deregister(&response.stream));
  }
}

impl fmt::Debug for TcpClientConnection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "TcpClientConnection: {:?}", self.handler.as_ref().expect("never none").get_stream())
  }
}

struct ClientHandler {
  pub handler: TcpHandler,
  pub error: Option<ClientError>,
}

// TODO: this should be merged with the server handler
impl Handler for ClientHandler {
  type Timeout = ();
  type Message = ();

  fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
    match token {
      RESPONSE => {
        if events.is_error() {
          warn!("closing, error from: {:?}", self.handler.get_stream());
          // TODO: do we need to shutdown the stream?
          event_loop.shutdown();
        } else if events.is_hup() {
          info!("client hungup: {:?}", self.handler.get_stream());
          // TODO: do we need to shutdown the stream?
          //remove = Some(RemoveFrom::TcpHandlers(token));
          event_loop.shutdown();
        } else if events.is_readable() || events.is_writable() {
          // the handler will deal with the rest of the connection, we need to check the return value
          //  for an error with wouldblock, this means that the handler couldn't complete the request.
          match self.handler.handle_message(events) {
            Ok(TcpState::Done) => {
              // the shutdown will stop the event_loop run to return the requester
              self.handler.reset();
              event_loop.shutdown();
            },
            Ok(..) => {
              // registering the event to only wake up on the correct event
              //  this reduces looping on states like writable that can remain set for a long time
              //if let Err(e) = event_loop.reregister(handler.get_stream(), token, handler.get_events(), PollOpt::level()) {
              debug!("reregistering for next call: {:?}", self.handler.get_events());
              if let Err(e) = event_loop.reregister(self.handler.get_stream(), token, self.handler.get_events(), PollOpt::all()) {
                  error!("could not reregister stream: {:?} cause: {}", self.handler.get_stream(), e);
                  // TODO: need to return an error here
                  //remove = Some(RemoveFrom::TcpHandlers(token));
              }
            },
            Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
              // this is expected with the connection would block
              // noop
            },
            Err(e) => {
              // shutdown the connection, remove it.
              warn!("connection: {:?} shutdown on error: {}", self.handler.get_stream(), e);
              // TODO: do we need to shutdown the stream?
              //remove = Some(RemoveFrom::TcpHandlers(token));
              // TODO: need to return an error here
              //self.error = Some(e);
              event_loop.shutdown();
            }
          }
        }
      },
      _ => {
        error!("unrecognized token: {:?}", token);
        self.error = Some(ClientErrorKind::Message("no data was received from the remote").into());
      },
    }
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, _: ()) {
    self.error = Some(ClientErrorKind::Message("timed out awaiting response from server(s)").into());
    event_loop.shutdown();
  }
}

// TODO: should test this independently of the client code
<commit_msg>TcpClientConnection needs to reregister itself after getting WouldBlock<commit_after>// Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! TCP based DNS client

use std::net::SocketAddr;
use std::io;
use std::mem;
use std::fmt;

use mio::tcp::TcpStream;
use mio::{Token, EventLoop, Handler, EventSet, PollOpt}; // not * b/c don't want confusion with std::net

use ::error::*;
use ::client::ClientConnection;
use ::tcp::{TcpHandler, TcpState};

const RESPONSE: Token = Token(0);

/// TCP based DNS client
pub struct TcpClientConnection {
  handler: Option<TcpHandler>,
  event_loop: EventLoop<ClientHandler>,
  error: Option<ClientError>,
}

impl TcpClientConnection {
  /// Creates a new client connection.
  ///
  /// *Note* this has side affects of establishing the connection to the specified DNS server and
  ///        starting the event_loop. Expect this to change in the future.
  ///
  /// # Arguments
  ///
  /// * `name_server` - address of the name server to use for queries
  pub fn new(name_server: SocketAddr) -> ClientResult<Self> {
    // TODO: randomize local port binding issue #23
    //  probably not necessary for TCP...
    debug!("connecting to {:?}", name_server);
    let stream = try!(TcpStream::connect(&name_server));

    let mut event_loop: EventLoop<ClientHandler> = try!(EventLoop::new());
    // TODO make the timeout configurable, 5 seconds is the dig default
    // TODO the error is private to mio, which makes this awkward...
    if event_loop.timeout_ms((), 5000).is_err() { return Err(ClientErrorKind::Message("error setting timer").into()) };
    // TODO: Linux requires a register before a reregister, reregister is needed b/c of OSX later
    //  ideally this would not be added to the event loop until the client connection request.
    try!(event_loop.register(&stream, RESPONSE, EventSet::all(), PollOpt::all()));

    Ok(TcpClientConnection{ handler: Some(TcpHandler::new_client_handler(stream)), event_loop: event_loop, error: None })
  }
}

impl ClientConnection for TcpClientConnection {
  fn send(&mut self, buffer: Vec<u8> ) -> ClientResult<Vec<u8>> {
    self.error = None;
    // TODO: b/c of OSX this needs to be a reregister (since deregister is not working)
    // ideally it should be a register with the later deregister...
    try!(self.event_loop.reregister(self.handler.as_ref().expect("never none").get_stream(), RESPONSE, EventSet::all(), PollOpt::all()));
    // this is the request message, needs to be set each time
    // TODO: it would be cool to reuse this buffer.
    let mut handler = mem::replace(&mut self.handler, None).expect("never none");
    handler.set_buffer(buffer);
    let mut client_handler = ClientHandler{ handler: handler, error: None };
    let result = self.event_loop.run(&mut client_handler);
    self.handler = Some(client_handler.handler);

    try!(result);

    if self.error.is_some() { return Err(mem::replace(&mut self.error, None).unwrap()) }
    Ok(self.handler.as_mut().expect("never none").remove_buffer())
    //debug!("client deregistering");
    // TODO: when this line is added OSX starts failing, but we should have it...
//    try!(self.event_loop.deregister(&response.stream));
  }
}

impl fmt::Debug for TcpClientConnection {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "TcpClientConnection: {:?}", self.handler.as_ref().expect("never none").get_stream())
  }
}

struct ClientHandler {
  pub handler: TcpHandler,
  pub error: Option<ClientError>,
}

// TODO: this should be merged with the server handler
impl Handler for ClientHandler {
  type Timeout = ();
  type Message = ();

  fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
    match token {
      RESPONSE => {
        if events.is_error() {
          warn!("closing, error from: {:?}", self.handler.get_stream());
          // TODO: do we need to shutdown the stream?
          event_loop.shutdown();
        } else if events.is_hup() {
          info!("client hungup: {:?}", self.handler.get_stream());
          // TODO: do we need to shutdown the stream?
          //remove = Some(RemoveFrom::TcpHandlers(token));
          event_loop.shutdown();
        } else if events.is_readable() || events.is_writable() {
          // the handler will deal with the rest of the connection, we need to check the return value
          //  for an error with wouldblock, this means that the handler couldn't complete the request.
          match self.handler.handle_message(events) {
            Ok(TcpState::Done) => {
              // the shutdown will stop the event_loop run to return the requester
              self.handler.reset();
              event_loop.shutdown();
            },
            Ok(..) => {
              // registering the event to only wake up on the correct event
              //  this reduces looping on states like writable that can remain set for a long time
              //if let Err(e) = event_loop.reregister(handler.get_stream(), token, handler.get_events(), PollOpt::level()) {
              debug!("reregistering for next call: {:?}", self.handler.get_events());
              if let Err(e) = event_loop.reregister(self.handler.get_stream(), token, self.handler.get_events(), PollOpt::all()) {
                  error!("could not reregister stream: {:?} cause: {}", self.handler.get_stream(), e);
                  // TODO: need to return an error here
                  //remove = Some(RemoveFrom::TcpHandlers(token));
              }
            },
            Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
              debug!("WouldBlock, reregistering for next call: {:?}", self.handler.get_events());
              if let Err(e) = event_loop.reregister(self.handler.get_stream(), token, self.handler.get_events(), PollOpt::all()) {
                  error!("could not reregister stream: {:?} cause: {}", self.handler.get_stream(), e);
                  // FIXME: Maybe it doesn't need reregistration on this system?
              }
            },
            Err(e) => {
              // shutdown the connection, remove it.
              warn!("connection: {:?} shutdown on error: {}", self.handler.get_stream(), e);
              // TODO: do we need to shutdown the stream?
              //remove = Some(RemoveFrom::TcpHandlers(token));
              // TODO: need to return an error here
              //self.error = Some(e);
              event_loop.shutdown();
            }
          }
        }
      },
      _ => {
        error!("unrecognized token: {:?}", token);
        self.error = Some(ClientErrorKind::Message("no data was received from the remote").into());
      },
    }
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, _: ()) {
    self.error = Some(ClientErrorKind::Message("timed out awaiting response from server(s)").into());
    event_loop.shutdown();
  }
}

// TODO: should test this independently of the client code
<|endoftext|>


<commit_before>// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Ccodegen-units=1
// ignore-tidy-linelength

// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number
// of entries.

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()",
// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >",
// CHECK: !DISubrange(count: 5

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
// CHECK: !DISubrange(count: 4

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
// CHECK: !DISubrange(count: 3

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::bar::{closure#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"

#![crate_type = "lib"]

pub struct Foo;

pub trait SomeTrait {
    fn method1(&self) -> u32;
    fn method2(&self) -> u32;
}

impl SomeTrait for Foo {
    fn method1(&self) -> u32 { 1 }
    fn method2(&self) -> u32 { 2 }
}

pub trait SomeTraitWithGenerics<T, U> {
    fn method1(&self) -> (T, U);
}

impl SomeTraitWithGenerics<u64, i8> for Foo {
    fn method1(&self) -> (u64, i8) { (1, 2) }
}

pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
    let y: &dyn SomeTrait = x;
    let z: &dyn SomeTraitWithGenerics<u64, i8> = x;
    (y.method1(), z.method1(), x as &dyn Send)
}

// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC
// because the trait type contains a late bound region that needed to be erased before the type
// layout for the niche enum `Option<&dyn Fn()>` could can be computed.
pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
    Box::new(|_x: Option<&dyn Fn()>| {})
}
<commit_msg>Update src/test/codegen/debug-vtable.rs<commit_after>// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Ccodegen-units=1
// ignore-tidy-linelength

// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number
// of entries.

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()",
// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >",
// CHECK: !DISubrange(count: 5

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
// CHECK: !DISubrange(count: 4

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
// CHECK: !DISubrange(count: 3

// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::bar::{closure#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"

#![crate_type = "lib"]

pub struct Foo;

pub trait SomeTrait {
    fn method1(&self) -> u32;
    fn method2(&self) -> u32;
}

impl SomeTrait for Foo {
    fn method1(&self) -> u32 { 1 }
    fn method2(&self) -> u32 { 2 }
}

pub trait SomeTraitWithGenerics<T, U> {
    fn method1(&self) -> (T, U);
}

impl SomeTraitWithGenerics<u64, i8> for Foo {
    fn method1(&self) -> (u64, i8) { (1, 2) }
}

pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
    let y: &dyn SomeTrait = x;
    let z: &dyn SomeTraitWithGenerics<u64, i8> = x;
    (y.method1(), z.method1(), x as &dyn Send)
}

// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC
// because the trait type contains a late bound region that needed to be erased before the type
// layout for the niche enum `Option<&dyn Fn()>` could be computed.
pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
    Box::new(|_x: Option<&dyn Fn()>| {})
}
<|endoftext|>


<commit_before>// Just a grab bug of stuff that you wouldn't want to actualy write

fn strange() -> bool { let _x = ret true; }

fn funny() {
    fn f(_x: ()) { }
    f(ret);
}

fn odd() {
    // FIXME: This doesn't compile
    // log ret;
}

fn what() {
    fn the(x: @mutable bool) { ret while !*x { *x = true; }; }
    let i = @mutable false;
    let dont = bind the(i);
    dont();
    assert (*i);
}

fn zombiejesus() {
    do  {
        while (ret) {
            if (ret) {
                alt (ret) { _ { ret ? ret : ret } };
            } else if (ret) {
                ret;
            }
        }
    } while ret
}

fn notsure() {
    let _x;
    let _y = (_x = 0) == (_x = 0);
    let _z = (_x <- 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = (_y <-> _z) == (_y <-> _z);
}

fn hammertime() -> int {
    // FIXME: Doesn't compile
    //let _x = log true == (ret 0);
    ret 0;
}

fn canttouchthis() -> uint {
    pure fn p() -> bool { true }
    let _a = (assert (true)) == (check (p()));
    let _c = (check (p())) == ();
    let _b = (log 0) == (ret 0u);
}

fn angrydome() {
    while true { if break { } }
    let i = 0;
    do  { i += 1; if i == 1 { alt cont { _ { } } } } while false
}

fn evil_lincoln() { let evil <- log "lincoln"; }

fn main() {
    strange();
    funny();
    odd();
    what();
    zombiejesus();
    notsure();
    hammertime();
    canttouchthis();
    angrydome();
    evil_lincoln();
}
<commit_msg>Remove FIXME test that's covered by run-pass/unreachable-code.rs<commit_after>// Just a grab bug of stuff that you wouldn't want to actualy write

fn strange() -> bool { let _x = ret true; }

fn funny() {
    fn f(_x: ()) { }
    f(ret);
}

fn what() {
    fn the(x: @mutable bool) { ret while !*x { *x = true; }; }
    let i = @mutable false;
    let dont = bind the(i);
    dont();
    assert (*i);
}

fn zombiejesus() {
    do  {
        while (ret) {
            if (ret) {
                alt (ret) { _ { ret ? ret : ret } };
            } else if (ret) {
                ret;
            }
        }
    } while ret
}

fn notsure() {
    let _x;
    let _y = (_x = 0) == (_x = 0);
    let _z = (_x <- 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = (_y <-> _z) == (_y <-> _z);
}

fn hammertime() -> int {
    // FIXME: Doesn't compile
    //let _x = log true == (ret 0);
    ret 0;
}

fn canttouchthis() -> uint {
    pure fn p() -> bool { true }
    let _a = (assert (true)) == (check (p()));
    let _c = (check (p())) == ();
    let _b = (log 0) == (ret 0u);
}

fn angrydome() {
    while true { if break { } }
    let i = 0;
    do  { i += 1; if i == 1 { alt cont { _ { } } } } while false
}

fn evil_lincoln() { let evil <- log "lincoln"; }

fn main() {
    strange();
    funny();
    what();
    zombiejesus();
    notsure();
    hammertime();
    canttouchthis();
    angrydome();
    evil_lincoln();
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![experimental]

use registry::{Registry, Ns};
use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::ptr::P;

pub struct GlobalGenerator;

impl super::Generator for GlobalGenerator {
    fn write(&self, ecx: &ExtCtxt, registry: &Registry, ns: Ns) -> Vec<P<ast::Item>> {
        let mut result = Vec::new();
        result.push(write_header(ecx));
        result.push(write_metaloadfn(ecx));
        result.push(write_type_aliases(ecx, &ns));
        result.extend(write_enums(ecx, registry).into_iter());
        result.extend(write_fns(ecx, registry).into_iter());
        result.extend(write_fnptr_struct_def(ecx).into_iter());
        result.push(write_ptrs(ecx, registry));
        result.extend(write_fn_mods(ecx, registry, &ns).into_iter());
        result.push(write_failing_fns(ecx, registry));
        result.extend(write_load_fn(ecx, registry).into_iter());
        result
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header(ecx: &ExtCtxt) -> P<ast::Item> {
    (quote_item!(ecx,
        mod __gl_imports {
            extern crate gl_common;
            extern crate libc;
            pub use std::mem;
        }
    )).unwrap()
}

/// Creates the metaloadfn function for fallbacks
fn write_metaloadfn(ecx: &ExtCtxt) -> P<ast::Item> {
    (quote_item!(ecx,
        fn metaloadfn(loadfn: |&str| -> *const __gl_imports::libc::c_void,
                      symbol: &str,
                      fallbacks: &[&str]) -> *const __gl_imports::libc::c_void {
            let mut ptr = loadfn(symbol);
            if ptr.is_null() {
                for &sym in fallbacks.iter() {
                    ptr = loadfn(sym);
                    if !ptr.is_null() { break; }
                }
            }
            ptr
        }
    )).unwrap()
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases(ecx: &ExtCtxt, ns: &Ns) -> P<ast::Item> {
    let aliases = super::gen_type_aliases(ecx, ns);

    (quote_item!(ecx,
        #[stable]
        pub mod types {
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]

            $aliases
        }
    )).unwrap()
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    registry.enum_iter().map(|e| {
        super::gen_enum_item(ecx, e, "types::")
    }).collect()
}

/// Creates the functions corresponding to the GL commands.
///
/// The function calls the corresponding function pointer stored in the `storage` module created
///  by `write_ptrs`.
fn write_fns(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    registry.cmd_iter().map(|c| {
        use syntax::ext::quote::rt::ToSource;

        let doc = match registry.aliases.find(&c.proto.ident) {
            Some(v) => format!("/** Fallbacks: {} */", v.connect(", ")),
            None => "".to_string()
        };

        ecx.parse_item(
            format!(
                "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
                #[inline] #[unstable] {doc} pub unsafe fn {name}({typed_params}) -> {return_suffix} {{ \
                    __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                        (storage::{name}.f)({idents}) \
                }}",
                name = c.proto.ident,
                doc = doc,
                typed_params = super::gen_parameters(ecx, c).into_iter().map(|p| p.to_source()).collect::<Vec<String>>().connect(", "),
                return_suffix = super::gen_return_type(ecx, c).to_source(),
                idents = super::gen_parameters(ecx, c).into_iter().map(|p| p.pat.to_source()).collect::<Vec<String>>().connect(", "),
            )
        )
    }).collect()
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def(ecx: &ExtCtxt) -> Vec<P<ast::Item>> {
    let mut result = Vec::new();

    result.push((quote_item!(ecx,
        pub struct FnPtr {
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }
    )).unwrap());

    result.push((quote_item!(ecx,
        impl FnPtr {
            /// Creates a `FnPtr` from a load attempt.
            pub fn new(ptr: *const __gl_imports::libc::c_void, failing_fn: *const __gl_imports::libc::c_void) -> FnPtr {
                if ptr.is_null() {
                    FnPtr { f: failing_fn, is_loaded: false }
                } else {
                    FnPtr { f: ptr, is_loaded: true }
                }
            }
        }
    )).unwrap());

    result
}

/// Creates a `storage` module which contains a static `FnPtr` per GL command in the registry.
fn write_ptrs(ecx: &ExtCtxt, registry: &Registry) -> P<ast::Item> {
    let storages = registry.cmd_iter().map(|c| {
        let name = ecx.ident_of(c.proto.ident.as_slice());

        (quote_item!(ecx,
            pub static mut $name: FnPtr = FnPtr {
                f: failing::$name as *const libc::c_void,
                is_loaded: false
            };
        )).unwrap()
    }).collect::<Vec<P<ast::Item>>>();

    (quote_item!(ecx,
        mod storage {
            #![allow(non_snake_case)]
            use super::__gl_imports::libc;
            use super::failing;
            use super::FnPtr;

            $storages
        }
    )).unwrap()
}

/// Creates one module for each GL command.
///
/// Each module contains `is_loaded` and `load_with` which interact with the `storage` module
///  created by `write_ptrs`.
fn write_fn_mods(ecx: &ExtCtxt, registry: &Registry, ns: &Ns) -> Vec<P<ast::Item>> {
    registry.cmd_iter().map(|c| {
        let fallbacks = match registry.aliases.find(&c.proto.ident) {
            Some(v) => {
                let names = v.iter().map(|name| format!("\"{}\"", super::gen_symbol_name(ns, name.as_slice()))).collect::<Vec<_>>();
                format!("[{}]", names.connect(", "))
            }, None => "[]".to_string(),
        };
        let fallbacks = ecx.parse_expr(fallbacks);
        let fnname = ecx.ident_of(c.proto.ident.as_slice());
        let symbol = super::gen_symbol_name(ns, c.proto.ident.as_slice());
        let symbol = symbol.as_slice();

        (quote_item!(ecx,
            #[unstable]
            #[allow(non_snake_case)]
            pub mod $fnname {
                use super::{failing, storage, metaloadfn};
                use super::FnPtr;

                #[inline]
                #[allow(dead_code)]
                pub fn is_loaded() -> bool {
                    unsafe { storage::$fnname.is_loaded }
                }

                #[allow(dead_code)]
                pub fn load_with(loadfn: |symbol: &str| -> *const super::__gl_imports::libc::c_void) {
                    unsafe {
                        storage::$fnname = FnPtr::new(metaloadfn(loadfn, $symbol, $fallbacks),
                            failing::$fnname as *const super::__gl_imports::libc::c_void)
                    }
                }
            }
        )).unwrap()
    }).collect()

    // TODO: this is a reliquate from an old code, I have no idea what it does
    // for c in self.registry.cmd_iter() {
    //     self.write_line(format!(
    //         "pub mod {name} {{ \
    //             #[inline] \
    //             pub fn is_loaded() -> bool {{ \
    //                 unsafe {{ ::storage::{name}.is_loaded }} \
    //             }} \
    //         }}",
    //         name = c.proto.ident,
    //     ).as_slice());
    // }
}

/// Creates a `failing` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_failing_fns(ecx: &ExtCtxt, registry: &Registry) -> P<ast::Item> {
    use syntax::ext::quote::rt::ToSource;

    let functions = registry.cmd_iter().map(|c| {
        ecx.parse_item(format!(
            "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
            pub extern \"system\" fn {name}({params}) -> {return_suffix} {{ \
                panic!(\"`{name}` was not loaded\") \
            }}",
            name = c.proto.ident,
            params = super::gen_parameters(ecx, c).into_iter().map(|p| p.to_source()).collect::<Vec<String>>().connect(", "),
            return_suffix = super::gen_return_type(ecx, c).to_source()
        ))
    }).collect::<Vec<P<ast::Item>>>();

    (quote_item!(ecx,
        mod failing {
            use super::types;
            use super::__gl_imports;

            $functions
        }
    )).unwrap()
}

/// Creates the `load_with` function.
///
/// The function calls `load_with` in each module created by `write_fn_mods`.
fn write_load_fn(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    let loadings = registry.cmd_iter().map(|c| {
        let cmd_name = ecx.ident_of(c.proto.ident.as_slice());
        quote_stmt!(ecx, $cmd_name::load_with(|s| loadfn(s));)
    }).collect::<Vec<P<ast::Stmt>>>();

    let a = (quote_item!(ecx,
        /// Load each OpenGL symbol using a custom load function. This allows for the
        /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
        /// ~~~ignore
        /// gl::load_with(|s| glfw.get_proc_address(s));
        /// ~~~
        #[unstable]
        #[allow(dead_code)]
        pub fn load_with(loadfn: |symbol: &str| -> *const __gl_imports::libc::c_void) {
            $loadings
        }
    )).unwrap();

    let b = (quote_item!(ecx,
        /// Load each OpenGL symbol using a custom load function.
        ///
        /// ~~~ignore
        /// gl::load(&glfw);
        /// ~~~
        #[unstable]
        #[allow(dead_code)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) {
            load_with(|name| loader.get_proc_addr(name));
        }
    )).unwrap();

    vec![a, b]
}
<commit_msg>Fix issue with static mut and quote_item!<commit_after>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![experimental]

use registry::{Registry, Ns};
use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::ptr::P;

pub struct GlobalGenerator;

impl super::Generator for GlobalGenerator {
    fn write(&self, ecx: &ExtCtxt, registry: &Registry, ns: Ns) -> Vec<P<ast::Item>> {
        let mut result = Vec::new();
        result.push(write_header(ecx));
        result.push(write_metaloadfn(ecx));
        result.push(write_type_aliases(ecx, &ns));
        result.extend(write_enums(ecx, registry).into_iter());
        result.extend(write_fns(ecx, registry).into_iter());
        result.extend(write_fnptr_struct_def(ecx).into_iter());
        result.push(write_ptrs(ecx, registry));
        result.extend(write_fn_mods(ecx, registry, &ns).into_iter());
        result.push(write_failing_fns(ecx, registry));
        result.extend(write_load_fn(ecx, registry).into_iter());
        result
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header(ecx: &ExtCtxt) -> P<ast::Item> {
    (quote_item!(ecx,
        mod __gl_imports {
            extern crate gl_common;
            extern crate libc;
            pub use std::mem;
        }
    )).unwrap()
}

/// Creates the metaloadfn function for fallbacks
fn write_metaloadfn(ecx: &ExtCtxt) -> P<ast::Item> {
    (quote_item!(ecx,
        fn metaloadfn(loadfn: |&str| -> *const __gl_imports::libc::c_void,
                      symbol: &str,
                      fallbacks: &[&str]) -> *const __gl_imports::libc::c_void {
            let mut ptr = loadfn(symbol);
            if ptr.is_null() {
                for &sym in fallbacks.iter() {
                    ptr = loadfn(sym);
                    if !ptr.is_null() { break; }
                }
            }
            ptr
        }
    )).unwrap()
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases(ecx: &ExtCtxt, ns: &Ns) -> P<ast::Item> {
    let aliases = super::gen_type_aliases(ecx, ns);

    (quote_item!(ecx,
        #[stable]
        pub mod types {
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]

            $aliases
        }
    )).unwrap()
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    registry.enum_iter().map(|e| {
        super::gen_enum_item(ecx, e, "types::")
    }).collect()
}

/// Creates the functions corresponding to the GL commands.
///
/// The function calls the corresponding function pointer stored in the `storage` module created
///  by `write_ptrs`.
fn write_fns(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    registry.cmd_iter().map(|c| {
        use syntax::ext::quote::rt::ToSource;

        let doc = match registry.aliases.find(&c.proto.ident) {
            Some(v) => format!("/** Fallbacks: {} */", v.connect(", ")),
            None => "".to_string()
        };

        ecx.parse_item(
            format!(
                "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
                #[inline] #[unstable] {doc} pub unsafe fn {name}({typed_params}) -> {return_suffix} {{ \
                    __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                        (storage::{name}.f)({idents}) \
                }}",
                name = c.proto.ident,
                doc = doc,
                typed_params = super::gen_parameters(ecx, c).into_iter().map(|p| p.to_source()).collect::<Vec<String>>().connect(", "),
                return_suffix = super::gen_return_type(ecx, c).to_source(),
                idents = super::gen_parameters(ecx, c).into_iter().map(|p| p.pat.to_source()).collect::<Vec<String>>().connect(", "),
            )
        )
    }).collect()
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def(ecx: &ExtCtxt) -> Vec<P<ast::Item>> {
    let mut result = Vec::new();

    result.push((quote_item!(ecx,
        pub struct FnPtr {
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }
    )).unwrap());

    result.push((quote_item!(ecx,
        impl FnPtr {
            /// Creates a `FnPtr` from a load attempt.
            pub fn new(ptr: *const __gl_imports::libc::c_void, failing_fn: *const __gl_imports::libc::c_void) -> FnPtr {
                if ptr.is_null() {
                    FnPtr { f: failing_fn, is_loaded: false }
                } else {
                    FnPtr { f: ptr, is_loaded: true }
                }
            }
        }
    )).unwrap());

    result
}

/// Creates a `storage` module which contains a static `FnPtr` per GL command in the registry.
fn write_ptrs(ecx: &ExtCtxt, registry: &Registry) -> P<ast::Item> {
    let storages = registry.cmd_iter().map(|c| {
        ecx.parse_item(format!(
            "pub static mut {name}: FnPtr = FnPtr {{
                f: failing::{name} as *const libc::c_void,
                is_loaded: false
            }};",
            name = c.proto.ident
        ))
    }).collect::<Vec<P<ast::Item>>>();

    (quote_item!(ecx,
        mod storage {
            #![allow(non_snake_case)]
            use super::__gl_imports::libc;
            use super::failing;
            use super::FnPtr;

            $storages
        }
    )).unwrap()
}

/// Creates one module for each GL command.
///
/// Each module contains `is_loaded` and `load_with` which interact with the `storage` module
///  created by `write_ptrs`.
fn write_fn_mods(ecx: &ExtCtxt, registry: &Registry, ns: &Ns) -> Vec<P<ast::Item>> {
    registry.cmd_iter().map(|c| {
        let fallbacks = match registry.aliases.find(&c.proto.ident) {
            Some(v) => {
                let names = v.iter().map(|name| format!("\"{}\"", super::gen_symbol_name(ns, name.as_slice()))).collect::<Vec<_>>();
                format!("[{}]", names.connect(", "))
            }, None => "[]".to_string(),
        };
        let fallbacks = ecx.parse_expr(fallbacks);
        let fnname = ecx.ident_of(c.proto.ident.as_slice());
        let symbol = super::gen_symbol_name(ns, c.proto.ident.as_slice());
        let symbol = symbol.as_slice();

        (quote_item!(ecx,
            #[unstable]
            #[allow(non_snake_case)]
            pub mod $fnname {
                use super::{failing, storage, metaloadfn};
                use super::FnPtr;

                #[inline]
                #[allow(dead_code)]
                pub fn is_loaded() -> bool {
                    unsafe { storage::$fnname.is_loaded }
                }

                #[allow(dead_code)]
                pub fn load_with(loadfn: |symbol: &str| -> *const super::__gl_imports::libc::c_void) {
                    unsafe {
                        storage::$fnname = FnPtr::new(metaloadfn(loadfn, $symbol, $fallbacks),
                            failing::$fnname as *const super::__gl_imports::libc::c_void)
                    }
                }
            }
        )).unwrap()
    }).collect()

    // TODO: this is a reliquate from an old code, I have no idea what it does
    // for c in self.registry.cmd_iter() {
    //     self.write_line(format!(
    //         "pub mod {name} {{ \
    //             #[inline] \
    //             pub fn is_loaded() -> bool {{ \
    //                 unsafe {{ ::storage::{name}.is_loaded }} \
    //             }} \
    //         }}",
    //         name = c.proto.ident,
    //     ).as_slice());
    // }
}

/// Creates a `failing` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_failing_fns(ecx: &ExtCtxt, registry: &Registry) -> P<ast::Item> {
    use syntax::ext::quote::rt::ToSource;

    let functions = registry.cmd_iter().map(|c| {
        ecx.parse_item(format!(
            "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
            pub extern \"system\" fn {name}({params}) -> {return_suffix} {{ \
                panic!(\"`{name}` was not loaded\") \
            }}",
            name = c.proto.ident,
            params = super::gen_parameters(ecx, c).into_iter().map(|p| p.to_source()).collect::<Vec<String>>().connect(", "),
            return_suffix = super::gen_return_type(ecx, c).to_source()
        ))
    }).collect::<Vec<P<ast::Item>>>();

    (quote_item!(ecx,
        mod failing {
            use super::types;
            use super::__gl_imports;

            $functions
        }
    )).unwrap()
}

/// Creates the `load_with` function.
///
/// The function calls `load_with` in each module created by `write_fn_mods`.
fn write_load_fn(ecx: &ExtCtxt, registry: &Registry) -> Vec<P<ast::Item>> {
    let loadings = registry.cmd_iter().map(|c| {
        let cmd_name = ecx.ident_of(c.proto.ident.as_slice());
        quote_stmt!(ecx, $cmd_name::load_with(|s| loadfn(s));)
    }).collect::<Vec<P<ast::Stmt>>>();

    let a = (quote_item!(ecx,
        /// Load each OpenGL symbol using a custom load function. This allows for the
        /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
        /// ~~~ignore
        /// gl::load_with(|s| glfw.get_proc_address(s));
        /// ~~~
        #[unstable]
        #[allow(dead_code)]
        pub fn load_with(loadfn: |symbol: &str| -> *const __gl_imports::libc::c_void) {
            $loadings
        }
    )).unwrap();

    let b = (quote_item!(ecx,
        /// Load each OpenGL symbol using a custom load function.
        ///
        /// ~~~ignore
        /// gl::load(&glfw);
        /// ~~~
        #[unstable]
        #[allow(dead_code)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) {
            load_with(|name| loader.get_proc_addr(name));
        }
    )).unwrap();

    vec![a, b]
}
<|endoftext|>


<commit_before>use std::{fmt, iter};
use std::rc::Rc;
use std::fmt::Write;

use seax::compiler_tools::ForkTable;

pub mod ast;
pub mod types;

use ast::*;
use self::types::{Annotated, Type};

pub type SymbolTable<'a> = ForkTable<'a, String, Type>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression
    /// at the desired indentation level.
    fn to_sexpr(&self, level: usize) -> String;
    /// Analyse this node & annotate it with the appropriate type state.
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self>;

}

impl ASTNode for Form {

    fn to_sexpr(&self, level: usize) -> String {
        match self {
            &Form::Define(ref form) => form.to_sexpr(level),
        }
    }

    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for Ident {

    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for DefForm {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})", indent!(level),
                    name.to_sexpr(level),
                    annot.to_sexpr(level),
                    value.to_sexpr(level+1)
                    ),
            DefForm::Function { ref name, ref annot, ref formals, ref body } =>
                format!("{}(define {} {} {}\n{})", indent!(level),
                    name.to_sexpr(level),
                    annot.to_sexpr(level),
                    formals.iter().fold(String::new(), |mut s, f| {
                        s.push_str(&f.to_sexpr(level)); s
                        }),
                    body.to_sexpr(level + 1)
                    )
        }
    }

    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for Formal {

    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}
<commit_msg>Add Rustdoc comments<commit_after>use std::{fmt, iter};
use std::rc::Rc;
use std::fmt::Write;

use seax::compiler_tools::ForkTable;

pub mod ast;
pub mod types;

use ast::*;
use self::types::{Annotated, Type};

/// A symbol table is a `ForkTable` mapping `String`s to `Type` annotations.
///
/// This table should be forked upon entering a new scope.
pub type SymbolTable<'a> = ForkTable<'a, String, Type>;

macro_rules! indent {
    ($to:expr) => ( iter::repeat('\t')
                        .take($to)
                        .collect::<String>() )
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait ASTNode: Sized {

    /// Pretty-print the AST node as an S-expression at the desired
    /// indentation level.
    ///
    /// Note that this prints the desugared form and may not be a perfect
    /// match for the original source code.
    fn to_sexpr(&self, level: usize) -> String;

    /// Analyse this node & annotate it with the appropriate type state.
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self>;

}

impl ASTNode for Form {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match self {
            &Form::Define(ref form) => form.to_sexpr(level),
        }
    }

    #[allow(unused_variables)]
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

    #[allow(unused_variables)]
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for DefForm {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})", indent!(level),
                    name.to_sexpr(level),
                    annot.to_sexpr(level),
                    value.to_sexpr(level+1)
                    ),
            DefForm::Function { ref name, ref annot, ref formals, ref body } =>
                format!("{}(define {} {} {}\n{})", indent!(level),
                    name.to_sexpr(level),
                    annot.to_sexpr(level),
                    formals.iter().fold(String::new(), |mut s, f| {
                        s.push_str(&f.to_sexpr(level)); s
                        }),
                    body.to_sexpr(level + 1)
                    )
        }
    }

    #[allow(unused_variables)]
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}

impl ASTNode for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

    #[allow(unused_variables)]
    fn analyze<'a>(self, scope: SymbolTable) -> Annotated<'a, Self> {
        unimplemented!() //TODO: implement
    }

}
<|endoftext|>