<commit_before>extern crate libc;
use libc::{c_float, c_int, c_void, size_t};
use native_window::ANativeWindow;

mod egl;
mod gl;
mod native_window;
mod log;

// TODO: implement.
struct ANativeActivity {
  dummy: *const c_void,
}
// TODO: implement.
struct AConfiguration {
  dummy: *const c_void,
}
// TODO: implement.
struct ALooper {
  dummy: *const c_void,
}
// TODO: implement.
struct AInputQueue {
  dummy: *const c_void,
}

struct ARect {
  left: i32,
  top: i32,
  right: i32,
  bottom: i32,
}

// This is the interface for the standard glue code of a threaded application.  In this model, the
// application's code is running in its own thread separate from the main thread of the process.
// It is not required that this thread be associated with the Java VM, although it will need to be
// in order to make JNI calls to any Java objects.  Compatible with C.
struct AndroidApp {
  // The application can place a pointer to its own state object here if it likes.
  user_data: *const c_void,
  // Fill this in with the function to process main app commands (APP_CMD_*)
  // TODO: implement.
  on_app_cmd: *const c_void,
  // Fill this in with the function to process input events.  At this point the event has already
  // been pre-dispatched, and it will be finished upon return.  Return 1 if you have handled
  // the event, 0 for any default dispatching.
  on_input_event: *const c_void,
  // The ANativeActivity object instance that this app is running in.
  activity: *const ANativeActivity,
  // The current configuration the app is running in.
  config: *const AConfiguration,
  // This is the last instance's saved state, as provided at creation time.  It is NULL if there
  // was no state.  You can use this as you need; the memory will remain around until you call
  // android_app_exec_cmd() for APP_CMD_RESUME, at which point it will be freed and savedState
  // set to NULL.  These variables should only be changed when processing a APP_CMD_SAVE_STATE,
  // at which point they will be initialized to NULL and you can malloc your state and place
  // the information here.  In that case the memory will be freed for you later.
  saved_state: *const c_void,
  saved_state_size: size_t,
  // The ALooper associated with the app's thread.
  looper: *const ALooper,
  // When non-NULL, this is the input queue from which the app will receive user input events.
  input_queue: *const AInputQueue,
  // When non-NULL, this is the window surface that the app can draw in.
  window: *const ANativeWindow,
  // Current content rectangle of the window; this is the area where the window's content should be
  // placed to be seen by the user.
  content_rect: ARect,
  // Current state of the app's activity.  May be either APP_CMD_START, APP_CMD_RESUME,
  // APP_CMD_PAUSE, or APP_CMD_STOP; see below.
  activity_state: c_int,
  // This is non-zero when the application's NativeActivity is being destroyed and waiting for
  // the app thread to complete.
  destroy_requested: c_int,
  // Plus some private implementation details.
}

// TODO: implement.
struct ASensorManager {
  dummy: *const c_void,
}
// TODO: implement.
struct ASensor {
  dummy: *const c_void,
}
// TODO: implement.
struct ASensorEventQueue {
  dummy: *const c_void,
}

// Saved state data.  Compatible with C.
struct SavedState {
  angle: c_float,
  x: i32,
  y: i32,
}

// Shared state for our app.  Compatible with C.
struct Engine {
  app: *const AndroidApp,

  sensor_manager: *const ASensorManager,
  accelerometer_sensor: *const ASensor,
  sensor_event_queue: *const ASensorEventQueue,

  animating: c_int,
  display: egl::Display,
  surface: egl::Surface,
  context: egl::Context,
  width: i32,
  height: i32,
  state: SavedState,
}

/// Initialize EGL context for the current display.
#[no_mangle]
pub extern fn init_display(engine: &mut Engine) -> c_int {
  let display = egl::get_display(egl::DEFAULT_DISPLAY);

  match egl::initialize(display) {
    Ok(_) => (),
    Err(e) => {
      log::e_f(format!("egl::initialize() failed: {}", e));
      fail!();
    },
  };

  // Here specify the attributes of the desired configuration.  Below, we select an EGLConfig with
  // at least 8 bits per color component compatible with OpenGL ES 2.0.  A very simplified
  // selection process, where we pick the first EGLConfig that matches our criteria.
  let attribs_config = [
    egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT,
    egl::BLUE_SIZE, 8,
    egl::GREEN_SIZE, 8,
    egl::RED_SIZE, 8,
    egl::NONE
  ];
  let mut configs = vec!(0 as egl::Config);
  match egl::choose_config(display, attribs_config, &mut configs) {
    Ok(_) => (),
    Err(e) => {
      log::e_f(format!("egl::choose_config() failed: {}", e));
      fail!();
    },
  }
  if configs.len() == 0 {
    log::e("choose_config() did not find any configurations");
    fail!();
  }
  let config = *configs.get(0);

  // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by
  // ANativeWindow_setBuffersGeometry().  As soon as we picked a EGLConfig, we can safely
  // reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
  let format = match egl::get_config_attrib(display, config, egl::NATIVE_VISUAL_ID) {
    Ok(vid) => vid,
    Err(e) => {
      log::e_f(format!("egl::get_config_attrib() failed: {}", e));
      fail!();
    },
  };

  let window = unsafe { (*engine.app).window };
  native_window::set_buffers_geometry(window, 0, 0, format);

  let surface = match egl::create_window_surface(display, config, window) {
    Ok(srf) => srf,
    Err(e) => {
      log::e_f(format!("egl::create_window_surface() failed: {}", e));
      fail!();
    },
  };

  let attribs_context = [
    egl::CONTEXT_CLIENT_VERSION, 2,
    egl::NONE
  ];
  let context = match egl::create_context_with_attribs(display, config, egl::NO_CONTEXT, attribs_context) {
    Ok(ctx) => ctx,
    Err(e) => {
      log::e_f(format!("egl::create_context() failed: {}", e));
      fail!();
    },
  };

  match egl::make_current(display, surface, surface, context) {
    Ok(()) => (),
    Err(_) => {
      log::w("Unable to egl::make_current");
      return -1;
    }
  }

  let version = match gl::get_string(gl::VERSION) {
    Ok(s) => s,
    Err(e) => {
      log::e_f(format!("gl::get_string(gl::VERSION) failed: {}", e));
      fail!();
    },
  };
  let vendor = match gl::get_string(gl::VENDOR) {
    Ok(s) => s,
    Err(e) => {
      log::e_f(format!("gl::get_string(gl::VENDOR) failed: {}", e));
      fail!();
    },
  };
  let renderer = match gl::get_string(gl::RENDERER) {
    Ok(s) => s,
    Err(e) => {
      log::e_f(format!("gl::get_string(gl::RENDERER) failed: {}", e));
      fail!();
    },
  };
  let sl_version = match gl::get_string(gl::SHADING_LANGUAGE_VERSION) {
    Ok(s) => s,
    Err(e) => {
      log::e_f(format!("gl::get_string(gl::SHADING_LANGUAGE_VERSION) failed: {}", e));
      fail!();
    },
  };
  log::i_f(format!("OpenGL version: \"{}\", vendor: \"{}\", renderer: \"{}\", SL version: \"{}\"",
    version.as_str().unwrap(), vendor.as_str().unwrap(), renderer.as_str().unwrap(),
    sl_version.as_str().unwrap()));

  let extensions = match gl::get_string(gl::EXTENSIONS) {
    Ok(s) => s,
    Err(e) => {
      log::e_f(format!("gl::get_string(gl::EXTENSIONS) failed: {}", e));
      fail!();
    },
  };
  log::i_f(format!("OpenGL extensions: \"{}\"", extensions.as_str().unwrap()));

  let w = match egl::query_surface(display, surface, egl::WIDTH) {
    Ok(i) => i,
    Err(e) => {
      log::e_f(format!("egl::query_surface(egl::WIDTH) failed: {}", e));
      fail!();
    },
  };
  let h = match egl::query_surface(display, surface, egl::HEIGHT) {
    Ok(i) => i,
    Err(e) => {
      log::e_f(format!("egl::query_surface(egl::HEIGHT) failed: {}", e));
      fail!();
    },
  };

  engine.display = display;
  engine.context = context;
  engine.surface = surface;
  engine.width = w;
  engine.height = h;
  engine.state.angle = 0.0;

  match gl::enable(gl::CULL_FACE) {
    Ok(()) => (),
    Err(e) => {
      log::e_f(format!("gl::enable(gl::CULL_FACE) failed: {}", e));
      fail!();
    },
  };
  match gl::disable(gl::DEPTH_TEST) {
    Ok(()) => (),
    Err(e) => {
      log::e_f(format!("gl::disable(gl::DEPTH_TEST) failed: {}", e));
      fail!();
    },
  };

  return 0;
}

/// Draw the current frame on display.
#[no_mangle]
pub extern fn draw_frame(engine: &Engine) {
  if engine.display == 0 as egl::Display {
    // No display.
    return;
  }

  // Just fill the screen with a color.
  let r = (engine.state.x as f32) / (engine.width as f32);
  let g = engine.state.angle;
  let b = (engine.state.y as f32) / (engine.height as f32);
  gl::clear_color(r, g, b, 1.0);

  match gl::clear(gl::COLOR_BUFFER_BIT) {
    Ok(()) => (),
    Err(e) => {
      log::e_f(format!("gl::clear(gl::COLOR_BUFFER_BIT) failed: {}", e));
      fail!();
    },
  };
  match egl::swap_buffers(engine.display, engine.surface) {
    Ok(()) => (),
    Err(e) => {
      log::e_f(format!("egl::swap_buffers() failed: {}", e));
      fail!();
    },
  };
}

/// Tear down the EGL context currently associated with the display.
#[no_mangle]
pub extern fn term_display(engine: &mut Engine) {
  if engine.display != egl::NO_DISPLAY {
    match egl::make_current(engine.display, egl::NO_SURFACE, egl::NO_SURFACE, egl::NO_CONTEXT) {
      Ok(()) => (),
      Err(e) => {
        log::e_f(format!("egl::make_current() failed: {}", e));
        fail!();
      },
    };
    if engine.context != egl::NO_CONTEXT {
      match egl::destroy_context(engine.display, engine.context) {
        Ok(()) => (),
        Err(e) => {
          log::e_f(format!("egl::destroy_context() failed: {}", e));
          fail!();
        },
      };
    }
    if engine.surface != egl::NO_SURFACE {
      match egl::destroy_surface(engine.display, engine.surface) {
        Ok(()) => (),
        Err(e) => {
          log::e_f(format!("egl::destroy_surface() failed: {}", e));
          fail!();
        },
      };
    }
    match egl::terminate(engine.display) {
      Ok(()) => (),
      Err(e) => {
        log::e_f(format!("egl::terminate() failed: {}", e));
        fail!();
      },
    }
  }

  engine.animating = 0;
  engine.display = egl::NO_DISPLAY;
  engine.context = egl::NO_CONTEXT;
  engine.surface = egl::NO_SURFACE;
}
<commit_msg>Add macro gl_try!, use it everywhere in main.rs.<commit_after>#![feature(macro_rules)]

extern crate libc;
use libc::{c_float, c_int, c_void, size_t};
use native_window::ANativeWindow;

mod egl;
mod gl;
mod native_window;
mod log;

// Macro that logs an Android error on error and terminates.
macro_rules! gl_try( ($n: expr, $e: expr) => (
  match $e {
    Ok(e) => e,
    Err(e) => {
      log::e_f(format!("{} failed: {}", $n, e));
      fail!();
    }
  }
))

// TODO: implement.
struct ANativeActivity {
  dummy: *const c_void,
}
// TODO: implement.
struct AConfiguration {
  dummy: *const c_void,
}
// TODO: implement.
struct ALooper {
  dummy: *const c_void,
}
// TODO: implement.
struct AInputQueue {
  dummy: *const c_void,
}

struct ARect {
  left: i32,
  top: i32,
  right: i32,
  bottom: i32,
}

// This is the interface for the standard glue code of a threaded application.  In this model, the
// application's code is running in its own thread separate from the main thread of the process.
// It is not required that this thread be associated with the Java VM, although it will need to be
// in order to make JNI calls to any Java objects.  Compatible with C.
struct AndroidApp {
  // The application can place a pointer to its own state object here if it likes.
  user_data: *const c_void,
  // Fill this in with the function to process main app commands (APP_CMD_*)
  // TODO: implement.
  on_app_cmd: *const c_void,
  // Fill this in with the function to process input events.  At this point the event has already
  // been pre-dispatched, and it will be finished upon return.  Return 1 if you have handled
  // the event, 0 for any default dispatching.
  on_input_event: *const c_void,
  // The ANativeActivity object instance that this app is running in.
  activity: *const ANativeActivity,
  // The current configuration the app is running in.
  config: *const AConfiguration,
  // This is the last instance's saved state, as provided at creation time.  It is NULL if there
  // was no state.  You can use this as you need; the memory will remain around until you call
  // android_app_exec_cmd() for APP_CMD_RESUME, at which point it will be freed and savedState
  // set to NULL.  These variables should only be changed when processing a APP_CMD_SAVE_STATE,
  // at which point they will be initialized to NULL and you can malloc your state and place
  // the information here.  In that case the memory will be freed for you later.
  saved_state: *const c_void,
  saved_state_size: size_t,
  // The ALooper associated with the app's thread.
  looper: *const ALooper,
  // When non-NULL, this is the input queue from which the app will receive user input events.
  input_queue: *const AInputQueue,
  // When non-NULL, this is the window surface that the app can draw in.
  window: *const ANativeWindow,
  // Current content rectangle of the window; this is the area where the window's content should be
  // placed to be seen by the user.
  content_rect: ARect,
  // Current state of the app's activity.  May be either APP_CMD_START, APP_CMD_RESUME,
  // APP_CMD_PAUSE, or APP_CMD_STOP; see below.
  activity_state: c_int,
  // This is non-zero when the application's NativeActivity is being destroyed and waiting for
  // the app thread to complete.
  destroy_requested: c_int,
  // Plus some private implementation details.
}

// TODO: implement.
struct ASensorManager {
  dummy: *const c_void,
}
// TODO: implement.
struct ASensor {
  dummy: *const c_void,
}
// TODO: implement.
struct ASensorEventQueue {
  dummy: *const c_void,
}

// Saved state data.  Compatible with C.
struct SavedState {
  angle: c_float,
  x: i32,
  y: i32,
}

// Shared state for our app.  Compatible with C.
struct Engine {
  app: *const AndroidApp,

  sensor_manager: *const ASensorManager,
  accelerometer_sensor: *const ASensor,
  sensor_event_queue: *const ASensorEventQueue,

  animating: c_int,
  display: egl::Display,
  surface: egl::Surface,
  context: egl::Context,
  width: i32,
  height: i32,
  state: SavedState,
}

/// Initialize EGL context for the current display.
#[no_mangle]
pub extern fn init_display(engine: &mut Engine) -> c_int {
  let display = egl::get_display(egl::DEFAULT_DISPLAY);

  gl_try!("egl::initialize", egl::initialize(display));

  // Here specify the attributes of the desired configuration.  Below, we select an EGLConfig with
  // at least 8 bits per color component compatible with OpenGL ES 2.0.  A very simplified
  // selection process, where we pick the first EGLConfig that matches our criteria.
  let attribs_config = [
    egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT,
    egl::BLUE_SIZE, 8,
    egl::GREEN_SIZE, 8,
    egl::RED_SIZE, 8,
    egl::NONE
  ];
  let mut configs = vec!(0 as egl::Config);
  gl_try!("egl::choose_config", egl::choose_config(display, attribs_config, &mut configs));
  if configs.len() == 0 {
    log::e("choose_config() did not find any configurations");
    fail!();
  }
  let config = *configs.get(0);

  // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by
  // ANativeWindow_setBuffersGeometry().  As soon as we picked a EGLConfig, we can safely
  // reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
  let format = gl_try!("egl::get_config_attrib",
    egl::get_config_attrib(display, config, egl::NATIVE_VISUAL_ID));

  let window = unsafe { (*engine.app).window };
  native_window::set_buffers_geometry(window, 0, 0, format);

  let surface = gl_try!("egl::create_window_surface", egl::create_window_surface(display, config, window));

  let attribs_context = [
    egl::CONTEXT_CLIENT_VERSION, 2,
    egl::NONE
  ];
  let context = gl_try!("egl::create_context_with_attribs",
    egl::create_context_with_attribs(display, config, egl::NO_CONTEXT, attribs_context));

  gl_try!("egl::make_current", egl::make_current(display, surface, surface, context));

  let version = gl_try!("gl::get_string(gl::VERSION)", gl::get_string(gl::VERSION));
  let vendor = gl_try!("gl::get_string(gl::VENDOR)", gl::get_string(gl::VENDOR));
  let renderer = gl_try!("gl::get_string(gl::RENDERER)", gl::get_string(gl::RENDERER));
  let sl_version = gl_try!("gl::get_string(gl::SHADING_LANGUAGE_VERSION)",
    gl::get_string(gl::SHADING_LANGUAGE_VERSION));
  log::i_f(format!("OpenGL version: \"{}\", vendor: \"{}\", renderer: \"{}\", SL version: \"{}\"",
    version.as_str().unwrap(), vendor.as_str().unwrap(), renderer.as_str().unwrap(),
    sl_version.as_str().unwrap()));

  let extensions = gl_try!("gl::get_string(gl::EXTENSIONS)", gl::get_string(gl::EXTENSIONS));
  log::i_f(format!("OpenGL extensions: \"{}\"", extensions.as_str().unwrap()));

  let w = gl_try!("egl::query_surface(egl::WIDTH)", egl::query_surface(display, surface, egl::WIDTH));
  let h = gl_try!("egl::query_surface(egl::HEIGHT)", egl::query_surface(display, surface, egl::HEIGHT));

  engine.display = display;
  engine.context = context;
  engine.surface = surface;
  engine.width = w;
  engine.height = h;
  engine.state.angle = 0.0;

  gl_try!("gl::enable(gl::CULL_FACE)", gl::enable(gl::CULL_FACE));
  gl_try!("gl::disable(gl::DEPTH_TEST)", gl::disable(gl::DEPTH_TEST));

  return 0;
}

/// Draw the current frame on display.
#[no_mangle]
pub extern fn draw_frame(engine: &Engine) {
  if engine.display == 0 as egl::Display {
    // No display.
    return;
  }

  // Just fill the screen with a color.
  let r = (engine.state.x as f32) / (engine.width as f32);
  let g = engine.state.angle;
  let b = (engine.state.y as f32) / (engine.height as f32);
  gl::clear_color(r, g, b, 1.0);

  gl_try!("gl::clear(gl::COLOR_BUFFER_BIT)", gl::clear(gl::COLOR_BUFFER_BIT));
  gl_try!("egl::swap_buffers", egl::swap_buffers(engine.display, engine.surface));
}

/// Tear down the EGL context currently associated with the display.
#[no_mangle]
pub extern fn term_display(engine: &mut Engine) {
  if engine.display != egl::NO_DISPLAY {
    gl_try!("egl::make_current",
      egl::make_current(engine.display, egl::NO_SURFACE, egl::NO_SURFACE, egl::NO_CONTEXT));
    if engine.context != egl::NO_CONTEXT {
      gl_try!("egl::destroy_context", egl::destroy_context(engine.display, engine.context));
    }
    if engine.surface != egl::NO_SURFACE {
      gl_try!("egl::destroy_surface", egl::destroy_surface(engine.display, engine.surface));
    }
    gl_try!("egl::terminate", egl::terminate(engine.display));
  }

  engine.animating = 0;
  engine.display = egl::NO_DISPLAY;
  engine.context = egl::NO_CONTEXT;
  engine.surface = egl::NO_SURFACE;
}
<|endoftext|>


<commit_before>//! This module implements the todr command execution logic.

use std::cmp::Ordering;
use std::collections::HashMap;
use std::env;

use reqwest;

// Use our internal types module.
use renderer;
use types;

// Endpoint for REST communication with the Todoist.
static TODOIST_API: &'static str = "https://todoist.com/API/v8/sync";

/// Used to specify what resources to fetch from the server.
/// It should be a JSON-encoded array of strings.
///
/// Here is a list of available resource types:
/// -  labels,
/// -  projects,
/// -  items,
/// -  notes,
/// -  filters,
/// -  reminders,
/// -  locations,
/// -  user,
/// -  `live_notifications`,
/// -  collaborators,
/// - `notification_settings`
///
enum TodrResourceType {
    Items,
    Projects,
}

fn to_resource_type(resource_type: &TodrResourceType) -> String {
    let resource = match resource_type {
        TodrResourceType::Items => String::from("items"),
        TodrResourceType::Projects => String::from("projects"),
    };

    format!("[\"{}\"]", &resource)
}

fn execute_request(resource_type: &TodrResourceType) -> Result<reqwest::Response, reqwest::Error> {
    // Fetch the token from the users environment.
    let auth_token = env::var("TODR_AUTHTOKEN").expect("TODR_AUTHTOKEN is not set!");

    // Map the resource type to the proper string.
    let resource_string = to_resource_type(resource_type);

    // Setup the request parameters.
    //
    // See the API documentation available for the full
    // list of parameters, their values and what they do.
    //
    // Link: https://developer.todoist.com/sync/v8/?shell
    //
    let sync_token: String = "*".to_string();
    let all_data: String = "true".to_string();
    let mut params = HashMap::new();
    params.insert("token", &auth_token);
    params.insert("sync_token", &sync_token);
    params.insert("resource_types", &resource_string);
    params.insert("all_data", &all_data);

    let client = reqwest::Client::new();

    // Issue the request.
    client.get(TODOIST_API).form(&params).send()
}

//
// Request response handler implementations.
//

fn process_error(error: &reqwest::Error) {
    println!("{}", error);
}

fn process_response_items(mut response: reqwest::Response) {
    let sync_state: types::SyncStruct = response
        .json()
        .expect("Failed to deserialize json response");

    let mut items = sync_state.items.expect("Failed to parse items JSON");

    // Sort the items by their server order.
    let custom_sort = |a: &types::ItemStruct, b: &types::ItemStruct| {
        let item_order_sort = a.item_order.cmp(&b.item_order);
        let project_order_sort = a.project_id.cmp(&b.project_id);

        // item_order values are only unique per project, so if we want to
        // display items in the correct order we need to sort by project
        // groupings first, and then sort by item order.
        if project_order_sort == Ordering::Equal {
            item_order_sort
        } else {
            project_order_sort
        }
    };

    items.sort_by(custom_sort);

    for item in items {
        renderer::render_item(&item);
    }
}

fn process_response_projects(mut response: reqwest::Response) {
    let sync_state: types::SyncStruct = response
        .json()
        .expect("Failed to deserialize json response");

    // Sort the items by their server order.
    //
    let mut projects = sync_state.projects.expect("Failed to parse projects JSON");
    projects.sort_by_key(|p| p.item_order);

    for project in projects {
        renderer::render_project(&project);
    }
}

//
// Command handler implementations.
//

pub fn items_command() {
    let response = execute_request(&TodrResourceType::Items);

    match response {
        Ok(r) => process_response_items(r),
        Err(e) => process_error(&e),
    }
}

pub fn projects_command() {
    let response = execute_request(&TodrResourceType::Projects);

    match response {
        Ok(r) => process_response_projects(r),
        Err(e) => process_error(&e),
    }
}

pub fn help_command() {
    println!();
    println!("Commands:");
    println!();
    println!("  h | help  - This help message");
    println!();
    println!("  i | items - List all active todo items.");
    println!();
    println!("  p | projs - List all active projects.");
    println!();
    println!("  q | quit  - Exit the application.");
    println!();
}

pub fn unknown_command(command: &str) {
    println!("Unknown Command: {}", command);
}
<commit_msg>Bug: Fix HTTP request, use query instead of form.<commit_after>//! This module implements the todr command execution logic.

use std::cmp::Ordering;
use std::collections::HashMap;
use std::env;

use reqwest;

// Use our internal types module.
use renderer;
use types;

// Endpoint for REST communication with the Todoist.
static TODOIST_API: &'static str = "https://todoist.com/API/v7/sync";

/// Used to specify what resources to fetch from the server.
/// It should be a JSON-encoded array of strings.
///
/// Here is a list of available resource types:
/// -  labels,
/// -  projects,
/// -  items,
/// -  notes,
/// -  filters,
/// -  reminders,
/// -  locations,
/// -  user,
/// -  `live_notifications`,
/// -  collaborators,
/// - `notification_settings`
///
enum TodrResourceType {
    Items,
    Projects,
}

fn to_resource_type(resource_type: &TodrResourceType) -> String {
    let resource = match resource_type {
        TodrResourceType::Items => String::from("items"),
        TodrResourceType::Projects => String::from("projects"),
    };

    format!("[\"{}\"]", &resource)
}

fn execute_request(resource_type: &TodrResourceType) -> Result<reqwest::Response, reqwest::Error> {
    // Fetch the token from the users environment.
    let auth_token = env::var("TODR_AUTHTOKEN").expect("TODR_AUTHTOKEN is not set!");

    // Map the resource type to the proper string.
    let resource_string = to_resource_type(resource_type);

    // Setup the request parameters.
    //
    // See the API documentation available for the full
    // list of parameters, their values and what they do.
    //
    // Link: https://developer.todoist.com/sync/v8/?shell
    //
    let sync_token: String = "*".to_string();
    let all_data: String = "true".to_string();
    let mut params = HashMap::new();
    params.insert("token", &auth_token);
    params.insert("sync_token", &sync_token);
    params.insert("resource_types", &resource_string);
    params.insert("all_data", &all_data);

    let client = reqwest::Client::new();

    // Issue the request.
    client.get(TODOIST_API).query(&params).send()
}

//
// Request response handler implementations.
//

fn process_error(error: &reqwest::Error) {
    println!("{}", error);
}

fn common_response_handler(response: &mut reqwest::Response) {
    // Only print these traces in debug mode.
    if cfg!(debug_assertions) {
        println!("Headers:\n{:?}", response.headers());
        println!("Body:\n{:?}", response.text());
    }
}

fn process_response_items(mut response: reqwest::Response) {
    common_response_handler(&mut response);

    let sync_state: types::SyncStruct = response
        .json()
        .expect("Failed to de-serialize JSON response");

    let mut items = sync_state.items.expect("Failed to parse items JSON");

    // Sort the items by their server order.
    let custom_sort = |a: &types::ItemStruct, b: &types::ItemStruct| {
        let item_order_sort = a.item_order.cmp(&b.item_order);
        let project_order_sort = a.project_id.cmp(&b.project_id);

        // item_order values are only unique per project, so if we want to
        // display items in the correct order we need to sort by project
        // groupings first, and then sort by item order.
        if project_order_sort == Ordering::Equal {
            item_order_sort
        } else {
            project_order_sort
        }
    };

    items.sort_by(custom_sort);

    for item in items {
        renderer::render_item(&item);
    }
}

fn process_response_projects(mut response: reqwest::Response) {
    common_response_handler(&mut response);

    let sync_state: types::SyncStruct = response
        .json()
        .expect("Failed to deserialize json response");

    // Sort the items by their server order.
    //
    let mut projects = sync_state.projects.expect("Failed to parse projects JSON");
    projects.sort_by_key(|p| p.item_order);

    for project in projects {
        renderer::render_project(&project);
    }
}

//
// Command handler implementations.
//

pub fn items_command() {
    let response = execute_request(&TodrResourceType::Items);

    match response {
        Ok(r) => process_response_items(r),
        Err(e) => process_error(&e),
    }
}

pub fn projects_command() {
    let response = execute_request(&TodrResourceType::Projects);

    match response {
        Ok(r) => process_response_projects(r),
        Err(e) => process_error(&e),
    }
}

pub fn help_command() {
    println!();
    println!("Commands:");
    println!();
    println!("  h | help  - This help message");
    println!();
    println!("  i | items - List all active todo items.");
    println!();
    println!("  p | projs - List all active projects.");
    println!();
    println!("  q | quit  - Exit the application.");
    println!();
}

pub fn unknown_command(command: &str) {
    println!("Unknown Command: {}", command);
}
<|endoftext|>


<commit_before>use primitive::*;
<<<<<<< HEAD
use timer::*;
=======
use world::*;
>>>>>>> 71f9fb5189a1fa54d282d10c7c856f50a504fd0c

use std::time::Duration;
use std::sync::*;

pub trait Actor {
    fn name(&self) -> &str;
    fn symbol(&self) -> &str;
    fn coord(&self) -> &Coord;
    fn set_coord(&mut self, coord : &Coord);
    fn update(&mut self, delta : Duration);
}

// PLAYER
pub struct Player {
   coord : Coord,
   move_timer : Timer,
   world : Arc<Mutex<World>>,
}

impl Player {
    fn new(coord : Coord, world : Arc<Mutex<World>>) -> Self {
        Self {
            coord: coord,
            world: world,
        }
    }
    pub fn handle_input(&mut self, keypress : &char, dirty_coord_tx : &mut mpsc::Sender<Coord>) {
        match *keypress {
            'd'|'e' => {
                dirty_coord_tx.send(self.coord.clone());
                //self._coord.col = clamp(self._coord.col + 1, 0, ;
            },
            _ => {},
        }
    }
}

impl Actor for Player {
    fn name(&self) -> &str { "Rusty Sword!" }
    fn symbol(&self) -> &str { "†" } // U-2020
    fn coord(&self) -> &Coord { &self.coord }
    fn set_coord(&mut self, coord : &Coord) {
        self.coord = *coord;
    }
    fn update(&mut self, delta : Duration) {
        self.move_timer.update(delta);
    }
}

// MONSTER
pub struct Monster {
   coord : Coord,
   world : Arc<Mutex<World>>,
}

impl Monster {
    fn new(coord : Coord, world : Arc<Mutex<World>>) -> Self {
        Self {
            coord: coord,
            world: world,
        }
    }
}

impl Actor for Monster {
    fn name(&self) -> &str { "Rusty Sword!" }
    fn symbol(&self) -> &str { "X" } // U-2020
    fn coord(&self) -> &Coord { &self.coord }
    fn set_coord(&mut self, coord : &Coord) {
        self.coord = *coord;
    }
    fn update(&mut self, delta : Duration) { /* XXX */ }
}

<commit_msg>More merging<commit_after>use primitive::*;
use timer::*;
use world::*;

use std::time::Duration;
use std::sync::*;

pub trait Actor {
    fn name(&self) -> &str;
    fn symbol(&self) -> &str;
    fn coord(&self) -> &Coord;
    fn set_coord(&mut self, coord : &Coord);
    fn update(&mut self, delta : Duration);
}

// PLAYER
pub struct Player {
   coord : Coord,
   move_timer : Timer,
   world : Arc<Mutex<World>>,
}

impl Player {
    fn new(coord : Coord, world : Arc<Mutex<World>>) -> Self {
        Self {
            coord: coord,
            world: world,
        }
    }
    pub fn handle_input(&mut self, keypress : &char, dirty_coord_tx : &mut mpsc::Sender<Coord>) {
        match *keypress {
            'd'|'e' => {
                dirty_coord_tx.send(self.coord.clone());
                //self._coord.col = clamp(self._coord.col + 1, 0, ;
            },
            _ => {},
        }
    }
}

impl Actor for Player {
    fn name(&self) -> &str { "Rusty Sword!" }
    fn symbol(&self) -> &str { "†" } // U-2020
    fn coord(&self) -> &Coord { &self.coord }
    fn set_coord(&mut self, coord : &Coord) {
        self.coord = *coord;
    }
    fn update(&mut self, delta : Duration) {
        self.move_timer.update(delta);
    }
}

// MONSTER
pub struct Monster {
   coord : Coord,
   world : Arc<Mutex<World>>,
}

impl Monster {
    fn new(coord : Coord, world : Arc<Mutex<World>>) -> Self {
        Self {
            coord: coord,
            world: world,
        }
    }
}

impl Actor for Monster {
    fn name(&self) -> &str { "Rusty Sword!" }
    fn symbol(&self) -> &str { "X" } // U-2020
    fn coord(&self) -> &Coord { &self.coord }
    fn set_coord(&mut self, coord : &Coord) {
        self.coord = *coord;
    }
    fn update(&mut self, delta : Duration) { /* XXX */ }
}

<|endoftext|>


<commit_before>use std::any::Any;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;
use std::result;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, TryRecvError, RecvError, SendError};
use std::thread;

use time::{Duration, SteadyTime};

pub type InitResult<E> = result::Result<Option<u64>, E>;
pub type ActorResult<T> = result::Result<T, ActorError>;
pub type StartResult<T, E> = result::Result<Actor<T>, E>;

pub struct Actor<T> where T: Any + Send {
    pub sender: Sender<Message<T>>,
    pub receiver: Receiver<Message<T>>,
    pub handle: thread::JoinHandle<ActorResult<()>>,
    pub name: Option<String>,
}

impl<T> Actor<T> where T: Any + Send {
    /// Create a new actor handler struct.
    pub fn new(sender: Sender<Message<T>>, receiver: Receiver<Message<T>>,
        handle: thread::JoinHandle<ActorResult<()>>, name: Option<String>) -> Self {
        Actor {
            sender: sender,
            receiver: receiver,
            handle: handle,
            name: name,
        }
    }

    pub fn cast(&self, message: T) -> ActorResult<()> {
        self::cast(&self.sender, message)
    }

    pub fn call(&self, message: T) -> ActorResult<T> {
        self::call(&self.sender, &self.receiver, message)
    }
}

pub fn cast<T: Any + Send>(tx: &Sender<Message<T>>, message: T) -> ActorResult<()> {
    match tx.send(Message::Cast(message)) {
        Ok(()) => Ok(()),
        Err(err) => Err(ActorError::from(err)),
    }
}

pub fn call<T: Any + Send>(tx: &Sender<Message<T>>, rx: &Receiver<Message<T>>, message: T) -> ActorResult<T> {
    match tx.send(Message::Call(message)) {
        Ok(()) => {
            match rx.recv() {
                Ok(Message::Reply(msg)) => Ok(msg),
                Ok(_) => panic!("must reply from a call!"),
                Err(err) => Err(ActorError::from(err)),
            }
        },
        Err(err) => Err(ActorError::from(err)),
    }
}

pub struct Builder<T: GenServer> {
    name: Option<String>,
    spec: T,
}

impl<A: GenServer> Builder<A> {
    pub fn new(spec: A) -> Self {
        Builder {
            name: None,
            spec: spec,
        }
    }

    pub fn name(mut self, name: String) -> Builder<A> {
        self.name = Some(name);
        self
    }

    /// Start an actor on a new thread and return an Actor.
    pub fn start(self, mut state: A::S) -> StartResult<A::T, A::E> {
        let (otx, orx) = mpsc::channel::<Message<A::T>>();
        let (itx, irx) = mpsc::channel::<Message<A::T>>();
        let initial_wait_ms = match self.spec.init(&itx, &mut state) {
            Ok(result) => result,
            Err(err) => return Err(err),
        };
        let itx2 = itx.clone(); // clone inner receive loop's sender for actor struct
        let name = self.name.clone();
        let thread_name = name.clone().unwrap_or("GenServer".to_string());
        let handle = thread::Builder::new().name(thread_name.clone()).spawn(move || {
            let mut timeout: Option<SteadyTime> = None;
            if let Some(ms) = initial_wait_ms {
                set_timeout(ms, &mut timeout);
            }
            loop {
                if let Some(go_time) = timeout {
                    if go_time >= SteadyTime::now() {
                        match self.spec.handle_timeout(&otx, &mut state) {
                            HandleResult::Stop(reason, None) => return shutdown(reason, None, &otx),
                            HandleResult::NoReply(Some(0)) => {
                                set_timeout(0, &mut timeout);
                                continue;
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_timeout: {:?}", hr),
                        }
                    }
                }
                match irx.try_recv() {
                    Ok(Message::Call(msg)) => {
                        match self.spec.handle_call(msg, &otx, &itx, &mut state) {
                            HandleResult::Reply(msg, new_timeout) => {
                                try!(otx.send(Message::Reply(msg)));
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                        }
                    },
                    Ok(Message::Cast(msg)) => {
                        match self.spec.handle_cast(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_cast: {:?}", hr),
                        }
                    },
                    Ok(Message::Info(msg)) => {
                        match self.spec.handle_info(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_info: {:?}", hr),
                        }
                    },
                    Ok(hr) => panic!("received unexpected message type: {:?}", hr),
                    Err(TryRecvError::Disconnected) => { break; },
                    Err(TryRecvError::Empty) => { },
                }
            }
            Ok(())
        }).unwrap();
        Ok(Actor::new(itx2, orx, handle, name))
    }
}

#[derive(Debug)]
pub enum ActorError {
    InitFailure(String),
    AbnormalShutdown(String),
    SendError,
    RecvError,
}

impl<T: Any + Send> From<mpsc::SendError<Message<T>>> for ActorError {
    fn from(_err: mpsc::SendError<Message<T>>) -> Self {
        ActorError::SendError
    }
}

impl From<mpsc::RecvError> for ActorError {
    fn from(_err: mpsc::RecvError) -> Self {
        ActorError::RecvError
    }
}

#[derive(Debug)]
pub enum StopReason {
    Normal,
    Fatal(String),
}

#[derive(Debug)]
pub enum HandleResult<T> where T: Any + Send {
    Reply(T, Option<u64>),
    NoReply(Option<u64>),
    Stop(StopReason, Option<T>),
}

pub enum Message<T> where T: Any + Send {
    Call(T),
    Cast(T),
    Info(T),
    Reply(T),
}

impl<T> Debug for Message<T> where T: Any + Send + Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Call(ref msg) => write!(f, "CALL: {:?}", msg),
            &Message::Cast(ref msg) => write!(f, "CAST: {:?}", msg),
            &Message::Info(ref msg) => write!(f, "INFO: {:?}", msg),
            &Message::Reply(ref msg) => write!(f, "REPLY: {:?}", msg)
        }
    }
}

pub trait GenServer : Send + 'static {
    type T: Send + Any + Debug;
    type S: Send + Any;
    type E: Error + 'static;

    fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E>;

    fn handle_call(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _caller: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_call callback not implemented");
    }
    fn handle_cast(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_cast callback not implemented");
    }
    fn handle_info(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
    fn handle_timeout(&self, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
}

fn set_timeout(wait_ms: u64, current_timeout: &mut Option<SteadyTime>) {
    *current_timeout = Some(SteadyTime::now() + Duration::milliseconds(wait_ms as i64));
}

fn shutdown<T: Any + Send>(reason: StopReason, reply: Option<T>, sender: &Sender<Message<T>>) -> Result<(), ActorError> {
    if let Some(msg) = reply {
        let _result = sender.send(Message::Reply(msg));
    }
    match reason {
        StopReason::Normal => Ok(()),
        StopReason::Fatal(e) => Err(ActorError::AbnormalShutdown(e)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt;
    use std::error::Error;
    use std::sync::mpsc::Sender;

    struct Worker;

    struct MyState {
        pub initialized: bool,
    }

    impl MyState {
        pub fn new() -> Self {
            MyState {
                initialized: false,
            }
        }
    }

    #[derive(Debug)]
    enum MyError {
        DirtyState,
    }

    #[derive(Debug)]
    enum MyMessage {
        Ok,
        Stop,
        State(bool),
        GetState,
        SetState(bool),
    }

    impl GenServer for Worker {
        type T = MyMessage;
        type S = MyState;
        type E = MyError;

        fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E> {
            if state.initialized {
                Err(MyError::DirtyState)
            } else {
                state.initialized = true;
                Ok(None)
            }
        }

        fn handle_call(&self, msg: Self::T, _: &Sender<Message<Self::T>>, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::Stop => HandleResult::Stop(StopReason::Normal, Some(MyMessage::Ok)),
                MyMessage::GetState => HandleResult::Reply(MyMessage::State(state.initialized), None),
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::Reply(MyMessage::Ok, None)
                }
                _ => HandleResult::Stop(StopReason::Fatal(String::from("Nope")), None),
            }
        }

        fn handle_cast(&self, msg: Self::T, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::NoReply(None)
                },
                _ => HandleResult::NoReply(None)
            }
        }
    }

    impl fmt::Display for MyError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                MyError::DirtyState => write!(f, "state already initialized"),
            }
        }
    }

    impl Error for MyError {
        fn description(&self) -> &str {
            match *self {
                MyError::DirtyState => "state already initialized"
            }
        }
    }

    #[test]
    fn error_on_init() {
        let mut state = MyState::new();
        state.initialized = true;
        match Builder::new(Worker).start(state) {
            Err(MyError::DirtyState) => assert!(true),
            Ok(_) => assert!(false),
        }
    }

    #[test]
    fn call_set_get_state() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(true)) => assert!(true),
            _ => assert!(false),
        }
        assert!(actor.call(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(false)) => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn multiple_cast_and_call_ordered() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        assert!(actor.cast(MyMessage::SetState(true)).is_ok());
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(result)) => assert_eq!(result, false),
            _ => assert!(false),
        }
    }

    #[test]
    fn stopping_an_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::Stop) {
            Ok(MyMessage::Ok) => assert!(true),
            _ => assert!(false),
        }
        match actor.handle.join() {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn explicitly_naming_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).name("batman".to_string()).start(state).unwrap();
        assert!(actor.name.is_some());
        assert_eq!(actor.name.unwrap(), "batman".to_string());
    }

    #[test]
    fn default_named_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.name.is_none());
    }
}
<commit_msg>remove handle_info callback and associated types<commit_after>use std::any::Any;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;
use std::result;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, TryRecvError, RecvError, SendError};
use std::thread;

use time::{Duration, SteadyTime};

pub type InitResult<E> = result::Result<Option<u64>, E>;
pub type ActorResult<T> = result::Result<T, ActorError>;
pub type StartResult<T, E> = result::Result<Actor<T>, E>;

pub struct Actor<T> where T: Any + Send {
    pub sender: Sender<Message<T>>,
    pub receiver: Receiver<Message<T>>,
    pub handle: thread::JoinHandle<ActorResult<()>>,
    pub name: Option<String>,
}

impl<T> Actor<T> where T: Any + Send {
    /// Create a new actor handler struct.
    pub fn new(sender: Sender<Message<T>>, receiver: Receiver<Message<T>>,
        handle: thread::JoinHandle<ActorResult<()>>, name: Option<String>) -> Self {
        Actor {
            sender: sender,
            receiver: receiver,
            handle: handle,
            name: name,
        }
    }

    pub fn cast(&self, message: T) -> ActorResult<()> {
        self::cast(&self.sender, message)
    }

    pub fn call(&self, message: T) -> ActorResult<T> {
        self::call(&self.sender, &self.receiver, message)
    }
}

pub fn cast<T: Any + Send>(tx: &Sender<Message<T>>, message: T) -> ActorResult<()> {
    match tx.send(Message::Cast(message)) {
        Ok(()) => Ok(()),
        Err(err) => Err(ActorError::from(err)),
    }
}

pub fn call<T: Any + Send>(tx: &Sender<Message<T>>, rx: &Receiver<Message<T>>, message: T) -> ActorResult<T> {
    match tx.send(Message::Call(message)) {
        Ok(()) => {
            match rx.recv() {
                Ok(Message::Reply(msg)) => Ok(msg),
                Ok(_) => panic!("must reply from a call!"),
                Err(err) => Err(ActorError::from(err)),
            }
        },
        Err(err) => Err(ActorError::from(err)),
    }
}

pub struct Builder<T: GenServer> {
    name: Option<String>,
    spec: T,
}

impl<A: GenServer> Builder<A> {
    pub fn new(spec: A) -> Self {
        Builder {
            name: None,
            spec: spec,
        }
    }

    pub fn name(mut self, name: String) -> Builder<A> {
        self.name = Some(name);
        self
    }

    /// Start an actor on a new thread and return an Actor.
    pub fn start(self, mut state: A::S) -> StartResult<A::T, A::E> {
        let (otx, orx) = mpsc::channel::<Message<A::T>>();
        let (itx, irx) = mpsc::channel::<Message<A::T>>();
        let initial_wait_ms = match self.spec.init(&itx, &mut state) {
            Ok(result) => result,
            Err(err) => return Err(err),
        };
        let itx2 = itx.clone(); // clone inner receive loop's sender for actor struct
        let name = self.name.clone();
        let thread_name = name.clone().unwrap_or("GenServer".to_string());
        let handle = thread::Builder::new().name(thread_name.clone()).spawn(move || {
            let mut timeout: Option<SteadyTime> = None;
            if let Some(ms) = initial_wait_ms {
                set_timeout(ms, &mut timeout);
            }
            loop {
                if let Some(go_time) = timeout {
                    if go_time >= SteadyTime::now() {
                        match self.spec.handle_timeout(&otx, &mut state) {
                            HandleResult::Stop(reason, None) => return shutdown(reason, None, &otx),
                            HandleResult::NoReply(Some(0)) => {
                                set_timeout(0, &mut timeout);
                                continue;
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_timeout: {:?}", hr),
                        }
                    }
                }
                match irx.try_recv() {
                    Ok(Message::Call(msg)) => {
                        match self.spec.handle_call(msg, &otx, &itx, &mut state) {
                            HandleResult::Reply(msg, new_timeout) => {
                                try!(otx.send(Message::Reply(msg)));
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                        }
                    },
                    Ok(Message::Cast(msg)) => {
                        match self.spec.handle_cast(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_cast: {:?}", hr),
                        }
                    },
                    Ok(hr) => panic!("received unexpected message type: {:?}", hr),
                    Err(TryRecvError::Disconnected) => { break; },
                    Err(TryRecvError::Empty) => { },
                }
            }
            Ok(())
        }).unwrap();
        Ok(Actor::new(itx2, orx, handle, name))
    }
}

#[derive(Debug)]
pub enum ActorError {
    InitFailure(String),
    AbnormalShutdown(String),
    SendError,
    RecvError,
}

impl<T: Any + Send> From<mpsc::SendError<Message<T>>> for ActorError {
    fn from(_err: mpsc::SendError<Message<T>>) -> Self {
        ActorError::SendError
    }
}

impl From<mpsc::RecvError> for ActorError {
    fn from(_err: mpsc::RecvError) -> Self {
        ActorError::RecvError
    }
}

#[derive(Debug)]
pub enum StopReason {
    Normal,
    Fatal(String),
}

#[derive(Debug)]
pub enum HandleResult<T> where T: Any + Send {
    Reply(T, Option<u64>),
    NoReply(Option<u64>),
    Stop(StopReason, Option<T>),
}

pub enum Message<T> where T: Any + Send {
    Call(T),
    Cast(T),
    Reply(T),
}

impl<T> Debug for Message<T> where T: Any + Send + Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Call(ref msg) => write!(f, "CALL: {:?}", msg),
            &Message::Cast(ref msg) => write!(f, "CAST: {:?}", msg),
            &Message::Reply(ref msg) => write!(f, "REPLY: {:?}", msg)
        }
    }
}

pub trait GenServer : Send + 'static {
    type T: Send + Any + Debug;
    type S: Send + Any;
    type E: Error + 'static;

    fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E>;

    fn handle_call(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _caller: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_call callback not implemented");
    }
    fn handle_cast(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_cast callback not implemented");
    }
    fn handle_timeout(&self, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
}

fn set_timeout(wait_ms: u64, current_timeout: &mut Option<SteadyTime>) {
    *current_timeout = Some(SteadyTime::now() + Duration::milliseconds(wait_ms as i64));
}

fn shutdown<T: Any + Send>(reason: StopReason, reply: Option<T>, sender: &Sender<Message<T>>) -> Result<(), ActorError> {
    if let Some(msg) = reply {
        let _result = sender.send(Message::Reply(msg));
    }
    match reason {
        StopReason::Normal => Ok(()),
        StopReason::Fatal(e) => Err(ActorError::AbnormalShutdown(e)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt;
    use std::error::Error;
    use std::sync::mpsc::Sender;

    struct Worker;

    struct MyState {
        pub initialized: bool,
    }

    impl MyState {
        pub fn new() -> Self {
            MyState {
                initialized: false,
            }
        }
    }

    #[derive(Debug)]
    enum MyError {
        DirtyState,
    }

    #[derive(Debug)]
    enum MyMessage {
        Ok,
        Stop,
        State(bool),
        GetState,
        SetState(bool),
    }

    impl GenServer for Worker {
        type T = MyMessage;
        type S = MyState;
        type E = MyError;

        fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E> {
            if state.initialized {
                Err(MyError::DirtyState)
            } else {
                state.initialized = true;
                Ok(None)
            }
        }

        fn handle_call(&self, msg: Self::T, _: &Sender<Message<Self::T>>, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::Stop => HandleResult::Stop(StopReason::Normal, Some(MyMessage::Ok)),
                MyMessage::GetState => HandleResult::Reply(MyMessage::State(state.initialized), None),
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::Reply(MyMessage::Ok, None)
                }
                _ => HandleResult::Stop(StopReason::Fatal(String::from("Nope")), None),
            }
        }

        fn handle_cast(&self, msg: Self::T, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::NoReply(None)
                },
                _ => HandleResult::NoReply(None)
            }
        }
    }

    impl fmt::Display for MyError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                MyError::DirtyState => write!(f, "state already initialized"),
            }
        }
    }

    impl Error for MyError {
        fn description(&self) -> &str {
            match *self {
                MyError::DirtyState => "state already initialized"
            }
        }
    }

    #[test]
    fn error_on_init() {
        let mut state = MyState::new();
        state.initialized = true;
        match Builder::new(Worker).start(state) {
            Err(MyError::DirtyState) => assert!(true),
            Ok(_) => assert!(false),
        }
    }

    #[test]
    fn call_set_get_state() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(true)) => assert!(true),
            _ => assert!(false),
        }
        assert!(actor.call(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(false)) => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn multiple_cast_and_call_ordered() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        assert!(actor.cast(MyMessage::SetState(true)).is_ok());
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(result)) => assert_eq!(result, false),
            _ => assert!(false),
        }
    }

    #[test]
    fn stopping_an_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::Stop) {
            Ok(MyMessage::Ok) => assert!(true),
            _ => assert!(false),
        }
        match actor.handle.join() {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn explicitly_naming_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).name("batman".to_string()).start(state).unwrap();
        assert!(actor.name.is_some());
        assert_eq!(actor.name.unwrap(), "batman".to_string());
    }

    #[test]
    fn default_named_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.name.is_none());
    }
}
<|endoftext|>


<commit_before>extern crate intercom;
extern crate intercom_common;
mod os;
mod host;

use std::io::Write;

#[derive(Debug)]
pub enum BuildError {
    ParseError( String ),
    IoError( String, std::io::Error ),
    CommandError( String, String, String ),
}

impl BuildError {
    fn print_as_warning( &self, w : &mut Write ) -> Result<(), std::io::Error> {

        let msg : std::borrow::Cow<str> = match *self {
            BuildError::ParseError( ref m, .. ) => m.into(),
            BuildError::IoError( ref m, ref e ) => format!( "{}: {}", m, e ).into(),
            BuildError::CommandError( ref m, .. ) => m.into(),
        };

        writeln!( w, "cargo:warning={}", msg )?;

        // Handle all the errors that provide extra info.
        // (Only one currently, but we'll still want to structure this as a match)
        #[allow(clippy::single_match)]
        match *self {
            BuildError::CommandError( _, ref stdout, ref stderr ) => {
                if ! stdout.is_empty() {
                    writeln!( w, "cargo:warning=" )?;
                    writeln!( w, "cargo:warning=Program stdout:" )?;
                    writeln!( w, "cargo:warning=---------------" )?;
                    for line in stdout.split( '\n' ) {
                        writeln!( w, "cargo:warning={}", line )?;
                    }
                }

                if ! stderr.is_empty() {
                    writeln!( w, "cargo:warning=" )?;
                    writeln!( w, "cargo:warning=Program stderr:" )?;
                    writeln!( w, "cargo:warning=---------------" )?;
                    for line in stderr.split( '\n' ) {
                        writeln!( w, "cargo:warning={}", line )?;
                    }
                }

                // If the program didn't provide stdout or stderr, we'll want to
                // inform the user of that so they aren't left confused on why
                // our error messages are crap.
                if stdout.is_empty() && stderr.is_empty() {
                    writeln!( w, "cargo:warning=(Command produced no output)" )?;
                }
            },
            _ => {}  // No extra lines.
        }

        Ok(())
    }
}

pub fn build( all_type_systems : bool ) {
    match os::build( all_type_systems ) {
        Ok(..) => {}
        Err( e ) => {
            e.print_as_warning( &mut std::io::stdout() )
                    .expect( "Cannot write to stdout" );
            println!( "cargo:warning=Some Intercom functionality might not be available" );
        }
    }
}
<commit_msg>Add unit tests for build error report<commit_after>extern crate intercom;
extern crate intercom_common;
mod os;
mod host;

use std::io::Write;

#[derive(Debug)]
pub enum BuildError {
    ParseError( String ),
    IoError( String, std::io::Error ),
    CommandError( String, String, String ),
}

impl BuildError {
    fn print_as_warning( &self, w : &mut Write ) -> Result<(), std::io::Error> {

        let msg : std::borrow::Cow<str> = match *self {
            BuildError::ParseError( ref m, .. ) => m.into(),
            BuildError::IoError( ref m, ref e ) => format!( "{}: {}", m, e ).into(),
            BuildError::CommandError( ref m, .. ) => m.into(),
        };

        writeln!( w, "cargo:warning={}", msg )?;

        // Handle all the errors that provide extra info.
        // (Only one currently, but we'll still want to structure this as a match)
        #[allow(clippy::single_match)]
        match *self {
            BuildError::CommandError( _, ref stdout, ref stderr ) => {
                if ! stdout.is_empty() {
                    writeln!( w, "cargo:warning=" )?;
                    writeln!( w, "cargo:warning=Program stdout:" )?;
                    writeln!( w, "cargo:warning=---------------" )?;
                    for line in stdout.split( '\n' ) {
                        writeln!( w, "cargo:warning={}", line )?;
                    }
                }

                if ! stderr.is_empty() {
                    writeln!( w, "cargo:warning=" )?;
                    writeln!( w, "cargo:warning=Program stderr:" )?;
                    writeln!( w, "cargo:warning=---------------" )?;
                    for line in stderr.split( '\n' ) {
                        writeln!( w, "cargo:warning={}", line )?;
                    }
                }

                // If the program didn't provide stdout or stderr, we'll want to
                // inform the user of that so they aren't left confused on why
                // our error messages are crap.
                if stdout.is_empty() && stderr.is_empty() {
                    writeln!( w, "cargo:warning=(Command produced no output)" )?;
                }
            },
            _ => {}  // No extra lines.
        }

        Ok(())
    }
}

pub fn build( all_type_systems : bool ) {
    match os::build( all_type_systems ) {
        Ok(..) => {}
        Err( e ) => {
            e.print_as_warning( &mut std::io::stdout() )
                    .expect( "Cannot write to stdout" );
            println!( "cargo:warning=Some Intercom functionality might not be available" );
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_basic_error() {
        let e = BuildError::ParseError( "Error message".to_string() );
        let mut v = vec![];
        e.print_as_warning( &mut v ).expect( "Failed to write string" );

        let s = String::from_utf8_lossy( &v );
        assert_eq!( s, "cargo:warning=Error message\n" );
    }

    #[test]
    fn test_command_error() {
        let e = BuildError::CommandError(
            "Error message".to_string(),
            "stdout".to_string(),
            "stderr".to_string(),
        );
        let mut v = vec![];
        e.print_as_warning( &mut v ).expect( "Failed to write string" );

        let s = String::from_utf8_lossy( &v );
        assert_eq!( s, "\
            cargo:warning=Error message\n\
            cargo:warning=\n\
            cargo:warning=Program stdout:\n\
            cargo:warning=---------------\n\
            cargo:warning=stdout\n\
            cargo:warning=\n\
            cargo:warning=Program stderr:\n\
            cargo:warning=---------------\n\
            cargo:warning=stderr\n" );
    }

    #[test]
    fn test_command_error_no_output() {
        let e = BuildError::CommandError(
            "Error message".to_string(),
            String::new(),
            String::new() );
        let mut v = vec![];
        e.print_as_warning( &mut v ).expect( "Failed to write string" );

        let s = String::from_utf8_lossy( &v );
        assert_eq!( s, "\
            cargo:warning=Error message\n\
            cargo:warning=(Command produced no output)\n" );
    }
}
<|endoftext|>


<commit_before>use num::cast::*;
use vec::Vec3;

pub enum Angle<T> {
    degrees(T),
    radians(T),
}

pub impl<T:Copy Num NumCast> Angle<T> {
    pure fn degrees() -> T {
        match self {
            degrees(theta) => theta,
            radians(theta) => theta * cast(180f64 / f64::consts::pi)
        }
    }

    pure fn radians() -> T {
        match self {
            degrees(theta) => theta * cast(f64::consts::pi / 180f64),
            radians(theta) => theta
        }
    }
}

pub struct AxisRotation<T> {
    axis: Vec3<T>,
    theta: Angle<T>,
}

pub struct Euler<T> {
    x: T,   // pitch
    y: T,   // yaw
    z: T,   // roll
}<commit_msg>Implement operator overloads for Angle type<commit_after>use num::cast::*;
use vec::Vec3;

pub enum Angle<T> {
    degrees(T),
    radians(T),
}

pub impl<T:Copy Num NumCast> Angle<T> {
    pure fn degrees() -> T {
        match self {
            degrees(theta) => theta,
            radians(theta) => theta * cast(180f64 / f64::consts::pi)
        }
    }

    pure fn radians() -> T {
        match self {
            degrees(theta) => theta * cast(f64::consts::pi / 180f64),
            radians(theta) => theta
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Add<T,Angle<T>> {
    #[inline(always)]
    pure fn add(rhs: &T) -> Angle<T> {
        match self {
            degrees(theta) => degrees(theta + *rhs),
            radians(theta) => radians(theta + *rhs)
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Sub<T,Angle<T>> {
    #[inline(always)]
    pure fn sub(rhs: &T) -> Angle<T> {
        match self {
            degrees(theta) => degrees(theta - *rhs),
            radians(theta) => radians(theta - *rhs)
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Mul<T,Angle<T>> {
    #[inline(always)]
    pure fn mul(rhs: &T) -> Angle<T> {
        match self {
            degrees(theta) => degrees(theta * *rhs),
            radians(theta) => radians(theta * *rhs)
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Div<T,Angle<T>> {
    #[inline(always)]
    pure fn div(rhs: &T) -> Angle<T> {
        match self {
            degrees(theta) => degrees(theta / *rhs),
            radians(theta) => radians(theta / *rhs)
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Modulo<T,Angle<T>> {
    #[inline(always)]
    pure fn modulo(rhs: &T) -> Angle<T> {
        match self {
            degrees(theta) => degrees(theta % *rhs),
            radians(theta) => radians(theta % *rhs)
        }
    }
}

pub impl<T:Copy Num> Angle<T>: Neg<Angle<T>> {
    #[inline(always)]
    pure fn neg() -> Angle<T> {
        match self {
            degrees(theta) => degrees(-theta),
            radians(theta) => radians(-theta)
        }
    }
}

pub struct AxisRotation<T> {
    axis: Vec3<T>,
    theta: Angle<T>,
}

pub struct Euler<T> {
    x: T,   // pitch
    y: T,   // yaw
    z: T,   // roll
}<|endoftext|>


<commit_before>use std::io;
use std::ascii::AsciiExt;

use utils::trim_newline;

/// A FASTQ record, returned by the FASTQ parser.
pub struct Record {
    pub name: String,
    pub seq: Vec<u8>,
    pub qual: Vec<u8>
}

/// An iterable FASTQ parser.
pub struct FastqFile<T> {
    buffer: T
}

/// Create a new FASTQ parser object.
///
/// # Arguments
///
/// * `buffer` - a buffer object (e.g. the io::BufferedReader over a file or STDIN)
///
/// # Example
///
/// ```rust
/// use bio::io::fastq::FastqFile;
/// use std::io::{BufferedReader, stdin};
///
/// let mut buffer = BufferedReader::new(stdin());
/// let fastq = FastqFile::new(buffer);
/// ```
impl<T> FastqFile<T> where T: io::Buffer {
    pub fn new(buffer: T) -> Self {
        FastqFile { buffer: buffer }
    }
}

/// Iterator over the FASTQ file.
impl<T> Iterator for FastqFile<T> where T: io::Buffer {
    type Item = Record;

    fn next(&mut self) -> Option<Record> {
        let mut name;
        match self.buffer.read_line() {
            Ok(line) => {
                name = line;
            },
            Err(io::IoError { kind: io::IoErrorKind::EndOfFile, .. } ) => return None,
            Err(e) => panic!(e.desc)
        }

        if !name.starts_with("@") {
            panic!("Expecting record to start with '>'.")
        }
        name.remove(0);

        let mut seq = self.buffer.read_line().ok().expect("Incomplete record");

        let sep = self.buffer.read_line().ok().expect("Incomplete record");
        if !sep.starts_with("+") {
            panic!("Expecting '+' separator between sequence and quals.")
        }

        let mut qual = self.buffer.read_line().ok().expect("Incomplete record");
        trim_newline(&mut name);
        trim_newline(&mut seq);
        trim_newline(&mut qual);

        Some(Record { name: name, seq: seq.to_ascii_uppercase().into_bytes(), qual: qual.into_bytes() })
    }
}
<commit_msg>Improved select implementation.<commit_after>use std::io;
use std::ascii::AsciiExt;

use utils::trim_newline;

/// A FASTQ record, returned by the FASTQ parser.
pub struct Record {
    pub name: String,
    pub seq: Vec<u8>,
    pub qual: Vec<u8>
}

/// An iterable FASTQ parser.
///
/// # Example
///
/// ```rust
/// use bio::io::fastq::FastqFile;
/// use std::io::{BufferedReader, stdin};
///
/// let mut buffer = BufferedReader::new(stdin());
/// let fastq = FastqFile::new(buffer);
/// ```
pub struct FastqFile<T> {
    buffer: T
}

impl<T> FastqFile<T> where T: io::Buffer {
    /// Create a new FASTQ parser object.
    ///
    /// # Arguments
    ///
    /// * `buffer` - a buffer object (e.g. the io::BufferedReader over a file or STDIN)
    pub fn new(buffer: T) -> Self {
        FastqFile { buffer: buffer }
    }
}

/// Iterator over the FASTQ file.
impl<T> Iterator for FastqFile<T> where T: io::Buffer {
    type Item = Record;

    fn next(&mut self) -> Option<Record> {
        let mut name;
        match self.buffer.read_line() {
            Ok(line) => {
                name = line;
            },
            Err(io::IoError { kind: io::IoErrorKind::EndOfFile, .. } ) => return None,
            Err(e) => panic!(e.desc)
        }

        if !name.starts_with("@") {
            panic!("Expecting record to start with '>'.")
        }
        name.remove(0);

        let mut seq = self.buffer.read_line().ok().expect("Incomplete record");

        let sep = self.buffer.read_line().ok().expect("Incomplete record");
        if !sep.starts_with("+") {
            panic!("Expecting '+' separator between sequence and quals.")
        }

        let mut qual = self.buffer.read_line().ok().expect("Incomplete record");
        trim_newline(&mut name);
        trim_newline(&mut seq);
        trim_newline(&mut qual);

        Some(Record { name: name, seq: seq.to_ascii_uppercase().into_bytes(), qual: qual.into_bytes() })
    }
}
<|endoftext|>


<commit_before>#[crate_type = "bin"];

extern mod syntax;

pub mod types;
pub mod clangll;
pub mod clang;
pub mod gen;
pub mod main;
<commit_msg>fix errors of glob import statements<commit_after>#[crate_type = "bin"];
#[feature(globs)];

extern mod syntax;

pub mod types;
pub mod clangll;
pub mod clang;
pub mod gen;
pub mod main;
<|endoftext|>