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

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_id="zinc"]
#![crate_type="rlib"]
#![allow(ctypes)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

extern crate core;

#[cfg(test)] #[phase(syntax,link)] extern crate std;
#[cfg(test)] extern crate native;

pub mod drivers;
pub mod hal;
pub mod lib;
pub mod os;

// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
}

#[test]
fn dummy_test() {
}
<commit_msg>Fix attribute deprication warning -<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_id="zinc"]
#![crate_type="rlib"]
#![allow(ctypes)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

extern crate core;

#[cfg(test)] #[phase(plugin,link)] extern crate std;
#[cfg(test)] extern crate native;

pub mod drivers;
pub mod hal;
pub mod lib;
pub mod os;

// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
}

#[test]
fn dummy_test() {
}
<|endoftext|>


<commit_before>extern crate unicode_names;

use std::env;
use std::fmt;
use std::char;

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match unicode_names::name(self.c) {
            // TODO: restructure this for high-bit chars
            Some(n) => {
                let num = self.c as u32;
                let quote : String = self.c.escape_default().collect();
                write!(f, "{} = {}, {:}, 0x{:x}, 0{:o}, bits {:b}: prints as {}",
                       self.c, n, num, num, num, num, quote)
            },
            None => write!(f, "{} is unknown", self.c)
        }
    }
}

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns either None (if the
/// character description is not understood), or Some(Describable)
/// that holds the character.
fn from_arg(spec: &str) -> Vec<Describable> {
    let mut res : Vec<Describable> = Vec::new();

    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| res.push(Describable{c: c}));
    } else {
        unicode_names::character(spec).map(|c| res.push(Describable{c: c}));
    }
    for base in vec![10, 16, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| res.push(Describable{c: c})));
    }
    res
}

fn main() {
    let args =
        env::args().skip(1)
        .flat_map(|argument| from_arg(argument.as_ref()));
    for c in args {
        println!("{}", c);
    }
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('c', from_arg("c")[0].c);
    assert_eq!(']', from_arg("]")[0].c);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('c', from_arg("latin small letter c")[0].c);
    assert_eq!(']', from_arg("right square bracket")[0].c);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    assert_eq!('<', received[0].c);
    assert_eq!('`', received[1].c);
    assert_eq!('0', received[2].c);
}
<commit_msg>Flip base 16/10<commit_after>extern crate unicode_names;

use std::env;
use std::fmt;
use std::char;

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match unicode_names::name(self.c) {
            // TODO: restructure this for high-bit chars
            Some(n) => {
                let num = self.c as u32;
                let quote : String = self.c.escape_default().collect();
                write!(f, "{} = {}, {:}, 0x{:x}, 0{:o}, bits {:b}: prints as {}",
                       self.c, n, num, num, num, num, quote)
            },
            None => write!(f, "{} is unknown", self.c)
        }
    }
}

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns either None (if the
/// character description is not understood), or Some(Describable)
/// that holds the character.
fn from_arg(spec: &str) -> Vec<Describable> {
    let mut res : Vec<Describable> = Vec::new();

    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| res.push(Describable{c: c}));
    } else {
        unicode_names::character(spec).map(|c| res.push(Describable{c: c}));
    }
    for base in vec![16, 10, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| res.push(Describable{c: c})));
    }
    res
}

fn main() {
    let args =
        env::args().skip(1)
        .flat_map(|argument| from_arg(argument.as_ref()));
    for c in args {
        println!("{}", c);
    }
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('c', from_arg("c")[0].c);
    assert_eq!(']', from_arg("]")[0].c);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('c', from_arg("latin small letter c")[0].c);
    assert_eq!(']', from_arg("right square bracket")[0].c);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    let mut iter = received.iter();
    assert_eq!('`', iter.next().unwrap().c);
    assert_eq!('<', iter.next().unwrap().c);
    assert_eq!('0', iter.next().unwrap().c);
}
<|endoftext|>


<commit_before>#![feature(tuple_indexing)]
#![feature(struct_inherit)]
#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate num;
extern crate native;
extern crate glfw;

use glfw::Context;
use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let mut memory = Memory::new(65536);
    let mut cpu = Cpu::new(&mut memory);
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    let (window, events) = glfw.create_window(256, 256, "Hello this is window", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_key_polling(true);
    window.make_current();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }

        let clock_cycle = cpu.tick();
    }
}

//#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        },
        glfw::KeyEvent(glfw::KeyUp, _, glfw::Press, _) => {
        },
        _ => {}
    }
}
<commit_msg>Remove extern crate num from main.rs<commit_after>#![feature(tuple_indexing)]
#![feature(struct_inherit)]
#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate native;
extern crate glfw;

use glfw::Context;
use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let mut memory = Memory::new(65536);
    let mut cpu = Cpu::new(&mut memory);
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    let (window, events) = glfw.create_window(256, 256, "Hello this is window", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_key_polling(true);
    window.make_current();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }

        let clock_cycle = cpu.tick();
    }
}

//#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        },
        glfw::KeyEvent(glfw::KeyUp, _, glfw::Press, _) => {
        },
        _ => {}
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate clap;
extern crate hyper;
extern crate hyper_native_tls;

mod gitignore;
mod cli;

use std::fs::{File, OpenOptions, create_dir, read_dir};
use std::io::{BufReader, Result, Error, ErrorKind};
use std::io::prelude::*;
use std::path::Path;
use std::process::{exit, Command};
use std::env;

#[derive(Deserialize)]
struct Config {
    mkdir: Option<Vec<String>>,
    touch: Option<Vec<String>>,
    exec: Option<Vec<String>>,
    gitignore: Option<Vec<String>>,
    include: Option<Vec<String>>,
    order: Option<Vec<String>>,
}

fn main() {
    let matches = cli::build_cli().get_matches();
    let lang = matches.value_of("lang").unwrap();

    if let Some(matches) = matches.subcommand_matches("new") {
        println!("doing new {}", matches.value_of("NAME").unwrap());
    }

    let config_path = match get_config_path(&lang.to_string()) {
        Some(p) => p,
        None => {
            println!("Could not find home directory");
            exit(1);
        }
    };

    let config: Config = match parse_config(config_path) {
        Ok(c) => c,
        Err(err) => {
            println!("Error while parsing config! {:?}", err);
            exit(1);
        }
    };

    if let Some(subcmd) = matches.subcommand_matches("new") {
        let name = subcmd.value_of("NAME").unwrap();
        if file_exists(&name.to_string()) {
            println!("A file or directory with that name already exists");
            exit(1);
        } else {
            match create_dir(name.clone()) {
                Ok(_) => println!("Created directory '{}'", name),
                Err(e) => {
                    println!("Could not create directory '{}'. {:?}", name, e);
                    exit(1);
                }
            }
            if let Err(_) = env::set_current_dir(Path::new(&*name)) {
                println!("Could not change directory!");
                exit(1);
            }
        }
    }

    if !dir_is_empty(&".".to_string()) {
        println!("Directory is not empty!");
        exit(1);
    }

    if let Some(ref includes) = config.include {
        for incl in includes {
            let path = match get_config_path(&incl) {
                Some(p) => p,
                None => {
                    println!("Could not resolve home directory");
                    exit(1);
                }
            };

            let conf: Config = match parse_config(path) {
                Ok(c) => c,
                Err(e) => {
                    println!("Could not read include '{}'. {}", incl, e);
                    exit(1);
                }
            };
            process_config(conf);
        }
    }

    process_config(config);

}

fn mkdir(dirs: &Option<Vec<String>>) {
    if let Some(ref dirs) = *dirs {
        for dir in dirs {
            if !file_exists(&dir) {
                match create_dir(dir.clone()) {
                    Ok(_) => println!("Created directory '{}'", dir),
                    Err(e) => println!("Could not create directory '{}'. {:?}", dir, e),
                }
            } else {
                println!("Directory '{}' already exists", dir);
            }
        }
    }
}

fn gitignore(gi: &Option<Vec<String>>) {
    if let Some(ref gi) = *gi {
        let ign = gitignore::get_gitignore(&gi).unwrap();
        let file = OpenOptions::new()
            .create_new(true)
            .append(true)
            .open(".gitignore");
        if let Ok(mut file) = file {
            match writeln!(file, "{}", ign) {
                Ok(_) => {}
                Err(e) => println!("Could not write .gitignore. {:?}", e),
            }
        } else {
            println!("Could not write .gitignore");
        }
    }
}

fn touch(files: &Option<Vec<String>>) {
    if let Some(ref fnames) = *files {
        for file in fnames {
            if !create_file(&file) {
                println!("Could not create file '{}'", file);
            }
        }
    }
}

fn exec_list(cmd_list: &Option<Vec<String>>) {
    if let Some(ref cmds) = *cmd_list {
        for cmd in cmds {
            println!("Executing '{}'", cmd);
            match exec(&cmd) {
                Ok((out, err)) => {
                    println!("stdout: {}", out);
                    println!("stderr: {}", err);
                }
                Err(e) => println!("Failed to execute: {:?}", e),
            }
        }
    }
}

fn process_config(config: Config) {
    let order: Vec<String> = match config.order {
        Some(order) => order,
        None => {
            vec!["mkdir".to_string(),
                 "gitignore".to_string(),
                 "touch".to_string(),
                 "exec".to_string()]
        }
    };

    for ord in order {
        match &*ord {
            "mkdir" => mkdir(&config.mkdir),
            "gitignore" => gitignore(&config.gitignore),
            "touch" => touch(&config.touch),
            "exec" => exec_list(&config.exec),
            x => println!("Unknown operation \"{}\"", x),
        }
    }
}

/// Returns the config path for a `lang` parameter.
///
/// This method concatenates $HOME with "/.skeleton/{lang}.toml"
///
/// # Examples
///
/// ```
/// let path = get_config_path(&"rust".to_string())
/// ```
fn get_config_path(lang: &String) -> Option<String> {
    let home = match env::home_dir() {
        Some(p) => p,
        None => return None,
    };
    let config_path_cow = home.to_string_lossy();
    let mut config_path = config_path_cow.into_owned();
    // let mut config_path = env!("HOME").to_string();

    config_path.push_str("/.skeleton/");
    config_path.push_str(lang);
    config_path.push_str(".toml");
    Some(config_path)
}

/// Checks if a directory is empty
///
/// # Examples
///
/// ```
/// let dir_is_empty(&".".to_string());
/// ```
fn dir_is_empty(dir: &String) -> bool {
    let paths = match read_dir(dir) {
        Ok(paths) => paths,
        Err(_) => return false,
    };

    for _ in paths {
        return false;
    }
    true
}

/// Checks if a file exists
fn file_exists(name: &String) -> bool {
    Path::new(&name).exists()
}

/// Executes a command using `sh` or `cmd.exe` depending on the used operating system.
///
/// Returns either a `Error` or a tuple `(stdout, stderr)`
fn exec(cmd: &String) -> Result<(String, String)> {
    #[cfg(unix)]
    let shell = "sh";
    #[cfg(unix)]
    let arg1 = "-c";
    #[cfg(windows)]
    let shell = "cmd.exe";
    #[cfg(windows)]
    let arg1 = "/C";

    let out = Command::new(shell).arg(arg1).arg(cmd).output()?;

    Ok((String::from_utf8(out.stdout).unwrap_or("Could not parse stdout".to_string()),
        String::from_utf8(out.stderr).unwrap_or("Could not parse stderr".to_string())))

}

/// Creates a file if it doesn't exist.
fn create_file(file_name: &String) -> bool {
    !file_exists(&file_name) &&
    OpenOptions::new()
        .append(true)
        .create(true)
        .open(file_name)
        .is_ok()
}

/// Parses a configuration file and returns the `Config` struct.
fn parse_config(file_name: String) -> Result<Config> {
    let file = File::open(file_name)?;
    let mut reader = BufReader::new(file);
    let mut contents = String::new();

    reader.read_to_string(&mut contents)?;

    toml::from_str(&contents).map_err(|err| Error::new(ErrorKind::InvalidInput, err))
}

#[test]
fn test_file_exists() {
    assert!(file_exists(&"test/foo.toml".to_string()));
    assert!(!file_exists(&"test/none".to_string()));
}

#[test]
fn test_parse_config() {
    let conf = parse_config("test/foo.toml".to_string()).unwrap();
    let gi = conf.gitignore.unwrap();
    assert_eq!(gi, vec!["rust".to_string(), "vim".to_string()]);

    let mkd = conf.mkdir.unwrap();
    assert_eq!(mkd, vec!["b".to_string()]);

    let touch = conf.touch.unwrap();
    assert_eq!(touch, vec!["a".to_string()]);

    let exec = conf.exec.unwrap();
    assert_eq!(exec, vec!["touch asdf".to_string()]);
}

#[test]
fn test_exec() {
    let (stdout, stderr) = exec(&"echo test".to_string()).unwrap();
    #[cfg(unix)]
    assert_eq!(stdout, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stdout, "test\r\n".to_string());
    assert_eq!(stderr, "".to_string());
    let (stdout, stderr) = exec(&"echo test 1>&2".to_string()).unwrap();
    assert_eq!(stdout, "".to_string());
    #[cfg(unix)]
    assert_eq!(stderr, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stderr, "test\r\n".to_string());
}

#[test]
fn test_dir_is_empty() {
    let is_empty = dir_is_empty(&"./test".to_string());
    assert!(!is_empty);
    let non_existent = dir_is_empty(&"./non_existent_dir".to_string());
    assert!(!non_existent);
}

#[test]
fn test_get_config_path() {
    let expected = get_config_path(&"foo".to_string()).unwrap();
    let mut actual = env::home_dir().unwrap().to_str().unwrap().to_string();
    actual.push_str("/.skeleton/foo.toml");
    assert_eq!(actual, expected);
}
<commit_msg>Fix Windows test cases<commit_after>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate clap;
extern crate hyper;
extern crate hyper_native_tls;

mod gitignore;
mod cli;

use std::fs::{File, OpenOptions, create_dir, read_dir};
use std::io::{BufReader, Result, Error, ErrorKind};
use std::io::prelude::*;
use std::path::Path;
use std::process::{exit, Command};
use std::env;

#[derive(Deserialize)]
struct Config {
    mkdir: Option<Vec<String>>,
    touch: Option<Vec<String>>,
    exec: Option<Vec<String>>,
    gitignore: Option<Vec<String>>,
    include: Option<Vec<String>>,
    order: Option<Vec<String>>,
}

fn main() {
    let matches = cli::build_cli().get_matches();
    let lang = matches.value_of("lang").unwrap();

    if let Some(matches) = matches.subcommand_matches("new") {
        println!("doing new {}", matches.value_of("NAME").unwrap());
    }

    let config_path = match get_config_path(&lang.to_string()) {
        Some(p) => p,
        None => {
            println!("Could not find home directory");
            exit(1);
        }
    };

    let config: Config = match parse_config(config_path) {
        Ok(c) => c,
        Err(err) => {
            println!("Error while parsing config! {:?}", err);
            exit(1);
        }
    };

    if let Some(subcmd) = matches.subcommand_matches("new") {
        let name = subcmd.value_of("NAME").unwrap();
        if file_exists(&name.to_string()) {
            println!("A file or directory with that name already exists");
            exit(1);
        } else {
            match create_dir(name.clone()) {
                Ok(_) => println!("Created directory '{}'", name),
                Err(e) => {
                    println!("Could not create directory '{}'. {:?}", name, e);
                    exit(1);
                }
            }
            if let Err(_) = env::set_current_dir(Path::new(&*name)) {
                println!("Could not change directory!");
                exit(1);
            }
        }
    }

    if !dir_is_empty(&".".to_string()) {
        println!("Directory is not empty!");
        exit(1);
    }

    if let Some(ref includes) = config.include {
        for incl in includes {
            let path = match get_config_path(&incl) {
                Some(p) => p,
                None => {
                    println!("Could not resolve home directory");
                    exit(1);
                }
            };

            let conf: Config = match parse_config(path) {
                Ok(c) => c,
                Err(e) => {
                    println!("Could not read include '{}'. {}", incl, e);
                    exit(1);
                }
            };
            process_config(conf);
        }
    }

    process_config(config);

}

fn mkdir(dirs: &Option<Vec<String>>) {
    if let Some(ref dirs) = *dirs {
        for dir in dirs {
            if !file_exists(&dir) {
                match create_dir(dir.clone()) {
                    Ok(_) => println!("Created directory '{}'", dir),
                    Err(e) => println!("Could not create directory '{}'. {:?}", dir, e),
                }
            } else {
                println!("Directory '{}' already exists", dir);
            }
        }
    }
}

fn gitignore(gi: &Option<Vec<String>>) {
    if let Some(ref gi) = *gi {
        let ign = gitignore::get_gitignore(&gi).unwrap();
        let file = OpenOptions::new()
            .create_new(true)
            .append(true)
            .open(".gitignore");
        if let Ok(mut file) = file {
            match writeln!(file, "{}", ign) {
                Ok(_) => {}
                Err(e) => println!("Could not write .gitignore. {:?}", e),
            }
        } else {
            println!("Could not write .gitignore");
        }
    }
}

fn touch(files: &Option<Vec<String>>) {
    if let Some(ref fnames) = *files {
        for file in fnames {
            if !create_file(&file) {
                println!("Could not create file '{}'", file);
            }
        }
    }
}

fn exec_list(cmd_list: &Option<Vec<String>>) {
    if let Some(ref cmds) = *cmd_list {
        for cmd in cmds {
            println!("Executing '{}'", cmd);
            match exec(&cmd) {
                Ok((out, err)) => {
                    println!("stdout: {}", out);
                    println!("stderr: {}", err);
                }
                Err(e) => println!("Failed to execute: {:?}", e),
            }
        }
    }
}

fn process_config(config: Config) {
    let order: Vec<String> = match config.order {
        Some(order) => order,
        None => {
            vec!["mkdir".to_string(),
                 "gitignore".to_string(),
                 "touch".to_string(),
                 "exec".to_string()]
        }
    };

    for ord in order {
        match &*ord {
            "mkdir" => mkdir(&config.mkdir),
            "gitignore" => gitignore(&config.gitignore),
            "touch" => touch(&config.touch),
            "exec" => exec_list(&config.exec),
            x => println!("Unknown operation \"{}\"", x),
        }
    }
}

/// Returns the config path for a `lang` parameter.
///
/// This method concatenates $HOME with "/.skeleton/{lang}.toml"
///
/// # Examples
///
/// ```
/// let path = get_config_path(&"rust".to_string())
/// ```
fn get_config_path(lang: &String) -> Option<String> {
    let home = match env::home_dir() {
        Some(p) => p,
        None => return None,
    };
    let config_path_cow = home.to_string_lossy();
    let mut config_path = config_path_cow.into_owned();
    // let mut config_path = env!("HOME").to_string();

    config_path.push_str("/.skeleton/");
    config_path.push_str(lang);
    config_path.push_str(".toml");
    Some(config_path)
}

/// Checks if a directory is empty
///
/// # Examples
///
/// ```
/// let dir_is_empty(&".".to_string());
/// ```
fn dir_is_empty(dir: &String) -> bool {
    let paths = match read_dir(dir) {
        Ok(paths) => paths,
        Err(_) => return false,
    };

    for _ in paths {
        return false;
    }
    true
}

/// Checks if a file exists
fn file_exists(name: &String) -> bool {
    Path::new(&name).exists()
}

/// Executes a command using `sh` or `cmd.exe` depending on the used operating system.
///
/// Returns either a `Error` or a tuple `(stdout, stderr)`
fn exec(cmd: &String) -> Result<(String, String)> {
    #[cfg(unix)]
    let shell = "sh";
    #[cfg(unix)]
    let arg1 = "-c";
    #[cfg(windows)]
    let shell = "cmd.exe";
    #[cfg(windows)]
    let arg1 = "/C";

    let out = Command::new(shell).arg(arg1).arg(cmd).output()?;

    Ok((String::from_utf8(out.stdout).unwrap_or("Could not parse stdout".to_string()),
        String::from_utf8(out.stderr).unwrap_or("Could not parse stderr".to_string())))

}

/// Creates a file if it doesn't exist.
fn create_file(file_name: &String) -> bool {
    !file_exists(&file_name) &&
    OpenOptions::new()
        .append(true)
        .create(true)
        .open(file_name)
        .is_ok()
}

/// Parses a configuration file and returns the `Config` struct.
fn parse_config(file_name: String) -> Result<Config> {
    let file = File::open(file_name)?;
    let mut reader = BufReader::new(file);
    let mut contents = String::new();

    reader.read_to_string(&mut contents)?;

    toml::from_str(&contents).map_err(|err| Error::new(ErrorKind::InvalidInput, err))
}

#[test]
fn test_file_exists() {
    assert!(file_exists(&"test/foo.toml".to_string()));
    assert!(!file_exists(&"test/none".to_string()));
}

#[test]
fn test_parse_config() {
    let conf = parse_config("test/foo.toml".to_string()).unwrap();
    let gi = conf.gitignore.unwrap();
    assert_eq!(gi, vec!["rust".to_string(), "vim".to_string()]);

    let mkd = conf.mkdir.unwrap();
    assert_eq!(mkd, vec!["b".to_string()]);

    let touch = conf.touch.unwrap();
    assert_eq!(touch, vec!["a".to_string()]);

    let exec = conf.exec.unwrap();
    assert_eq!(exec, vec!["touch asdf".to_string()]);
}

#[test]
fn test_exec() {
    let (stdout, stderr) = exec(&"echo test".to_string()).unwrap();
    #[cfg(unix)]
    assert_eq!(stdout, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stdout, "test \r\n".to_string());
    assert_eq!(stderr, "".to_string());
    let (stdout, stderr) = exec(&"echo test 1>&2".to_string()).unwrap();
    assert_eq!(stdout, "".to_string());
    #[cfg(unix)]
    assert_eq!(stderr, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stderr, "test \r\n".to_string());
}

#[test]
fn test_dir_is_empty() {
    let is_empty = dir_is_empty(&"./test".to_string());
    assert!(!is_empty);
    let non_existent = dir_is_empty(&"./non_existent_dir".to_string());
    assert!(!non_existent);
}

#[test]
fn test_get_config_path() {
    let expected = get_config_path(&"foo".to_string()).unwrap();
    let mut actual = env::home_dir().unwrap().to_str().unwrap().to_string();
    actual.push_str("/.skeleton/foo.toml");
    assert_eq!(actual, expected);
}
<|endoftext|>


<commit_before>//! # Triple buffering
//!
//! In this crate, we attempt to implement a triple buffering mechanism,
//! suitable for emulating shared memory cells in a thread-safe and
//! non-blocking fashion between one single writer and one single reader.

use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

/// ## Indexing
///
/// These types are used to index into triple buffers
/// TODO: Switch to i8 / AtomicI8 once the later is stable
type TripleBufferIndex = usize;
type AtomicTripleBufferIndex = AtomicUsize;

/// ## Shared state
///
/// In a triple buffering communication protocol, the reader and writer share
/// the following storage:
///
/// - Three memory buffers suitable for storing the data at hand
/// - One index pointing to the buffer which no one is currently using
/// - One index pointing to the most recently updated buffer
///
#[derive(Debug)]
struct TripleBufferSharedState<T: Clone + PartialEq> {
    /// Three buffers of data
    buffers: [UnsafeCell<T>; 3],

    /// Index of the back-buffer (buffer which no one is currently accessing)
    back_idx: AtomicTripleBufferIndex,

    /// Index of the most recently updated buffer
    last_idx: AtomicTripleBufferIndex,
}
//
impl<T: Clone + PartialEq> Clone for TripleBufferSharedState<T> {
    fn clone(&self) -> Self {
        // The use of UnsafeCell makes buffers somwhat cumbersome to clone...
        let clone_buffer = | i: TripleBufferIndex | {
            UnsafeCell::new(
                unsafe { (*self.buffers[i].get()).clone() }
            )
        };

        // ...so better define a shortcut before we move on to actual cloning
        TripleBufferSharedState {
            buffers: [
                clone_buffer(0),
                clone_buffer(1),
                clone_buffer(2),
            ],
            back_idx: AtomicTripleBufferIndex::new(
                self.back_idx.load(Ordering::Relaxed)
            ),
            last_idx: AtomicTripleBufferIndex::new(
                self.last_idx.load(Ordering::Relaxed)
            ),
        }
    }
}
//
impl<T: Clone + PartialEq> PartialEq for TripleBufferSharedState<T> {
    fn eq(&self, other: &Self) -> bool {
        // The use of UnsafeCell makes buffers somwhat cumbersome to compare...
        let buffer_eq = | i: TripleBufferIndex | -> bool {
            unsafe { *self.buffers[i].get() == *other.buffers[i].get() }
        };

        // ...and atomics aren't much better...
        let atomics_eq = | x: &AtomicTripleBufferIndex,
                           y: &AtomicTripleBufferIndex | -> bool {
            x.load(Ordering::Relaxed) == y.load(Ordering::Relaxed)
        };

        // ...so better define some shortcuts before getting started:
        buffer_eq(0) && buffer_eq(1) && buffer_eq(2) &&
        atomics_eq(&self.back_idx, &other.back_idx) &&
        atomics_eq(&self.last_idx, &other.last_idx)
    }
}
//
unsafe impl<T: Clone + PartialEq> Sync for TripleBufferSharedState<T> {}

/// ## Producing data ("input")
///
/// The producer of data has exclusive write access to the so-called "write
/// buffer". To send an update, it writes it into the back buffer, then swaps
/// the write buffer with the back buffer, making the data readable.
///
#[derive(Debug)]
struct TripleBufferInput<T: Clone + PartialEq> {
    shared: Arc<TripleBufferSharedState<T>>,
    write_idx: TripleBufferIndex,
}
//
impl<T: Clone + PartialEq> TripleBufferInput<T> {
    /// Write a new value into the triple buffer
    fn write(&mut self, value: T) {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Determine which shared buffer is the write buffer
        let active_idx = self.write_idx;

        // Move the input value into the write buffer
        let write_ptr = shared_state.buffers[active_idx].get();
        unsafe { *write_ptr = value; }

        // Swap the back buffer and the write buffer. This makes the new data
        // block available to the reader and gives us a new buffer to write to.
        self.write_idx = shared_state.back_idx.swap(
            active_idx,
            Ordering::Release  // Send previous updates to the reader
        );

        // Notify the reader that we submitted an update
        shared_state.last_idx.store(active_idx, Ordering::Relaxed);
    }
}

/// ## Consuming data ("output")
///
/// The consumer of data has exclusive read access to the so-called "read
/// buffer". To access the latest data, it swaps the read buffer with the
/// back buffer if the later contains more recent data, then reads from
/// the (possibly new) read buffer.
///
#[derive(Debug)]
struct TripleBufferOutput<T: Clone + PartialEq> {
    shared: Arc<TripleBufferSharedState<T>>,
    read_idx: TripleBufferIndex,
}
//
impl<T: Clone + PartialEq> TripleBufferOutput<T> {
    /// Access the latest fully written value from the triple buffer
    fn read(&mut self) -> &T {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Check if the writer has submitted an update
        let last_idx = shared_state.last_idx.load(Ordering::Relaxed);

        // If an update is pending in the back buffer, make it our read buffer
        if self.read_idx != last_idx {
            // Swap the back buffer and the read buffer. We get exclusive read
            // access to the data, and the writer gets a new back buffer.
            self.read_idx = shared_state.back_idx.swap(
                self.read_idx,
                Ordering::Acquire  // Synchronize with the writer's updates
            );
        }

        // Access data from the current read buffer
        let read_ptr = shared_state.buffers[self.read_idx].get();
        unsafe { &*read_ptr }
    }
}

/// ## Triple buffer
///
/// A triple buffer is created as the combination of an input and an output.
///
#[derive(Debug)]
struct TripleBuffer<T: Clone + PartialEq> {
    input: TripleBufferInput<T>,
    output: TripleBufferOutput<T>,
}
//
impl<T: Clone + PartialEq> TripleBuffer<T> {
    /// Construct a triple buffer with a certain initial value
    fn new(initial: T) -> Self {
        // Start with the shared state...
        let shared_state = Arc::new(
            TripleBufferSharedState {
                buffers: [
                    UnsafeCell::new(initial.clone()),
                    UnsafeCell::new(initial.clone()),
                    UnsafeCell::new(initial)
                ],
                back_idx: AtomicTripleBufferIndex::new(0),
                last_idx: AtomicTripleBufferIndex::new(2),
            }
        );

        // ...then construct the input and output structs
        TripleBuffer {
            input: TripleBufferInput {
                shared: shared_state.clone(),
                write_idx: 1,
            },
            output: TripleBufferOutput {
                shared: shared_state,
                read_idx: 2,
            },
        }
    }
}
//
impl<T: Clone + PartialEq> Clone for TripleBuffer<T> {
    fn clone(&self) -> Self {
        // Clone the shared state...
        let shared_state = Arc::new(
            (*self.input.shared).clone()
        );

        // ...then the input and output structs
        TripleBuffer {
            input: TripleBufferInput {
                shared: shared_state.clone(),
                write_idx: self.input.write_idx,
            },
            output: TripleBufferOutput {
                shared: shared_state,
                read_idx: self.output.read_idx,
            },
        }
    }
}
//
impl<T: Clone + PartialEq> PartialEq for TripleBuffer<T> {
    fn eq(&self, other: &Self) -> bool {
        (*self.input.shared == *other.input.shared) &&
        (self.input.write_idx == other.input.write_idx) &&
        (self.output.read_idx == other.output.read_idx)
    }
}

/// ## Testing
///
/// Unit tests and benchmarks for triple buffers
///
#[cfg(test)]
mod tests {
    /// Test that triple buffers are properly initialized
    #[test]
    fn test_init() {
        // Let's create a triple buffer
        let buf = ::TripleBuffer::new(42);

        // Access the shared state
        let ref buf_shared = *buf.input.shared;
        let back_idx = buf_shared.back_idx.load(::Ordering::Relaxed);
        let last_idx = buf_shared.last_idx.load(::Ordering::Relaxed);

        // Write-/read-/back-buffer indexes must be in range
        assert!(index_in_range(buf.input.write_idx));
        assert!(index_in_range(buf.output.read_idx));
        assert!(index_in_range(back_idx));

        // Write-/read-/back-buffer indexes must be distinct
        assert!(buf.input.write_idx != buf.output.read_idx);
        assert!(buf.input.write_idx != back_idx);
        assert!(buf.output.read_idx != back_idx);

        // Read buffer must be properly initialized
        let read_ptr = buf_shared.buffers[buf.output.read_idx].get();
        assert!(unsafe { *read_ptr } == 42);

        // Last-written index must initially point to the read buffer
        assert_eq!(last_idx, buf.output.read_idx);
    }

    /// Test that (sequentially) writing to a triple buffer works
    #[test]
    fn test_seq_write() {
        // Let's create a triple buffer
        let mut buf = ::TripleBuffer::new(false);

        // Back up the initial buffer state
        let old_buf = buf.clone();
        let ref old_shared = old_buf.input.shared;

        // Perform a write
        buf.input.write(true);

        // Check new implementation state
        {
            // Start from the old buffer state
            let mut expected_buf = old_buf.clone();
            let ref expected_shared = expected_buf.input.shared;

            // We expect the former write buffer to have received the new value
            let old_write_idx = old_buf.input.write_idx;
            let write_buf_ptr = expected_shared.buffers[old_write_idx].get();
            unsafe { *write_buf_ptr = true; }

            // We expect the former write buffer to be the new back buffer
            expected_shared.back_idx.store(
                old_write_idx,
                ::Ordering::Relaxed
            );

            // We expect the last updated index to point to former write buffer
            expected_shared.last_idx.store(
                old_write_idx,
                ::Ordering::Relaxed
            );

            // We expect the old back buffer to become the new write buffer
            let old_back_idx = old_shared.back_idx.load(::Ordering::Relaxed);
            expected_buf.input.write_idx = old_back_idx;

            // Nothing else should have changed
            assert_eq!(buf, expected_buf);
        }
    }

    /// Check that (sequentially) reading from a triple buffer works
    #[test]
    fn test_seq_read() {
        // Let's create a triple buffer and write into it
        let mut buf = ::TripleBuffer::new(1.0);
        buf.input.write(4.2);

        // Test readout from dirty (freshly written) triple buffer
        {
            // Back up the initial buffer state
            let old_buf = buf.clone();
            let ref old_shared = old_buf.input.shared;

            // Read from the buffer
            let result = *buf.output.read();

            // Output value should be correct
            assert_eq!(result, 4.2);

            // Start from the old buffer state
            let mut expected_buf = old_buf.clone();
            let ref expected_shared = expected_buf.input.shared;

            // We expect the new back index to point to the former read buffer
            expected_shared.back_idx.store(
                old_buf.output.read_idx,
                ::Ordering::Relaxed
            );

            // We expect the new read index to point to the former back buffer
            let old_back_idx = old_shared.back_idx.load(::Ordering::Relaxed);
            expected_buf.output.read_idx = old_back_idx;

            // Nothing else should have changed
            assert_eq!(buf, expected_buf);
        }

        // Test readout from clean (unchanged) triple buffer
        {
            // Back up the initial buffer state
            let old_buf = buf.clone();

            // Read from the buffer
            let result = *buf.output.read();

            // Output value should be correct
            assert_eq!(result, 4.2);

            // Buffer state should be unchanged
            assert_eq!(buf, old_buf);
        }
    }

    // Check that concurrent reads and writes work
    #[test]
    fn test_conc_access() {
        // We will stress the infrastructure by performing this many writes
        // as a reader continuously reads the latest value
        let test_write_count = 1000;

        // This is the buffer that our reader and writer will share
        let buf = ::TripleBuffer::new(0u64);

        // Let's split it into an input and an output
        let (mut buf_input, mut buf_output) = (buf.input, buf.output);

        // The reader continuously checks the buffered value, and should see
        // every update without any incoherent value
        let reader = ::thread::spawn(move || {
            let mut last_value = 0u64;
            while last_value < test_write_count {
                let new_value = *buf_output.read();
                assert!(
                    (new_value >= last_value) && (new_value-last_value <= 1)
                );
                last_value = new_value;
            }
        });

        // The writer continuously increments the buffered value, with some
        // rate limiting to ensure that the reader can see the updates
        let writer = ::thread::spawn(move || {
            // TODO: Use a barrier here instead
            ::thread::sleep(::Duration::from_millis(1));
            for value in 1 .. test_write_count+1 {
                buf_input.write(value);
                ::thread::yield_now();
                ::thread::sleep(::Duration::from_millis(1));
            }
        });

        // Wait for the reader and writer to finish
        reader.join().unwrap();
        writer.join().unwrap();
    }

    // TODO: Benchmark the performance of concurrent reads and writes

    /// Range check for triple buffer indexes
    #[allow(unused_comparisons)]
    fn index_in_range(idx: ::TripleBufferIndex) -> bool {
        (idx >= 0) & (idx <= 2)
    }
}

fn main() {
    println!("Hello, world!");

    let mut buf = TripleBuffer::new("Hello!");
    println!("Initial value is {}", buf.output.read());

    buf.input.write("World!");
    println!("New value is {}", buf.output.read())
}
<commit_msg>Ran the reader in the main thread instead of an extra thread<commit_after>//! # Triple buffering
//!
//! In this crate, we attempt to implement a triple buffering mechanism,
//! suitable for emulating shared memory cells in a thread-safe and
//! non-blocking fashion between one single writer and one single reader.

use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

/// ## Indexing
///
/// These types are used to index into triple buffers
/// TODO: Switch to i8 / AtomicI8 once the later is stable
type TripleBufferIndex = usize;
type AtomicTripleBufferIndex = AtomicUsize;

/// ## Shared state
///
/// In a triple buffering communication protocol, the reader and writer share
/// the following storage:
///
/// - Three memory buffers suitable for storing the data at hand
/// - One index pointing to the buffer which no one is currently using
/// - One index pointing to the most recently updated buffer
///
#[derive(Debug)]
struct TripleBufferSharedState<T: Clone + PartialEq> {
    /// Three buffers of data
    buffers: [UnsafeCell<T>; 3],

    /// Index of the back-buffer (buffer which no one is currently accessing)
    back_idx: AtomicTripleBufferIndex,

    /// Index of the most recently updated buffer
    last_idx: AtomicTripleBufferIndex,
}
//
impl<T: Clone + PartialEq> Clone for TripleBufferSharedState<T> {
    fn clone(&self) -> Self {
        // The use of UnsafeCell makes buffers somwhat cumbersome to clone...
        let clone_buffer = | i: TripleBufferIndex | {
            UnsafeCell::new(
                unsafe { (*self.buffers[i].get()).clone() }
            )
        };

        // ...so better define a shortcut before we move on to actual cloning
        TripleBufferSharedState {
            buffers: [
                clone_buffer(0),
                clone_buffer(1),
                clone_buffer(2),
            ],
            back_idx: AtomicTripleBufferIndex::new(
                self.back_idx.load(Ordering::Relaxed)
            ),
            last_idx: AtomicTripleBufferIndex::new(
                self.last_idx.load(Ordering::Relaxed)
            ),
        }
    }
}
//
impl<T: Clone + PartialEq> PartialEq for TripleBufferSharedState<T> {
    fn eq(&self, other: &Self) -> bool {
        // The use of UnsafeCell makes buffers somwhat cumbersome to compare...
        let buffer_eq = | i: TripleBufferIndex | -> bool {
            unsafe { *self.buffers[i].get() == *other.buffers[i].get() }
        };

        // ...and atomics aren't much better...
        let atomics_eq = | x: &AtomicTripleBufferIndex,
                           y: &AtomicTripleBufferIndex | -> bool {
            x.load(Ordering::Relaxed) == y.load(Ordering::Relaxed)
        };

        // ...so better define some shortcuts before getting started:
        buffer_eq(0) && buffer_eq(1) && buffer_eq(2) &&
        atomics_eq(&self.back_idx, &other.back_idx) &&
        atomics_eq(&self.last_idx, &other.last_idx)
    }
}
//
unsafe impl<T: Clone + PartialEq> Sync for TripleBufferSharedState<T> {}

/// ## Producing data ("input")
///
/// The producer of data has exclusive write access to the so-called "write
/// buffer". To send an update, it writes it into the back buffer, then swaps
/// the write buffer with the back buffer, making the data readable.
///
#[derive(Debug)]
struct TripleBufferInput<T: Clone + PartialEq> {
    shared: Arc<TripleBufferSharedState<T>>,
    write_idx: TripleBufferIndex,
}
//
impl<T: Clone + PartialEq> TripleBufferInput<T> {
    /// Write a new value into the triple buffer
    fn write(&mut self, value: T) {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Determine which shared buffer is the write buffer
        let active_idx = self.write_idx;

        // Move the input value into the write buffer
        let write_ptr = shared_state.buffers[active_idx].get();
        unsafe { *write_ptr = value; }

        // Swap the back buffer and the write buffer. This makes the new data
        // block available to the reader and gives us a new buffer to write to.
        self.write_idx = shared_state.back_idx.swap(
            active_idx,
            Ordering::Release  // Send previous updates to the reader
        );

        // Notify the reader that we submitted an update
        shared_state.last_idx.store(active_idx, Ordering::Relaxed);
    }
}

/// ## Consuming data ("output")
///
/// The consumer of data has exclusive read access to the so-called "read
/// buffer". To access the latest data, it swaps the read buffer with the
/// back buffer if the later contains more recent data, then reads from
/// the (possibly new) read buffer.
///
#[derive(Debug)]
struct TripleBufferOutput<T: Clone + PartialEq> {
    shared: Arc<TripleBufferSharedState<T>>,
    read_idx: TripleBufferIndex,
}
//
impl<T: Clone + PartialEq> TripleBufferOutput<T> {
    /// Access the latest fully written value from the triple buffer
    fn read(&mut self) -> &T {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Check if the writer has submitted an update
        let last_idx = shared_state.last_idx.load(Ordering::Relaxed);

        // If an update is pending in the back buffer, make it our read buffer
        if self.read_idx != last_idx {
            // Swap the back buffer and the read buffer. We get exclusive read
            // access to the data, and the writer gets a new back buffer.
            self.read_idx = shared_state.back_idx.swap(
                self.read_idx,
                Ordering::Acquire  // Synchronize with the writer's updates
            );
        }

        // Access data from the current read buffer
        let read_ptr = shared_state.buffers[self.read_idx].get();
        unsafe { &*read_ptr }
    }
}

/// ## Triple buffer
///
/// A triple buffer is created as the combination of an input and an output.
///
#[derive(Debug)]
struct TripleBuffer<T: Clone + PartialEq> {
    input: TripleBufferInput<T>,
    output: TripleBufferOutput<T>,
}
//
impl<T: Clone + PartialEq> TripleBuffer<T> {
    /// Construct a triple buffer with a certain initial value
    fn new(initial: T) -> Self {
        // Start with the shared state...
        let shared_state = Arc::new(
            TripleBufferSharedState {
                buffers: [
                    UnsafeCell::new(initial.clone()),
                    UnsafeCell::new(initial.clone()),
                    UnsafeCell::new(initial)
                ],
                back_idx: AtomicTripleBufferIndex::new(0),
                last_idx: AtomicTripleBufferIndex::new(2),
            }
        );

        // ...then construct the input and output structs
        TripleBuffer {
            input: TripleBufferInput {
                shared: shared_state.clone(),
                write_idx: 1,
            },
            output: TripleBufferOutput {
                shared: shared_state,
                read_idx: 2,
            },
        }
    }
}
//
impl<T: Clone + PartialEq> Clone for TripleBuffer<T> {
    fn clone(&self) -> Self {
        // Clone the shared state...
        let shared_state = Arc::new(
            (*self.input.shared).clone()
        );

        // ...then the input and output structs
        TripleBuffer {
            input: TripleBufferInput {
                shared: shared_state.clone(),
                write_idx: self.input.write_idx,
            },
            output: TripleBufferOutput {
                shared: shared_state,
                read_idx: self.output.read_idx,
            },
        }
    }
}
//
impl<T: Clone + PartialEq> PartialEq for TripleBuffer<T> {
    fn eq(&self, other: &Self) -> bool {
        (*self.input.shared == *other.input.shared) &&
        (self.input.write_idx == other.input.write_idx) &&
        (self.output.read_idx == other.output.read_idx)
    }
}

/// ## Testing
///
/// Unit tests and benchmarks for triple buffers
///
#[cfg(test)]
mod tests {
    /// Test that triple buffers are properly initialized
    #[test]
    fn test_init() {
        // Let's create a triple buffer
        let buf = ::TripleBuffer::new(42);

        // Access the shared state
        let ref buf_shared = *buf.input.shared;
        let back_idx = buf_shared.back_idx.load(::Ordering::Relaxed);
        let last_idx = buf_shared.last_idx.load(::Ordering::Relaxed);

        // Write-/read-/back-buffer indexes must be in range
        assert!(index_in_range(buf.input.write_idx));
        assert!(index_in_range(buf.output.read_idx));
        assert!(index_in_range(back_idx));

        // Write-/read-/back-buffer indexes must be distinct
        assert!(buf.input.write_idx != buf.output.read_idx);
        assert!(buf.input.write_idx != back_idx);
        assert!(buf.output.read_idx != back_idx);

        // Read buffer must be properly initialized
        let read_ptr = buf_shared.buffers[buf.output.read_idx].get();
        assert!(unsafe { *read_ptr } == 42);

        // Last-written index must initially point to the read buffer
        assert_eq!(last_idx, buf.output.read_idx);
    }

    /// Test that (sequentially) writing to a triple buffer works
    #[test]
    fn test_seq_write() {
        // Let's create a triple buffer
        let mut buf = ::TripleBuffer::new(false);

        // Back up the initial buffer state
        let old_buf = buf.clone();
        let ref old_shared = old_buf.input.shared;

        // Perform a write
        buf.input.write(true);

        // Check new implementation state
        {
            // Start from the old buffer state
            let mut expected_buf = old_buf.clone();
            let ref expected_shared = expected_buf.input.shared;

            // We expect the former write buffer to have received the new value
            let old_write_idx = old_buf.input.write_idx;
            let write_buf_ptr = expected_shared.buffers[old_write_idx].get();
            unsafe { *write_buf_ptr = true; }

            // We expect the former write buffer to be the new back buffer
            expected_shared.back_idx.store(
                old_write_idx,
                ::Ordering::Relaxed
            );

            // We expect the last updated index to point to former write buffer
            expected_shared.last_idx.store(
                old_write_idx,
                ::Ordering::Relaxed
            );

            // We expect the old back buffer to become the new write buffer
            let old_back_idx = old_shared.back_idx.load(::Ordering::Relaxed);
            expected_buf.input.write_idx = old_back_idx;

            // Nothing else should have changed
            assert_eq!(buf, expected_buf);
        }
    }

    /// Check that (sequentially) reading from a triple buffer works
    #[test]
    fn test_seq_read() {
        // Let's create a triple buffer and write into it
        let mut buf = ::TripleBuffer::new(1.0);
        buf.input.write(4.2);

        // Test readout from dirty (freshly written) triple buffer
        {
            // Back up the initial buffer state
            let old_buf = buf.clone();
            let ref old_shared = old_buf.input.shared;

            // Read from the buffer
            let result = *buf.output.read();

            // Output value should be correct
            assert_eq!(result, 4.2);

            // Start from the old buffer state
            let mut expected_buf = old_buf.clone();
            let ref expected_shared = expected_buf.input.shared;

            // We expect the new back index to point to the former read buffer
            expected_shared.back_idx.store(
                old_buf.output.read_idx,
                ::Ordering::Relaxed
            );

            // We expect the new read index to point to the former back buffer
            let old_back_idx = old_shared.back_idx.load(::Ordering::Relaxed);
            expected_buf.output.read_idx = old_back_idx;

            // Nothing else should have changed
            assert_eq!(buf, expected_buf);
        }

        // Test readout from clean (unchanged) triple buffer
        {
            // Back up the initial buffer state
            let old_buf = buf.clone();

            // Read from the buffer
            let result = *buf.output.read();

            // Output value should be correct
            assert_eq!(result, 4.2);

            // Buffer state should be unchanged
            assert_eq!(buf, old_buf);
        }
    }

    // Check that concurrent reads and writes work
    #[test]
    fn test_conc_access() {
        // We will stress the infrastructure by performing this many writes
        // as a reader continuously reads the latest value
        let test_write_count = 1000;

        // This is the buffer that our reader and writer will share
        let mut buf = ::TripleBuffer::new(0u64);

        // Extract the input stage so that we can send it to the writer
        let mut buf_input = buf.input;

        // The writer continuously increments the buffered value, with some
        // rate limiting to ensure that the reader can see the updates
        let writer = ::thread::spawn(move || {
            // TODO: Use a barrier here instead
            for value in 1 .. test_write_count+1 {
                buf_input.write(value);
                ::thread::yield_now();
                ::thread::sleep(::Duration::from_millis(1));
            }
        });

        // The reader continuously checks the buffered value, and should see
        // every update without any incoherent value
        let mut last_value = 0u64;
        while last_value < test_write_count {
            let new_value = *buf.output.read();
            assert!(
                (new_value >= last_value) && (new_value-last_value <= 1)
            );
            last_value = new_value;
        }

        // Wait for the writer to finish
        writer.join().unwrap();
    }

    // TODO: Benchmark the performance of concurrent reads and writes

    /// Range check for triple buffer indexes
    #[allow(unused_comparisons)]
    fn index_in_range(idx: ::TripleBufferIndex) -> bool {
        (idx >= 0) & (idx <= 2)
    }
}

fn main() {
    println!("Hello, world!");

    let mut buf = TripleBuffer::new("Hello!");
    println!("Initial value is {}", buf.output.read());

    buf.input.write("World!");
    println!("New value is {}", buf.output.read())
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"] // error_chain

extern crate websocket;
extern crate env_logger;
#[macro_use]
extern crate log;
#[macro_use]
extern crate error_chain;
extern crate url;
extern crate clap;

use std::thread;
use std::io::{stdin,stdout};

use websocket::{Message, Sender, Receiver, DataFrame};
use websocket::message::Type;
use websocket::client::request::Url;
use websocket::Client;

use std::borrow::Borrow;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write};

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Log(log::SetLoggerError);
        Url(::url::ParseError);
        Ws(::websocket::result::WebSocketError);
        VarError(::std::env::VarError);
        RE(std::sync::mpsc::RecvError);
    }
}

// Initialize logger with default "info" log level:
fn init_logger() -> Result<()> {
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(None, log::LogLevelFilter::Info);
    if ::std::env::var("RUST_LOG").is_ok() {
       builder.parse(&::std::env::var("RUST_LOG")?);
    }
    builder.init()?;
    Ok(())
}

struct SenderWrapper<T: Sender> (T);

impl<T: Sender> ::std::io::Write for SenderWrapper<T> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        let message = Message::binary(buf);
        let ret;
        let len = buf.len();
        if len > 0 {
            debug!("Sending message of {} bytes", len);
            ret = self.0.send_message(&message);
        } else {
            // Interpret zero length buffer is request
            // to close communication

            debug!("Sending the closing message");
            ret = self.0.send_message(&Message::close());
        }
        ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;
        Ok(len)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        Ok(())
    }
}

struct ReceiverWrapper<T: Receiver<DataFrame>> (T);

impl<T:Receiver<DataFrame>> ::std::io::Read for ReceiverWrapper<T> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let ret = self.0.recv_message();
        let msg : Message = ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;

        match msg.opcode {
            Type::Close => {
                Ok(0)
            }
            Type::Ping => {
                unimplemented!();
            }
            _ => {
                let msgpayload : &[u8] = msg.payload.borrow();
                let len = msgpayload.len();
                debug!("Received message of {} bytes", len);

                assert!(buf.len() >= len);

                buf[0..len].clone_from_slice(msgpayload);

                Ok(len)
            }
        }
    }
}

fn try_main() -> Result<()> {
    //env_logger::init()?;
    init_logger()?;

    // setup command line arguments
    let matches = ::clap::App::new("WS Command Line Client")
        .version("0.1")
        .author("Vitaly \"_Vi\" Shukela <vi0oss@gmail.com>")
        .about("Send binary data from stdin to a WebSocket and back to stdout.")
        .arg(::clap::Arg::with_name("URL")
             .help("The URL of the WebSocket server.")
             .required(true)
             .index(1)).get_matches();

    let url = Url::parse(matches.value_of("URL").ok_or("no URL")?)?;

    info!("Connecting to {}", url);

    let request = Client::connect(url)?;

    let response = request.send()?; // Send the request and retrieve a response

    info!("Validating response...");

    response.validate()?; // Validate the response

    info!("Successfully connected");

    let (sender, receiver) = response.begin().split();
    let mut writer1 = SenderWrapper(sender);
    let mut reader1 = ReceiverWrapper(receiver);
    let mut writer2 = stdout();
    let mut reader2 = stdin();

    let receive_loop = thread::spawn(move || -> Result<()> {
        // Actual data transfer happens here
        ::std::io::copy(&mut reader1, &mut writer2)?;
        writer2.write(b"")?;
        Ok(())
    });

    // Actual data transfer happens here
    ::std::io::copy(&mut reader2, &mut writer1)?;
    writer1.write(b"")?; // Signal close

    info!("Waiting for child threads to exit");

    if let Err(x) = receive_loop.join() {
        error!("Receiver loop delayed error: {:?}", x);
    }

    info!("Exited");
    Ok(())
}

fn main() {
    if let Err(x) = try_main() {
        let _ = writeln!(::std::io::stderr(), "{:?}", x);
    }
}

<commit_msg>Further refactor: DataExchangeSession<commit_after>#![recursion_limit = "1024"] // error_chain

extern crate websocket;
extern crate env_logger;
#[macro_use]
extern crate log;
#[macro_use]
extern crate error_chain;
extern crate url;
extern crate clap;

use std::thread;
use std::io::{stdin,stdout};

use websocket::{Message, Sender, Receiver, DataFrame};
use websocket::message::Type;
use websocket::client::request::Url;
use websocket::Client;

use std::borrow::Borrow;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Write, Read};

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Log(log::SetLoggerError);
        Url(::url::ParseError);
        Ws(::websocket::result::WebSocketError);
        VarError(::std::env::VarError);
        RE(std::sync::mpsc::RecvError);
    }
}

// Initialize logger with default "info" log level:
fn init_logger() -> Result<()> {
    let mut builder = env_logger::LogBuilder::new();
    builder.filter(None, log::LogLevelFilter::Info);
    if ::std::env::var("RUST_LOG").is_ok() {
       builder.parse(&::std::env::var("RUST_LOG")?);
    }
    builder.init()?;
    Ok(())
}

struct SenderWrapper<T: Sender> (T);

impl<T: Sender> ::std::io::Write for SenderWrapper<T> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        let message = Message::binary(buf);
        let ret;
        let len = buf.len();
        if len > 0 {
            debug!("Sending message of {} bytes", len);
            ret = self.0.send_message(&message);
        } else {
            // Interpret zero length buffer is request
            // to close communication

            debug!("Sending the closing message");
            ret = self.0.send_message(&Message::close());
        }
        ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;
        Ok(len)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        Ok(())
    }
}

struct ReceiverWrapper<T: Receiver<DataFrame>> (T);

impl<T:Receiver<DataFrame>> ::std::io::Read for ReceiverWrapper<T> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let ret = self.0.recv_message();
        let msg : Message = ret.map_err(|e|IoError::new(IoErrorKind::BrokenPipe, e))?;

        match msg.opcode {
            Type::Close => {
                Ok(0)
            }
            Type::Ping => {
                unimplemented!();
            }
            _ => {
                let msgpayload : &[u8] = msg.payload.borrow();
                let len = msgpayload.len();
                debug!("Received message of {} bytes", len);

                assert!(buf.len() >= len);

                buf[0..len].clone_from_slice(msgpayload);

                Ok(len)
            }
        }
    }
}

struct DataExchangeSession<R1,R2,W1,W2>
    where R1 : Read + Send, R2: Read + Send, W1: Write + Send, W2: Write + Send
{
    reader1 : R1,
    writer1 : W1,
    reader2 : R2,
    writer2 : W2,
}

impl<R1,R2,W1,W2> DataExchangeSession<R1,R2,W1,W2>
    where R1 : Read + Send + 'static, R2: Read + Send, W1: Write + Send, W2: Write + Send + 'static
{
    fn data_exchange(self) -> Result<()> {

        let mut reader1 = self.reader1;
        let mut writer1 = self.writer1;
        let mut reader2 = self.reader2;
        let mut writer2 = self.writer2;

        let receive_loop = thread::spawn(move || -> Result<()> {
            // Actual data transfer happens here
            ::std::io::copy(&mut reader1, &mut writer2)?;
            writer2.write(b"")?;
            Ok(())
        });

        // Actual data transfer happens here
        ::std::io::copy(&mut reader2, &mut writer1)?;
        writer1.write(b"")?; // Signal close

        info!("Waiting for child threads to exit");

        receive_loop.join().map_err(|x|format!("{:?}",x))?
    }
}

fn try_main() -> Result<()> {
    //env_logger::init()?;
    init_logger()?;

    // setup command line arguments
    let matches = ::clap::App::new("WS Command Line Client")
        .version("0.1")
        .author("Vitaly \"_Vi\" Shukela <vi0oss@gmail.com>")
        .about("Send binary data from stdin to a WebSocket and back to stdout.")
        .arg(::clap::Arg::with_name("URL")
             .help("The URL of the WebSocket server.")
             .required(true)
             .index(1)).get_matches();

    let url = Url::parse(matches.value_of("URL").ok_or("no URL")?)?;

    info!("Connecting to {}", url);

    let request = Client::connect(url)?;

    let response = request.send()?; // Send the request and retrieve a response

    info!("Validating response...");

    response.validate()?; // Validate the response

    info!("Successfully connected");

    let (sender, receiver) = response.begin().split();

    let des = DataExchangeSession {
        writer1 : SenderWrapper(sender),
        reader1 : ReceiverWrapper(receiver),
        writer2 : stdout(),
        reader2 : stdin(),
    };

    des.data_exchange()?;

    info!("Exited");
    Ok(())
}

fn main() {
    if let Err(x) = try_main() {
        let _ = writeln!(::std::io::stderr(), "{:?}", x);
    }
}

<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log {:?}: {}", log_type, string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: *const Size, new_size_ptr: *const Size) {
    unsafe {
        println!("output_resolution: {:?} from  {:?} to {:?}",
                 output, &*old_size_ptr, &*new_size_ptr);
    }
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: *const Geometry) {
    unsafe {
        println!("view_request_geometry: {:?} wants {:?}", view, &*geometry);
        view.set_geometry(0, geometry);
        render_output(view.get_output());
    }
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: *const Point) {
    //println!("view_request_move: to {}, start interactive mode.", &*dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: *const Point) {
    unsafe {
        println!("view_request_resize: size {:?}, to {}, start interactive mode.",
                 edge, &*location);
    }
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    unsafe {
        use std::process::{Command};
        println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
                 time, &*mods_ptr, key, state);
        if state == KeyState::Pressed { return false; }
        if key == 67 {
            println!("Preparing to open the terminal...");
            rustwlc::exec("/bin/weston-terminal".to_string(),
                          vec!["/bin/weston-terminal".to_string()]);
        }
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: *const Point) -> bool {
    unsafe {
        println!("pointer_button: pressed {} at {}", key, &*point_ptr);
        if state == ButtonState::Pressed {
            view.focus();
        }
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: *const KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point_ptr: *const Point) {
    unsafe { pointer::set_position(&*point_ptr); }
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: *const KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: *const Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: *const LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: *const LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Updated Way-Cooler to use new development branch of rust-wlc. No more unsafe code needed here (except for callback, will change). Only Rust data structures used now, no more raw pointers<commit_after>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log {:?}: {}", log_type, string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    println!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    println!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(0, geometry);
    render_output(view.get_output());
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: &Point) {
    //println!("view_request_move: to {}, start interactive mode.", *dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: &Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, *location);
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    use std::process::{Command};
    println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
             time, *mods_ptr, key, state);
    if state == KeyState::Pressed { return false; }
    if key == 67 {
        println!("Preparing to open the terminal...");
        rustwlc::exec("/bin/weston-terminal".to_string(),
                      vec!["/bin/weston-terminal".to_string()]);
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: &Point) -> bool {
    println!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: &Point) {
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: &LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: &LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>