<commit_before>/*
 * Description: A client for the emdocs protocol.
 *
 * Copyright (C) 2022 Danny McClanahan <dmcC2@hypnicjerk.ai>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

//! A client for the emdocs protocol.

#![deny(rustdoc::missing_crate_level_docs)]
/* Make all doctests fail if they produce any warnings. */
#![doc(test(attr(deny(warnings))))]
#![deny(clippy::all)]

use emdocs_protocol::{
  messages::{self, OperationService},
  p2p::{self, P2p},
};

use clap::{Parser, Subcommand};
use serde_json;

use std::{
  io::{self, BufRead, Write},
  thread, time,
};

#[derive(Debug, Parser)]
#[clap(author, version, about, long_about = None)]
struct Opts {
  #[clap(subcommand)]
  action: Action,

  /// Port to receive p2p connections at.
  /* TODO: what should this default port be? */
  #[clap(short, long, default_value_t = 37263)]
  port: usize,
}

#[derive(Debug, Subcommand)]
enum Action {
  /// Listen for HTTP connections at the remote port and propagate p2p messages.
  Serve,
  /// Communicate via lines of JSON over stdio.
  Interact,
}

/* echo '{"link": {"buffer_id": {"uuid": "bfbb5e5f7e474018a42b0664e6fdb6c9"}, "remote": {"ip_address": "https://0.0.0.0:3600"}}}\n{"op": {"source": {"uuid":"bfbb5e5f7e474018a42b0664e6fdb6c9"}, "transform": {"type": {"edit": {"point": {"code_point_index": 0}, "payload": {"insert": {"contents": "aaa"}}}}}}}' | cargo run -- interact | jq | sponge */
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
  let Opts { action, port } = Opts::parse();

  match action {
    Action::Serve => {
      let addr = format!("[::1]:{}", port).parse()?;
      tonic::transport::Server::builder()
        .add_service(p2p::proto::p2p_server::P2pServer::new(
          p2p::P2pService::new(),
        ))
        .serve(addr)
        .await?;
    },
    Action::Interact => {
      let p2p_client = p2p::P2pClient::connect(format!("http://[::1]:{}", port)).await?;

      struct OS;
      #[tonic::async_trait]
      impl messages::OperationService for OS {
        async fn process_operation(
          &self,
          request: messages::Operation,
        ) -> Result<messages::OperationResult, messages::ProtocolError> {
          dbg!(&request);
          let client_msg = messages::ClientMessage::op(request);
          let mut client_msg: Vec<u8> = serde_json::to_vec(&client_msg)?;
          /* Ensure we have clear lines between entries in stdout. */
          client_msg.push(b'\n');
          io::stdout().write(&client_msg)?;
          Ok(messages::OperationResult::ok)
        }
      }

      /* Write every operation *received from p2p* to stdout as a JSON encoded ClientMessage. */
      let p2p2 = p2p_client.clone();
      /* Process p2p events in a background thread. */
      tokio::spawn(async move {
        while let Ok(p2p::P2pReceiveResult { messages }) = p2p2.receive(p2p2.receive_params()).await
        {
          for p2p::P2pMessage {
            op,
            msg_id,
            user_id,
          } in messages.into_iter()
          {
            dbg!(msg_id);
            dbg!(user_id);
            assert_eq!(
              messages::OperationResult::ok,
              OS.process_operation(op)
                .await
                .expect("processing op failed")
            );
          }
        }
      });

      /* Hook up stdin to an instance of an IDEService by JSON decoding lines. */
      for line in io::stdin().lock().lines() {
        let ide_msg: messages::IDEMessage = serde_json::from_str(&line?)?;
        let client_msg = match ide_msg {
          messages::IDEMessage::op(op) => {
            dbg!(&op);
            /* Propagate the message to the rest of the swarm. */
            assert_eq!(
              p2p::P2pSendResult {},
              p2p_client
                .propagate(p2p::P2pMessage {
                  msg_id: p2p::P2pMessageId::default(),
                  user_id: p2p_client.receive_params().user_id,
                  op: op.clone(),
                })
                .await?,
            );
            messages::ClientMessage::ok
          },
          messages::IDEMessage::link(link) => {
            eprintln!("do nothing with link {:?}", link);
            messages::ClientMessage::ok
          },
        };
        assert_eq!(messages::ClientMessage::ok, client_msg);
      }

      thread::sleep(time::Duration::from_millis(2000));
    },
  }

  Ok(())
}
<commit_msg>add --sleep-after-stdin option to interact for debugging<commit_after>/*
 * Description: A client for the emdocs protocol.
 *
 * Copyright (C) 2022 Danny McClanahan <dmcC2@hypnicjerk.ai>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

//! A client for the emdocs protocol.

#![deny(rustdoc::missing_crate_level_docs)]
/* Make all doctests fail if they produce any warnings. */
#![doc(test(attr(deny(warnings))))]
#![deny(clippy::all)]

use emdocs_protocol::{
  messages::{self, OperationService},
  p2p::{self, P2p},
};

use clap::{Parser, Subcommand};
use serde_json;

use std::{
  io::{self, BufRead, Write},
  thread, time,
};

#[derive(Debug, Parser)]
#[clap(author, version, about, long_about = None)]
struct Opts {
  #[clap(subcommand)]
  action: Action,

  /// Port to receive p2p connections at.
  /* TODO: what should this default port be? */
  #[clap(short, long, default_value_t = 37263)]
  port: usize,
}

#[derive(Debug, Subcommand)]
enum Action {
  /// Listen for HTTP connections at the remote port and propagate p2p messages.
  Serve,
  /// Communicate via lines of JSON over stdio.
  Interact {
    /// Sleep for the specified number of milliseconds after stdin is closed. This is useful
    /// for debugging.
    #[clap(short, long)]
    sleep_after_stdin: Option<u64>,
  },
}

/* echo '{"link": {"buffer_id": {"uuid": "bfbb5e5f7e474018a42b0664e6fdb6c9"}, "remote": {"ip_address": "https://0.0.0.0:3600"}}}\n{"op": {"source": {"uuid":"bfbb5e5f7e474018a42b0664e6fdb6c9"}, "transform": {"type": {"edit": {"point": {"code_point_index": 0}, "payload": {"insert": {"contents": "aaa"}}}}}}}' | cargo run -- interact | jq | sponge */
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
  let Opts { action, port } = Opts::parse();

  match action {
    Action::Serve => {
      let addr = format!("[::1]:{}", port).parse()?;
      tonic::transport::Server::builder()
        .add_service(p2p::proto::p2p_server::P2pServer::new(
          p2p::P2pService::new(),
        ))
        .serve(addr)
        .await?;
    },
    Action::Interact { sleep_after_stdin } => {
      let p2p_client = p2p::P2pClient::connect(format!("http://[::1]:{}", port)).await?;

      struct OS;
      #[tonic::async_trait]
      impl messages::OperationService for OS {
        async fn process_operation(
          &self,
          request: messages::Operation,
        ) -> Result<messages::OperationResult, messages::ProtocolError> {
          dbg!(&request);
          let client_msg = messages::ClientMessage::op(request);
          let mut client_msg: Vec<u8> = serde_json::to_vec(&client_msg)?;
          /* Ensure we have clear lines between entries in stdout. */
          client_msg.push(b'\n');
          io::stdout().write(&client_msg)?;
          Ok(messages::OperationResult::ok)
        }
      }

      /* Write every operation *received from p2p* to stdout as a JSON encoded ClientMessage. */
      let p2p2 = p2p_client.clone();
      /* Process p2p events in a background thread. */
      tokio::spawn(async move {
        while let Ok(p2p::P2pReceiveResult { messages }) = p2p2.receive(p2p2.receive_params()).await
        {
          for p2p::P2pMessage {
            op,
            msg_id,
            user_id,
          } in messages.into_iter()
          {
            dbg!(msg_id);
            dbg!(user_id);
            assert_eq!(
              messages::OperationResult::ok,
              OS.process_operation(op)
                .await
                .expect("processing op failed")
            );
          }
        }
      });

      /* Hook up stdin to an instance of an IDEService by JSON decoding lines. */
      for line in io::stdin().lock().lines() {
        let ide_msg: messages::IDEMessage = serde_json::from_str(&line?)?;
        let client_msg = match ide_msg {
          messages::IDEMessage::op(op) => {
            dbg!(&op);
            /* Propagate the message to the rest of the swarm. */
            assert_eq!(
              p2p::P2pSendResult {},
              p2p_client
                .propagate(p2p::P2pMessage {
                  msg_id: p2p::P2pMessageId::default(),
                  user_id: p2p_client.receive_params().user_id,
                  op: op.clone(),
                })
                .await?,
            );
            messages::ClientMessage::ok
          },
          messages::IDEMessage::link(link) => {
            eprintln!("do nothing with link {:?}", link);
            messages::ClientMessage::ok
          },
        };
        assert_eq!(messages::ClientMessage::ok, client_msg);
      }

      if let Some(millis) = sleep_after_stdin {
        thread::sleep(time::Duration::from_millis(millis));
      }
    },
  }

  Ok(())
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unknown_lints)]
// #![allow(unused_features)]
// #![feature(test)]
#[macro_use] extern crate clap;
extern crate cgmath;
// use cgmath::prelude::*;

extern crate gl;

extern crate glutin;

extern crate gltf;
extern crate gltf_importer;
extern crate gltf_utils;

extern crate image;
extern crate num_traits;

#[macro_use]
extern crate bitflags;

use clap::{Arg, App, AppSettings};

#[macro_use]extern crate log;
extern crate simplelog;
use simplelog::{TermLogger, LevelFilter, Config as LogConfig};

mod utils;
mod viewer;
use viewer::{GltfViewer, CameraOptions};

mod shader;
mod controls;
mod framebuffer;
mod macros;
// TODO!: adapt Source...
// mod http_source;
// use http_source::HttpSource;
mod render;
use render::math::*;

pub fn main() {
    let args = App::new("gltf-viewer")
        .version(option_env!("VERSION").unwrap_or(crate_version!()))
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DeriveDisplayOrder)
        .arg(Arg::with_name("FILE") // TODO!: re-add URL when fixed...
            .required(true)
            .takes_value(true)
            .help("glTF file name"))
        .arg(Arg::with_name("screenshot")
            .long("screenshot")
            .short("s")
            .value_name("FILE")
            .help("Create screenshot (PNG)"))
        .arg(Arg::with_name("verbose")
            .long("verbose")
            .short("v")
            .multiple(true)
            .help("Enable verbose logging (log level INFO). Can be repeated multiple times to increase log level to DEBUG/TRACE)"))
        .arg(Arg::with_name("WIDTH")
            .long("width")
            .short("w")
            .default_value("800")
            .help("Width in pixels")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("HEIGHT")
            .long("height")
            .short("h")
            .default_value("600")
            .help("Height in pixels")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("COUNT")
            .long("count")
            .short("c")
            .default_value("1")
            .help("Saves N screenshots of size WxH, rotating evenly spaced around the object")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("headless")
            .long("headless")
            .help("Use real headless rendering for screenshots (Default is a hidden window) [EXPERIMENTAL]"))
        .arg(Arg::with_name("CAM-INDEX")
            .long("cam-index")
            .takes_value(true)
            .help("Use the glTF camera with the given index (starting at 0). \n\
                Default: Determine 'nice' camera position based on the scene's bounding box.
                All other camera options are ignored if this one is given.")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("CAM-POS")
            .long("cam-pos")
            .takes_value(true)
            .help("Camera (aka eye) position override as comma-separated Vector3. Example: 1.2,3.4,5.6"))
        .arg(Arg::with_name("CAM-TARGET")
            .long("cam-target")
            .takes_value(true)
            .help("Camera target (aka center) override as comma-separated Vector3. Example: 1.2,3.4,5.6"))
        .arg(Arg::with_name("CAM-FOVY")
            .long("cam-fovy")
            .takes_value(true)
            .default_value("60")
            .help("Vertical field of view ('zoom') in degrees.")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .get_matches();
    let source = args.value_of("FILE").unwrap();

    let width: u32 = args.value_of("WIDTH").unwrap().parse().unwrap();
    let height: u32 = args.value_of("HEIGHT").unwrap().parse().unwrap();
    let count: u32 = args.value_of("COUNT").unwrap().parse().unwrap();

    let camera_options = CameraOptions {
        index: args.value_of("CAM-INDEX").map(|n| n.parse().unwrap()),
        position: args.value_of("CAM-POS").map(|v| parse_vec3(v).unwrap()),
        target: args.value_of("CAM-TARGET").map(|v| parse_vec3(v).unwrap()),
        fovy: args.value_of("CAM-FOVY").map(|n| n.parse().unwrap()).unwrap(),
    };

    let log_level = match args.occurrences_of("verbose") {
        0 => LevelFilter::Warn,
        1 => LevelFilter::Info,
        2 => LevelFilter::Debug,
        _ => LevelFilter::Trace
    };

    let _ = TermLogger::init(log_level, LogConfig { time: None, target: None, ..LogConfig::default() });

    let mut viewer = GltfViewer::new(source, width, height,
        args.is_present("headless"),
        !args.is_present("screenshot"),
        camera_options);

    if args.is_present("screenshot") {
        let filename = args.value_of("screenshot").unwrap();

        if !filename.to_lowercase().ends_with(".png") {
            warn!("filename should end with .png");
        }
        if count > 1 {
            viewer.multiscreenshot(filename, width, height, count)
        } else {
            viewer.screenshot(filename, width, height)
        }
        return;
    }

    viewer.start_render_loop();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn print_struct_sizes() {
        // run with `cargo test -- --nocapture`
        println!("Sizes in bytes:");
        println!("Scene:     {:>3}", std::mem::size_of::<render::Scene>());
        println!("Node:      {:>3}", std::mem::size_of::<render::Node>());
        println!("Mesh:      {:>3}", std::mem::size_of::<render::Mesh>());
        println!("Primitive: {:>3}", std::mem::size_of::<render::Primitive>());
        println!("Vertex:    {:>3}", std::mem::size_of::<render::Vertex>());
        println!();
        println!("Option<String>: {:>3}", std::mem::size_of::<Option<String>>());
        println!("String:         {:>3}", std::mem::size_of::<String>());
        println!("Vec<f32>:       {:>3}", std::mem::size_of::<Vec<f32>>());
        println!("Vec<Node>:      {:>3}", std::mem::size_of::<Vec<render::Node>>());
    }

//     extern crate test;
//     use self::test::Bencher;
//     #[bench]
//     fn bench_frame_timer(b: &mut Bencher) {
//         let mut timer = FrameTimer::new("Foobar", 60);
//         b.iter(|| {
//             for _ in 0..60 {
//                 timer.start();
//                 timer.end();
//             }
//         })
//     }
}
<commit_msg>improve arg parsing/help string<commit_after>#![allow(dead_code)]
#![allow(unknown_lints)]
// #![allow(unused_features)]
// #![feature(test)]
#[macro_use] extern crate clap;
extern crate cgmath;
// use cgmath::prelude::*;

extern crate gl;

extern crate glutin;

extern crate gltf;
extern crate gltf_importer;
extern crate gltf_utils;

extern crate image;
extern crate num_traits;

#[macro_use]
extern crate bitflags;

use clap::{Arg, App, AppSettings};

#[macro_use]extern crate log;
extern crate simplelog;
use simplelog::{TermLogger, LevelFilter, Config as LogConfig};

mod utils;
mod viewer;
use viewer::{GltfViewer, CameraOptions};

mod shader;
mod controls;
mod framebuffer;
mod macros;
// TODO!: adapt Source...
// mod http_source;
// use http_source::HttpSource;
mod render;
use render::math::*;

pub fn main() {
    let args = App::new("gltf-viewer")
        .version(option_env!("VERSION").unwrap_or(crate_version!()))
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DeriveDisplayOrder)
        .before_help("glTF 2.0 viewer\n\nNavigate with the mouse (left/right click + drag, mouse wheel) \
                    or WASD/cursor keys.")
        .arg(Arg::with_name("FILE") // TODO!: re-add URL when fixed...
            .required(true)
            .takes_value(true)
            .help("glTF file name"))
        .arg(Arg::with_name("screenshot")
            .long("screenshot")
            .short("s")
            .value_name("FILE")
            .help("Create screenshot (PNG)"))
        .arg(Arg::with_name("verbose")
            .long("verbose")
            .short("v")
            .multiple(true)
            .help("Enable verbose logging (log level INFO). Can be repeated multiple times to increase log level to DEBUG/TRACE)"))
        .arg(Arg::with_name("WIDTH")
            .long("width")
            .short("w")
            .default_value("800")
            .help("Width in pixels")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("HEIGHT")
            .long("height")
            .short("h")
            .default_value("600")
            .help("Height in pixels")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("COUNT")
            .long("count")
            .short("c")
            .default_value("1")
            .help("Saves N screenshots of size WxH, rotating evenly spaced around the object")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("headless")
            .long("headless")
            .help("Use real headless rendering for screenshots (Default is a hidden window) [EXPERIMENTAL]"))
        .arg(Arg::with_name("CAM-INDEX")
            .long("cam-index")
            .takes_value(true)
            .help("Use the glTF camera with the given index (starting at 0). \n\
                Default: Determine 'nice' camera position based on the scene's bounding box.
                All other camera options are ignored if this one is given.")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .arg(Arg::with_name("CAM-POS")
            .long("cam-pos")
            .takes_value(true)
            .allow_hyphen_values(true)
            .help("Camera (aka eye) position override as comma-separated Vector3. Example: 1.2,3.4,5.6"))
        .arg(Arg::with_name("CAM-TARGET")
            .long("cam-target")
            .takes_value(true)
            .allow_hyphen_values(true)
            .help("Camera target (aka center) override as comma-separated Vector3. Example: 1.2,3.4,5.6"))
        .arg(Arg::with_name("CAM-FOVY")
            .long("cam-fovy")
            .takes_value(true)
            .default_value("60")
            .help("Vertical field of view ('zoom') in degrees.")
            .validator(|value| value.parse::<u32>().map(|_| ()).map_err(|err| err.to_string())))
        .get_matches();
    let source = args.value_of("FILE").unwrap();

    let width: u32 = args.value_of("WIDTH").unwrap().parse().unwrap();
    let height: u32 = args.value_of("HEIGHT").unwrap().parse().unwrap();
    let count: u32 = args.value_of("COUNT").unwrap().parse().unwrap();

    let camera_options = CameraOptions {
        index: args.value_of("CAM-INDEX").map(|n| n.parse().unwrap()),
        position: args.value_of("CAM-POS").map(|v| parse_vec3(v).unwrap()),
        target: args.value_of("CAM-TARGET").map(|v| parse_vec3(v).unwrap()),
        fovy: args.value_of("CAM-FOVY").map(|n| n.parse().unwrap()).unwrap(),
    };

    let log_level = match args.occurrences_of("verbose") {
        0 => LevelFilter::Warn,
        1 => LevelFilter::Info,
        2 => LevelFilter::Debug,
        _ => LevelFilter::Trace
    };

    let _ = TermLogger::init(log_level, LogConfig { time: None, target: None, ..LogConfig::default() });

    let mut viewer = GltfViewer::new(source, width, height,
        args.is_present("headless"),
        !args.is_present("screenshot"),
        camera_options);

    if args.is_present("screenshot") {
        let filename = args.value_of("screenshot").unwrap();

        if !filename.to_lowercase().ends_with(".png") {
            warn!("filename should end with .png");
        }
        if count > 1 {
            viewer.multiscreenshot(filename, width, height, count)
        } else {
            viewer.screenshot(filename, width, height)
        }
        return;
    }

    viewer.start_render_loop();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn print_struct_sizes() {
        // run with `cargo test -- --nocapture`
        println!("Sizes in bytes:");
        println!("Scene:     {:>3}", std::mem::size_of::<render::Scene>());
        println!("Node:      {:>3}", std::mem::size_of::<render::Node>());
        println!("Mesh:      {:>3}", std::mem::size_of::<render::Mesh>());
        println!("Primitive: {:>3}", std::mem::size_of::<render::Primitive>());
        println!("Vertex:    {:>3}", std::mem::size_of::<render::Vertex>());
        println!();
        println!("Option<String>: {:>3}", std::mem::size_of::<Option<String>>());
        println!("String:         {:>3}", std::mem::size_of::<String>());
        println!("Vec<f32>:       {:>3}", std::mem::size_of::<Vec<f32>>());
        println!("Vec<Node>:      {:>3}", std::mem::size_of::<Vec<render::Node>>());
    }

//     extern crate test;
//     use self::test::Bencher;
//     #[bench]
//     fn bench_frame_timer(b: &mut Bencher) {
//         let mut timer = FrameTimer::new("Foobar", 60);
//         b.iter(|| {
//             for _ in 0..60 {
//                 timer.start();
//                 timer.end();
//             }
//         })
//     }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

extern crate arguments;
extern crate database;

use database::Database;
use database::driver::sqlite;
use std::fmt::Display;

const USAGE: &'static str = "
Usage: planner [options]

Options:
    --database <path>        SQLite3 database (required).
    --table <name>           Table containing area estimates (required).
    --cores <number>         Number of cores (required).
    --format (3d-ice|svg)    Output format [default: 3d-ice].

    --help                   Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

mod format;
mod layout;

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    use format::Format;
    use layout::Layout;

    let arguments = ok!(arguments::parse(std::env::args()));

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let backend = match arguments.get::<String>("database") {
        Some(ref database) => {
            if std::fs::metadata(database).is_err() {
                raise!("the database does not exist");
            }
            ok!(Database::open(database))
        },
        _ => raise!("a database filename is required"),
    };
    let (core_area, l3_area) = match arguments.get::<String>("table") {
        Some(ref table) => {
            (ok!(find(&backend, table, "core%")), ok!(find(&backend, table, "l3%")))
        },
        _ => raise!("a table name is required"),
    };
    let core_count = match arguments.get::<usize>("cores") {
        Some(core_count) if core_count > 0 => core_count,
        _ => raise!("a number of cores is required"),
    };

    let spec = layout::Spec {
        core_count: core_count,
        core_area: core_area,
        l3_area: l3_area,
    };

    let layout = layout::Tiles;
    let format = match &*arguments.get::<String>("format").unwrap_or("3d-ice".to_string()) {
        "svg" => Box::new(format::SVG) as Box<Format>,
        "3d-ice" => Box::new(format::ThreeDICE) as Box<Format>,
        _ => raise!("the output format is unknown"),
    };

    format.print(&ok!(layout.construct(&spec)), &mut std::io::stdout())
}

fn find(backend: &Database<sqlite::Driver>, table: &str, like: &str) -> Result<f64> {
    use database::prelude::*;

    let statement = select().table(table).column("area")
                            .wherein(column().name("name").like(like)).limit(1);

    let mut statement = ok!(backend.prepare(statement));
    ok!(statement.execute(&[]));

    if let Some(record) = ok!(statement.next()) {
        if let Some(&Value::Float(value)) = record.get(1) {
            return Ok(value);
        }
    }

    raise!("failed to find a required value in the table");
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    stderr().write_all(format!("Error: {}.\n", &*error).as_bytes()).unwrap();
    std::process::exit(1);
}
<commit_msg>Fix the query<commit_after>#![cfg_attr(test, allow(dead_code))]

extern crate arguments;
extern crate database;

use database::Database;
use database::driver::sqlite;
use std::fmt::Display;

const USAGE: &'static str = "
Usage: planner [options]

Options:
    --database <path>        SQLite3 database (required).
    --table <name>           Table containing area estimates (required).
    --cores <number>         Number of cores (required).
    --format (3d-ice|svg)    Output format [default: 3d-ice].

    --help                   Display this message.
";

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

mod format;
mod layout;

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    use format::Format;
    use layout::Layout;

    let arguments = ok!(arguments::parse(std::env::args()));

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let backend = match arguments.get::<String>("database") {
        Some(ref database) => {
            if std::fs::metadata(database).is_err() {
                raise!("the database does not exist");
            }
            ok!(Database::open(database))
        },
        _ => raise!("a database filename is required"),
    };
    let (core_area, l3_area) = match arguments.get::<String>("table") {
        Some(ref table) => {
            (ok!(find(&backend, table, "core%")), ok!(find(&backend, table, "l3%")))
        },
        _ => raise!("a table name is required"),
    };
    let core_count = match arguments.get::<usize>("cores") {
        Some(core_count) if core_count > 0 => core_count,
        _ => raise!("a number of cores is required"),
    };

    let spec = layout::Spec {
        core_count: core_count,
        core_area: core_area,
        l3_area: l3_area,
    };

    let layout = layout::Tiles;
    let format = match &*arguments.get::<String>("format").unwrap_or("3d-ice".to_string()) {
        "svg" => Box::new(format::SVG) as Box<Format>,
        "3d-ice" => Box::new(format::ThreeDICE) as Box<Format>,
        _ => raise!("the output format is unknown"),
    };

    format.print(&ok!(layout.construct(&spec)), &mut std::io::stdout())
}

fn find(backend: &Database<sqlite::Driver>, table: &str, like: &str) -> Result<f64> {
    use database::prelude::*;

    let statement = select().table(table).column("name").column("area")
                            .wherein(column().name("name").like(like)).limit(1);

    let mut statement = ok!(backend.prepare(statement));
    ok!(statement.execute(&[]));

    if let Some(record) = ok!(statement.next()) {
        if let Some(&Value::Float(value)) = record.get(1) {
            return Ok(value);
        }
    }

    raise!("failed to find a required value in the table");
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    use std::io::{stderr, Write};
    stderr().write_all(format!("Error: {}.\n", &*error).as_bytes()).unwrap();
    std::process::exit(1);
}
<|endoftext|>


<commit_before>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use cgmath::vector::{Vector3, Vector4};
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct Color4<T> { inner: Vector4<T>, }

impl<T: Clone> Clone for Color4<T> {
  fn clone(&self) -> Color4<T> {
    Color4 { inner: self.inner.clone(), }
  }
}

impl<T: Clone> Color4<T> {
  fn new(v: &Vector4<T>) -> Color4<T> {
    Color4 { inner: v.clone(), }
  }
}

pub struct Vertex<T> {
  position: Vector3<T>,
  color: Color4<T>,
}

impl<T: Clone> Clone for Vertex<T> {
  fn clone(&self) -> Vertex<T> {
    Vertex {
      position: self.position.clone(),
      color: self.color.clone(),
    }
  }
}

impl<T: Clone> Vertex<T> {
  fn new(v: &Vector3<T>, c: &Color4<T>) -> Vertex<T> {
    Vertex {
      position: v.clone(),
      color: c.clone(),
    }
  }
}

pub struct Triangle<T> {
  vertices: [Vertex<T>, ..3],
}

impl<T: Clone> Clone for Triangle<T> {
  fn clone(&self) -> Triangle<T> {
    Triangle {
      vertices: [self.vertices[0].clone(), self.vertices[1].clone(), self.vertices[2].clone()],
    }
  }
}

pub struct App {
  vao: u32,
  vbo: u32,
  vertex_data: Vec<Triangle<GLfloat>>,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl<T: Clone> Triangle<T> {
  fn new(
      v1: &Vertex<T>,
      v2: &Vertex<T>,
      v3: &Vertex<T>)
      -> Triangle<T> {
    Triangle {
      vertices: [v1.clone(), v2.clone(), v3.clone()],
    }
  }
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (self.vertex_data.len() * mem::size_of::<Triangle<GLfloat>>()) as GLsizeiptr,
                      mem::transmute(self.vertex_data.get(0)),
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);
      let color_attr = "in_color".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(color_attr as GLuint);

      gl::VertexAttribPointer(
          pos_attr as GLuint,
          (mem::size_of::<Vector3<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null(),
      );
      gl::VertexAttribPointer(
          color_attr as GLuint,
          (mem::size_of::<Color4<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null().offset(mem::size_of::<Vector3<GLfloat>>() as int),
      );
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    gl::DrawArrays(gl::TRIANGLES, 0, 3 * self.vertex_data.len() as i32);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      vertex_data: Vec::from_slice([
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0), &Color4::new(&Vector4::new(1.0, 0.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new( 0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 1.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 0.0, 1.0, 1.0))),
        ),
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0), &Color4::new(&Vector4::new(1.0, 0.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 1.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-1.0,  0.5, 0.0), &Color4::new(&Vector4::new(0.0, 0.0, 1.0, 1.0))),
        ),
      ]),
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn destroy(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
in vec4 in_color;\n\
varying vec4 color;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
color = in_color;\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
varying vec4 color;\n\
out vec4 out_color;\n\
void main() {\n\
out_color = color;\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<commit_msg>fix destructor<commit_after>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use cgmath::vector::{Vector3, Vector4};
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct Color4<T> { inner: Vector4<T>, }

impl<T: Clone> Clone for Color4<T> {
  fn clone(&self) -> Color4<T> {
    Color4 { inner: self.inner.clone(), }
  }
}

impl<T: Clone> Color4<T> {
  fn new(v: &Vector4<T>) -> Color4<T> {
    Color4 { inner: v.clone(), }
  }
}

pub struct Vertex<T> {
  position: Vector3<T>,
  color: Color4<T>,
}

impl<T: Clone> Clone for Vertex<T> {
  fn clone(&self) -> Vertex<T> {
    Vertex {
      position: self.position.clone(),
      color: self.color.clone(),
    }
  }
}

impl<T: Clone> Vertex<T> {
  fn new(v: &Vector3<T>, c: &Color4<T>) -> Vertex<T> {
    Vertex {
      position: v.clone(),
      color: c.clone(),
    }
  }
}

pub struct Triangle<T> {
  vertices: [Vertex<T>, ..3],
}

impl<T: Clone> Clone for Triangle<T> {
  fn clone(&self) -> Triangle<T> {
    Triangle {
      vertices: [self.vertices[0].clone(), self.vertices[1].clone(), self.vertices[2].clone()],
    }
  }
}

pub struct App {
  vao: u32,
  vbo: u32,
  vertex_data: Vec<Triangle<GLfloat>>,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl<T: Clone> Triangle<T> {
  fn new(
      v1: &Vertex<T>,
      v2: &Vertex<T>,
      v3: &Vertex<T>)
      -> Triangle<T> {
    Triangle {
      vertices: [v1.clone(), v2.clone(), v3.clone()],
    }
  }
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (self.vertex_data.len() * mem::size_of::<Triangle<GLfloat>>()) as GLsizeiptr,
                      mem::transmute(self.vertex_data.get(0)),
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);
      let color_attr = "in_color".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(color_attr as GLuint);

      gl::VertexAttribPointer(
          pos_attr as GLuint,
          (mem::size_of::<Vector3<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null(),
      );
      gl::VertexAttribPointer(
          color_attr as GLuint,
          (mem::size_of::<Color4<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null().offset(mem::size_of::<Vector3<GLfloat>>() as int),
      );
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    gl::DrawArrays(gl::TRIANGLES, 0, 3 * self.vertex_data.len() as i32);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      vertex_data: Vec::from_slice([
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0), &Color4::new(&Vector4::new(1.0, 0.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new( 0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 1.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 0.0, 1.0, 1.0))),
        ),
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0), &Color4::new(&Vector4::new(1.0, 0.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 1.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-1.0,  0.5, 0.0), &Color4::new(&Vector4::new(0.0, 0.0, 1.0, 1.0))),
        ),
      ]),
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn drop(&self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
in vec4 in_color;\n\
varying vec4 color;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
color = in_color;\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
varying vec4 color;\n\
out vec4 out_color;\n\
void main() {\n\
out_color = color;\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<|endoftext|>


<commit_before>use std::mem;

#[derive(Clone, Copy, Debug)]
enum Stone {
    Flat,
    Standing,
    Capstone,
}

#[derive(Clone, Copy, Debug)]
enum Player {
    One,
    Two,
}

#[derive(Clone, Copy, Debug)]
struct Piece {
    stone: Stone,
    owner: Player,
}

#[derive(Clone, Debug)]
struct Cell {
    pieces: Vec<Piece>,
}

impl Cell {
    fn new() -> Cell {
        Cell { pieces: vec![] }
    }

    fn len(&self) -> usize {
        self.pieces.len()
    }

    fn add_piece(&mut self, piece: Piece) -> () {
        self.pieces.push(piece);
    }

    fn place_piece(&mut self, piece: Piece) -> () {
        assert!(self.pieces.len() == 0,
                "Cannot place stone on top of existing stone.");
        self.pieces.push(piece);
    }
}

enum Direction {
    Right,
    Left,
    Up,
    Down,
}

impl Direction {
    fn adjust(&self, x: usize, y: usize, offset: usize) -> (usize, usize) {
        match self {
            &Direction::Right => (x + offset, y),
            &Direction::Left => (x - offset, y),
            &Direction::Up => (x, y + offset),
            &Direction::Down => (x, y - offset),
        }
    }
}

trait Turn {
    fn play(&self, &mut Board) -> ();
}

struct Placement {
    x: usize,
    y: usize,
    piece: Piece,
}

impl Turn for Placement {
    fn play(&self, board: &mut Board) -> () {
        board.grid[self.x][self.y].place_piece(self.piece);
    }
}

struct Slide {
    x: usize,
    y: usize,
    direction: Direction,
    offsets: Vec<usize>,
}

impl Slide {
    fn locations(&self) -> Vec<(usize, usize)> {
        let mut points = Vec::<(usize, usize)>::new();
        for offset in self.offsets.iter() {
            points.push(self.direction.adjust(self.x, self.y, *offset))
        }
        points
    }
}

impl Turn for Slide {
    fn play(&self, board: &mut Board) -> () {
        assert!(self.offsets.len() == board.grid[self.x][self.y].len(),
                "Trying to move a different number of pieces than exist.");

        let cell = mem::replace(&mut board.grid[self.x][self.y], Cell::new());
        for (point, piece) in self.locations().iter().zip(cell.pieces.iter()) {
            let (x, y) = *point;
            board.grid[x][y].add_piece(*piece);
        }
    }
}

#[derive(Debug)]
struct Board {
    grid: Vec<Vec<Cell>>,
}

impl Board {
    fn new(board_size: usize) -> Board {
        Board { grid: vec![vec![Cell::new(); board_size]; board_size] }
    }

    fn play<T: Turn>(&mut self, turn: T) -> () {
        turn.play(self);
    }
}

fn main() {
    let mut game = Board::new(4);
    Placement { x: 0, y: 0, piece: Piece { stone: Stone::Standing, owner: Player::One }}.play(&mut game);
    Placement { x: 0, y: 1, piece: Piece { stone: Stone::Standing, owner: Player::Two }}.play(&mut game);
    Slide { x: 0, y: 0, direction: Direction::Up, offsets: vec![1]}.play(&mut game);
    Slide { x: 0, y: 1, direction: Direction::Right, offsets: vec![1, 2]}.play(&mut game);
    println!("{:#?}", game);
}
<commit_msg>Use an enum for Turn<commit_after>use std::mem;

#[derive(Clone, Copy, Debug)]
enum Stone {
    Flat,
    Standing,
    Capstone,
}

#[derive(Clone, Copy, Debug)]
enum Player {
    One,
    Two,
}

#[derive(Clone, Copy, Debug)]
struct Piece {
    stone: Stone,
    owner: Player,
}

#[derive(Clone, Debug)]
struct Cell {
    pieces: Vec<Piece>,
}

impl Cell {
    fn new() -> Cell {
        Cell { pieces: vec![] }
    }

    fn len(&self) -> usize {
        self.pieces.len()
    }

    fn add_piece(&mut self, piece: Piece) -> () {
        // TODO: Stacking checks
        self.pieces.push(piece);
    }

    fn place_piece(&mut self, piece: Piece) -> () {
        assert!(self.pieces.len() == 0,
                "Cannot place stone on top of existing stone.");
        self.pieces.push(piece);
    }
}

enum Direction {
    Right,
    Left,
    Up,
    Down,
}

impl Direction {
    fn adjust(&self, x: usize, y: usize, offset: usize) -> (usize, usize) {
        match self {
            &Direction::Right => (x + offset, y),
            &Direction::Left => (x - offset, y),
            &Direction::Up => (x, y + offset),
            &Direction::Down => (x, y - offset),
        }
    }
}

enum Turn {
    Placement {
        x: usize,
        y: usize,
        piece: Piece,
    },
    Slide {
        x: usize,
        y: usize,
        direction: Direction,
        offsets: Vec<usize>,
    },
}

fn play(turn: &Turn, board: &mut Board) -> () {
    match turn {
        &Turn::Placement { x, y, piece } => {
            board.grid[x][y].place_piece(piece);
        }
        &Turn::Slide { x, y, ref direction, ref offsets } => {
            assert!(offsets.len() == board.grid[x][y].len(),
                    "Trying to move a different number of pieces than exist.");

            let cell = mem::replace(&mut board.grid[x][y], Cell::new());
            let points = offsets.iter().map(|z| direction.adjust(x, y, *z));
            for (point, piece) in points.zip(cell.pieces.iter()) {
                let (x, y) = point;
                board.grid[x][y].add_piece(*piece);
            }
        }
    }
}

#[derive(Debug)]
struct Board {
    grid: Vec<Vec<Cell>>,
}

impl Board {
    fn new(board_size: usize) -> Board {
        Board { grid: vec![vec![Cell::new(); board_size]; board_size] }
    }
}

fn main() {
    let mut game = Board::new(4);
    Placement { x: 0, y: 0, piece: Piece { stone: Stone::Standing, owner: Player::One }}.play(&mut game);
    Placement { x: 0, y: 1, piece: Piece { stone: Stone::Standing, owner: Player::Two }}.play(&mut game);
    Slide { x: 0, y: 0, direction: Direction::Up, offsets: vec![1]}.play(&mut game);
    Slide { x: 0, y: 1, direction: Direction::Right, offsets: vec![1, 2]}.play(&mut game);
    println!("{:#?}", game);
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]

#[macro_use] extern crate clap;
extern crate chrono;
#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate lazy_static;
extern crate libsqlite3_sys;
extern crate regex;
extern crate xdg;

use chrono::{UTC, TimeZone};
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use clap::App;

mod commands;
mod config;
mod models;
mod schema;
mod types;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

embed_migrations!("migrations");

pub fn establish_connection() -> SqliteConnection {
    let database_url = config::get_database_url();
    let connection = SqliteConnection::establish(&database_url).unwrap();
    embedded_migrations::run(&connection).unwrap();
    connection
}

fn output_command(command: &models::History) {
    lazy_static! {
        static ref HISTTIMEFORMAT: Option<String> = match env::var("HISTTIMEFORMAT") {
            Ok(fmt) => Some(String::from(fmt.trim())),
            Err(_) => None
        };
    };
    match *HISTTIMEFORMAT {
        Some(ref fmt) => {
            let timestamp = UTC.timestamp(command.timestamp as i64, 0);
            println!("{}\t{}", timestamp.format(fmt), command.command);
        },
        None => println!("{}\t{}", command.timestamp, command.command)
    }
}

pub fn output_commands(commands: &Vec<models::History>) {
    for command in commands {
        output_command(&command);
    }
}

pub fn dispatch_command(matches: clap::ArgMatches) {
    let connection = establish_connection();
    match matches.subcommand() {
        ("head", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::head(&connection, entries) {
                output_commands(&commands);
            };
        }
        ("import", Some(m)) => {
            let stdin = io::stdin();
            let reader = match m.value_of("input") {
                None => Box::new(stdin.lock()) as Box<BufRead>,
                Some(path) if path == "-" => Box::new(stdin.lock()) as Box<BufRead>,
                Some(path) => Box::new(io::BufReader::new(File::open(path).unwrap())) as Box<BufRead>,
            };
            let mut quiet = false;
            if m.is_present("quiet") {
                quiet = true;
            }
            match commands::import(&connection, reader) {
                Ok(n) => {
                    if ! quiet {
                        println!("imported {} commands", n);
                    }
                }
                Err(why) => {
                    if ! quiet {
                        println!("{}", why);
                    }
                }
            };
        }
        ("log", Some(_)) => {
            if let Ok(commands) = commands::log(&connection) {
                output_commands(&commands);
            };
        }
        ("magic", Some(_)) => {
            commands::magic();
        }
        ("search", Some(m)) => {
            let expression = m.value_of("expression").unwrap();
            if let Ok(commands) = commands::search(&connection, expression) {
                output_commands(&commands);
            };
        }
        ("sqlite3", Some(m)) => {
            let database_url = config::get_database_url();
            let mut sqlite3_options: Vec<&str> = match m.values_of("sqlite3_options") {
                Some(options) => options.collect(),
                None => clap::Values::default().collect(),
            };
            sqlite3_options.push(&database_url);
            commands::sqlite3(sqlite3_options);
        }
        ("tail", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::tail(&connection, entries) {
                output_commands(&commands);
            };
        }
        ("top", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::top(&connection, entries) {
                for command in commands {
                    println!("\t{}\t{}", command.frequency, command.command);
                };
            };
        }
        ("version", Some(m)) => {
            let mut verbose = false;
            if m.is_present("verbose") {
                verbose = true;
            }
            commands::version(verbose);
        }
        _ => unreachable!(),
    }
}

fn main() {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml).get_matches();
    dispatch_command(matches);
}
<commit_msg>Disable unused nightly feature<commit_after>#[macro_use] extern crate clap;
extern crate chrono;
#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate lazy_static;
extern crate libsqlite3_sys;
extern crate regex;
extern crate xdg;

use chrono::{UTC, TimeZone};
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use clap::App;

mod commands;
mod config;
mod models;
mod schema;
mod types;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;

embed_migrations!("migrations");

pub fn establish_connection() -> SqliteConnection {
    let database_url = config::get_database_url();
    let connection = SqliteConnection::establish(&database_url).unwrap();
    embedded_migrations::run(&connection).unwrap();
    connection
}

fn output_command(command: &models::History) {
    lazy_static! {
        static ref HISTTIMEFORMAT: Option<String> = match env::var("HISTTIMEFORMAT") {
            Ok(fmt) => Some(String::from(fmt.trim())),
            Err(_) => None
        };
    };
    match *HISTTIMEFORMAT {
        Some(ref fmt) => {
            let timestamp = UTC.timestamp(command.timestamp as i64, 0);
            println!("{}\t{}", timestamp.format(fmt), command.command);
        },
        None => println!("{}\t{}", command.timestamp, command.command)
    }
}

pub fn output_commands(commands: &Vec<models::History>) {
    for command in commands {
        output_command(&command);
    }
}

pub fn dispatch_command(matches: clap::ArgMatches) {
    let connection = establish_connection();
    match matches.subcommand() {
        ("head", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::head(&connection, entries) {
                output_commands(&commands);
            };
        }
        ("import", Some(m)) => {
            let stdin = io::stdin();
            let reader = match m.value_of("input") {
                None => Box::new(stdin.lock()) as Box<BufRead>,
                Some(path) if path == "-" => Box::new(stdin.lock()) as Box<BufRead>,
                Some(path) => Box::new(io::BufReader::new(File::open(path).unwrap())) as Box<BufRead>,
            };
            let mut quiet = false;
            if m.is_present("quiet") {
                quiet = true;
            }
            match commands::import(&connection, reader) {
                Ok(n) => {
                    if ! quiet {
                        println!("imported {} commands", n);
                    }
                }
                Err(why) => {
                    if ! quiet {
                        println!("{}", why);
                    }
                }
            };
        }
        ("log", Some(_)) => {
            if let Ok(commands) = commands::log(&connection) {
                output_commands(&commands);
            };
        }
        ("magic", Some(_)) => {
            commands::magic();
        }
        ("search", Some(m)) => {
            let expression = m.value_of("expression").unwrap();
            if let Ok(commands) = commands::search(&connection, expression) {
                output_commands(&commands);
            };
        }
        ("sqlite3", Some(m)) => {
            let database_url = config::get_database_url();
            let mut sqlite3_options: Vec<&str> = match m.values_of("sqlite3_options") {
                Some(options) => options.collect(),
                None => clap::Values::default().collect(),
            };
            sqlite3_options.push(&database_url);
            commands::sqlite3(sqlite3_options);
        }
        ("tail", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::tail(&connection, entries) {
                output_commands(&commands);
            };
        }
        ("top", Some(m)) => {
            let entries = value_t!(m, "entries", i64).unwrap();
            if let Ok(commands) = commands::top(&connection, entries) {
                for command in commands {
                    println!("\t{}\t{}", command.frequency, command.command);
                };
            };
        }
        ("version", Some(m)) => {
            let mut verbose = false;
            if m.is_present("verbose") {
                verbose = true;
            }
            commands::version(verbose);
        }
        _ => unreachable!(),
    }
}

fn main() {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml).get_matches();
    dispatch_command(matches);
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;
use vm::Cell;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            while index < self.instructions.len() {
                let current_cell = vm.cells[vm.data_pointer];
                let patch = match (self.instructions[index], self.status) {
                    (_, ProgramStatus::Seeking(goal)) => {
                        Program::forward_jump(
                            &self.instructions,
                            index,
                            goal,
                            self.current_depth,
                        )
                    }

                    (Command::JumpForward, _) => self.process_jump_forward(index, current_cell),

                    (Command::JumpBackward, _) => {
                        match current_cell {
                            0 => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth - 1,
                            },

                            _ => {
                                Program::backward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                )
                            }
                        }
                    }

                    (command, _) => {
                        vm.apply(command);
                        ProgramPatch {
                            status: ProgramStatus::Normal,
                            current_depth: self.current_depth,
                            instruction_pointer: index + 1,
                        }
                    }
                };

                self.update(patch);
                index = patch.instruction_pointer;
            }
        }
    }

    fn process_jump_forward(&self, index: usize, current_cell: Cell) -> ProgramPatch {
        match current_cell {
            0 => {
                Program::forward_jump(
                    &self.instructions,
                    index,
                    self.current_depth,
                    self.current_depth,
                )
            }

            _ => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth: self.current_depth + 1,
            },
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(&commands[index..], Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![
            Command::JumpForward,
            Command::JumpForward,
            Command::JumpBackward,
        ];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(
            actual,
            ProgramPatch {
                instruction_pointer: 3,
                current_depth: 1,
                status: ProgramStatus::Seeking(0),
            }
        )
    }
}
<commit_msg>Add process_jump_backward fn<commit_after>use command::Command;
use vm::VM;
use vm::Cell;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            while index < self.instructions.len() {
                let current_cell = vm.cells[vm.data_pointer];
                let patch = match (self.instructions[index], self.status) {
                    (_, ProgramStatus::Seeking(goal)) => {
                        Program::forward_jump(
                            &self.instructions,
                            index,
                            goal,
                            self.current_depth,
                        )
                    }

                    (Command::JumpForward, _) => self.process_jump_forward(index, current_cell),

                    (Command::JumpBackward, _) => {
                        match current_cell {
                            0 => ProgramPatch {
                                instruction_pointer: index + 1,
                                status: ProgramStatus::Normal,
                                current_depth: self.current_depth - 1,
                            },

                            _ => {
                                Program::backward_jump(
                                    &self.instructions,
                                    index,
                                    self.current_depth,
                                )
                            }
                        }
                    }

                    (command, _) => {
                        vm.apply(command);
                        ProgramPatch {
                            status: ProgramStatus::Normal,
                            current_depth: self.current_depth,
                            instruction_pointer: index + 1,
                        }
                    }
                };

                self.update(patch);
                index = patch.instruction_pointer;
            }
        }
    }

    fn process_jump_backward(&self, index: usize, current_cell: Cell) -> ProgramPatch {
        match current_cell {
            0 => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth: self.current_depth - 1,
            },

            _ => {
                Program::backward_jump(
                    &self.instructions,
                    index,
                    self.current_depth,
                )
            }
        }
    }

    fn process_jump_forward(&self, index: usize, current_cell: Cell) -> ProgramPatch {
        match current_cell {
            0 => {
                Program::forward_jump(
                    &self.instructions,
                    index,
                    self.current_depth,
                    self.current_depth,
                )
            }

            _ => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth: self.current_depth + 1,
            },
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index + 1,
                    status: ProgramStatus::Normal,
                    current_depth: current_depth + 1,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(&commands[index..], Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index + 1,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![
            Command::JumpForward,
            Command::JumpForward,
            Command::JumpBackward,
        ];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(
            actual,
            ProgramPatch {
                instruction_pointer: 3,
                current_depth: 1,
                status: ProgramStatus::Seeking(0),
            }
        )
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) => {}

            (Some(index), ProgramStatus::Normal) => {}

            _ => {}
        }
    }
}
<commit_msg>Add match guards for index based operations<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {}

            (Some(index), ProgramStatus::Normal) if index < self.instructions.len() => {}

            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "pwd"]
#![feature(rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use std::env;
use std::io::Write;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "pwd";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let program = args[0].clone();
    let opts = [
        getopts::optflag("", "help", "display this help and exit"),
        getopts::optflag("", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(&args[1..], &opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "Invalid options\n{}", f)
        }
    };

    if matches.opt_present("help") {
        println!("pwd {}", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION] NAME...", program);
        println!("");
        print!("{}", getopts::usage("Print the full filename of the current working directory.", &opts));
    } else if matches.opt_present("version") {
        println!("pwd version: {}", VERSION);

        return 0;
    } else {
        println!("{:?}", env::current_dir().unwrap());

        return 0;
    }

    0
}
<commit_msg>Remove quotes from current directory.<commit_after>#![crate_name = "pwd"]
#![feature(rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use std::env;
use std::io::Write;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "pwd";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let program = args[0].clone();
    let opts = [
        getopts::optflag("", "help", "display this help and exit"),
        getopts::optflag("", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(&args[1..], &opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "Invalid options\n{}", f)
        }
    };

    if matches.opt_present("help") {
        println!("pwd {}", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION] NAME...", program);
        println!("");
        print!("{}", getopts::usage("Print the full filename of the current working directory.", &opts));
    } else if matches.opt_present("version") {
        println!("pwd version: {}", VERSION);

        return 0;
    } else {
        println!("{}", env::current_dir().unwrap().display());

        return 0;
    }

    0
}
<|endoftext|>