<commit_before>#[macro_use]
extern crate nom;

use std::str;
use nom::{
    IResult,
    ErrorKind,
    is_hex_digit
};

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}
fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}
fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}
fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

fn main() {
    assert_eq!(pn_chars_base("a%2Ab")  , IResult::Done("%2Ab" , "a")      );
    assert_eq!(pn_chars_u("_a")        , IResult::Done("a"    , "_")      );
    assert_eq!(pn_chars("-_a")         , IResult::Done("_a"   , "-")      );
    assert_eq!(pn_chars(":a2Ab")       , IResult::Error(ErrorKind::Verify));
    assert_eq!(pn_prefix("hog.e:")     , IResult::Done(":"    , "hog.e")  );
    assert_eq!(pn_prefix("hoge.:")     , IResult::Error(ErrorKind::Verify));
    assert_eq!(plx("%2Abc")            , IResult::Done("bc"   , "%2A")    );
    assert_eq!(plx("\\.%2A")           , IResult::Done("%2A"  , "\\.")    );
    assert_eq!(percent("%2Abc")        , IResult::Done("bc"   , "%2A")    );
    assert_eq!(pn_local_esc("\\.a b c"), IResult::Done("a b c", "\\.")    );
}
<commit_msg>Implement PN_LOCAL<commit_after>#[macro_use]
extern crate nom;

use std::str;
use nom::{
    IResult,
    ErrorKind,
    is_hex_digit
};

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}

fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

fn is_pn_local(c: char) -> bool {
    is_pn_chars(c) || c == '.' || c == ':' // TODO: use is_plx
}
/* [168s] PN_LOCAL */
named!(pn_local<&str, &str>, verify!(
    take_while_s!(is_pn_local),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_u(c) || c == ':' // TODO: use is_plx
            } else if idx == len - 1 {
                is_pn_chars(c) || c == ':' // TODO: use is_plx
            } else {
                is_pn_chars(c) || c == ':' || c == '.' // TODO: use is_plx
            }
        })
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

fn main() {
    assert_eq!(pn_chars_base("a%2Ab")    , IResult::Done("%2Ab", "a")         );
    assert_eq!(pn_chars_u("_a")          , IResult::Done("a"   , "_")         );
    assert_eq!(pn_chars("-_a")           , IResult::Done("_a"  , "-")         );
    assert_eq!(pn_chars(":a2Ab")         , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_prefix("hog.e:")       , IResult::Done(":", "hog.e")        );
    assert_eq!(pn_prefix("hoge.:")       , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:fuga piyo"), IResult::Done(" piyo", "hoge:fuga"));
    assert_eq!(plx("%2Abc")              , IResult::Done("bc"   , "%2A")      );
    assert_eq!(plx("\\.%2A")             , IResult::Done("%2A"  , "\\.")      );
    assert_eq!(percent("%2Abc")          , IResult::Done("bc"   , "%2A")      );
    assert_eq!(pn_local_esc("\\.a b c")  , IResult::Done("a b c", "\\.")      );
}
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate debug;

extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use std::os;

use graphics::*;
use opengl_graphics::Gl;
use piston::*;
use sdl2_game_window::GameWindowSDL2;

use lightsout::{StructLevel, Level};

mod lightsout;

fn cmd_main() {
	let sx:Option<uint> = from_str(os::args()[1].as_slice());
	let sx:uint = match sx {
		Some(x) => x,
		None => 4
	};
	let sy:Option<uint> = from_str(os::args()[2].as_slice());
	let sy:uint = match sy {
		Some(y) => y,
		None => 4
	};
	let mut l:StructLevel = Level::new(sx, sy);
	println!("{}", l);
	println!("solved: {}", l.is_solved());

	let sol = lightsout::solve(&mut l);

	println!("{}", sol);
}

struct Env {
	mousex: f64,
	mousey: f64,
	window_width: f64,
	window_height: f64,
}

#[inline(always)]
fn pt_in_rect(px:f64, py:f64, rx: f64, ry:f64, w:f64, h:f64) -> bool {
	px >= rx && px <= rx + w && py >= ry && py <= ry + h
}

fn clear_board(sx: uint, sy: uint, c: &Context, gl: &mut Gl) {
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	c.rect(0.0, 0.0, margin + (margin + w) * (sx as f64) + 1.0, margin + (margin + h) * (sy as f64) + 1.0)
		.rgb(0.0, 0.0, 0.0).draw(gl);
}

fn render_level(level: &Level, env: &Env, c: &Context, gl: &mut Gl) {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	for y in range(0, sy) {
		for x in range(0, sx) {
			let cx = margin + (margin + w) * (x as f64);
			let cy = margin + (margin + h) * (y as f64);
			if pt_in_rect(env.mousex, env.mousey, cx, cy, w, h) {
				c.rect(cx-1.0, cy-1.0, w+2.0, h+2.0).rgb(1.0, 1.0, 0.0).draw(gl);
			}
			let c = c.rect(cx, cy, w, h);
			if level.get(x, y).unwrap() == 0 {
				c.rgb(0.4, 0.4, 0.4)
			} else {
				c.rgb(0.8, 0.8, 0.8)
			}.draw(gl);
		}
	}
}

fn mouse_to_level(level: &Level, mx: f64, my: f64) -> Option<(uint, uint)> {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	if !pt_in_rect(mx, my,
		       margin, margin,
		       margin + (w + margin) * sx as f64, margin + (h + margin) * sy as f64) {
		return None
	}

	let lx = (mx - margin) / (margin + w);
	let ly = (my - margin) / (margin + h);
	println!("lx={} ly={}", lx, ly);
	let ulx = lx as uint;
	let uly = ly as uint;
	let sx = margin + (margin + w) * (ulx as f64);
	let sy = margin + (margin + h) * (uly as f64);
	if pt_in_rect(mx, my, sx, sy, w, h) {
		Some((ulx, uly))
	} else {
		None
	}
}

fn make_ai_move(level: &mut StructLevel) {
	let sol = lightsout::solve(level);
	println!("solution: {}", sol);
	match sol {
		Some(moves) => {
			if moves.len() > 0 {
				let move = moves[0];
				let (mx, my) = move;
				level.make_move(mx, my);
			}
		},
		None => {}
	};
}

fn main() {
	let mut window = GameWindowSDL2::new(
		GameWindowSettings {
			title: "Rust Lights Out".to_string(),
			size: [800u32, 600u32],
			fullscreen: false,
			exit_on_esc: true,
		}
	);
	println!("window: {:?}", window);

	let game_iter_settings = GameIteratorSettings {
		updates_per_second: 120,
		max_frames_per_second: 60,
	};

	let ref mut gl = Gl::new();
	let mut level:StructLevel = Level::new(5, 5);

	let mut env = Env {
		mousex: 0f64,
		mousey: 0f64,
		window_width: window.get_settings().size[0] as f64,
		window_height: window.get_settings().size[1] as f64,
	};

	level.make_move(2, 2);

	for event in GameIterator::new(&mut window, &game_iter_settings) {
		match event {
			Render(args) => {
				gl.viewport(0, 0, args.width as i32, args.height as i32);
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rgb(1.0, 0.0, 0.0)
					.rect(0.0, 0.0, 100.0, 100.0)
					.draw(gl);
				clear_board(9, 9, &c, gl);
				render_level(&level, &env, &c, gl);
			},
			MouseMove(args) => {
				env.mousex = args.x;
				env.mousey = args.y;
			},
			MousePress(args) => {
				println!("{:?} {:?}", args, env);
				match mouse_to_level(&level, env.mousex, env.mousey) {
					Some((x, y)) => { level.make_move(x, y); },
					_ => {}
				}
			},
			KeyPress(args) => {
				println!("{:?} {:?}", args, env);
				match args.key {
					keyboard::Space => make_ai_move(&mut level),
					keyboard::Left
					| keyboard::Right
					| keyboard::Up
					| keyboard::Down => {
						let change_level_size = |dx: uint, dy: uint| {
							let (sx, sy) = level.size();
							if sx + dx > 1 && sy + dy > 1
									&& sx + dx < 10 && sy + dy < 10 {
								level = Level::new(sx + dx, sy + dy);
								println!("new level: {}", level);
							}
						};
						match args.key {
							keyboard::Up => change_level_size(0, -1),
							keyboard::Right => change_level_size(1, 0),
							keyboard::Down => change_level_size(0, 1),
							keyboard::Left => change_level_size(-1, 0),
							_ => {},
						};
					},
					_ => {}
				}
			},
			_ => {}
		}
	}
}
<commit_msg>keyboard 1 and 2 disable/enable a single light<commit_after>#![feature(globs)]
extern crate debug;

extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use std::os;

use graphics::*;
use opengl_graphics::Gl;
use piston::*;
use sdl2_game_window::GameWindowSDL2;

use lightsout::{StructLevel, Level};

mod lightsout;

fn cmd_main() {
	let sx:Option<uint> = from_str(os::args()[1].as_slice());
	let sx:uint = match sx {
		Some(x) => x,
		None => 4
	};
	let sy:Option<uint> = from_str(os::args()[2].as_slice());
	let sy:uint = match sy {
		Some(y) => y,
		None => 4
	};
	let mut l:StructLevel = Level::new(sx, sy);
	println!("{}", l);
	println!("solved: {}", l.is_solved());

	let sol = lightsout::solve(&mut l);

	println!("{}", sol);
}

struct Env {
	mousex: f64,
	mousey: f64,
	window_width: f64,
	window_height: f64,
}

#[inline(always)]
fn pt_in_rect(px:f64, py:f64, rx: f64, ry:f64, w:f64, h:f64) -> bool {
	px >= rx && px <= rx + w && py >= ry && py <= ry + h
}

fn clear_board(sx: uint, sy: uint, c: &Context, gl: &mut Gl) {
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	c.rect(0.0, 0.0, margin + (margin + w) * (sx as f64) + 1.0, margin + (margin + h) * (sy as f64) + 1.0)
		.rgb(0.0, 0.0, 0.0).draw(gl);
}

fn render_level(level: &Level, env: &Env, c: &Context, gl: &mut Gl) {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	for y in range(0, sy) {
		for x in range(0, sx) {
			let cx = margin + (margin + w) * (x as f64);
			let cy = margin + (margin + h) * (y as f64);
			if pt_in_rect(env.mousex, env.mousey, cx, cy, w, h) {
				c.rect(cx-1.0, cy-1.0, w+2.0, h+2.0).rgb(1.0, 1.0, 0.0).draw(gl);
			}
			let c = c.rect(cx, cy, w, h);
			if level.get(x, y).unwrap() == 0 {
				c.rgb(0.4, 0.4, 0.4)
			} else {
				c.rgb(0.8, 0.8, 0.8)
			}.draw(gl);
		}
	}
}

fn mouse_to_level(level: &Level, mx: f64, my: f64) -> Option<(uint, uint)> {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	if !pt_in_rect(mx, my,
		       margin, margin,
		       margin + (w + margin) * sx as f64, margin + (h + margin) * sy as f64) {
		return None
	}

	let lx = (mx - margin) / (margin + w);
	let ly = (my - margin) / (margin + h);
	println!("lx={} ly={}", lx, ly);
	let ulx = lx as uint;
	let uly = ly as uint;
	let sx = margin + (margin + w) * (ulx as f64);
	let sy = margin + (margin + h) * (uly as f64);
	if pt_in_rect(mx, my, sx, sy, w, h) {
		Some((ulx, uly))
	} else {
		None
	}
}

fn make_ai_move(level: &mut StructLevel) {
	let sol = lightsout::solve(level);
	println!("solution: {}", sol);
	match sol {
		Some(moves) => {
			if moves.len() > 0 {
				let move = moves[0];
				let (mx, my) = move;
				level.make_move(mx, my);
			}
		},
		None => {}
	};
}

fn main() {
	let mut window = GameWindowSDL2::new(
		GameWindowSettings {
			title: "Rust Lights Out".to_string(),
			size: [800u32, 600u32],
			fullscreen: false,
			exit_on_esc: true,
		}
	);
	println!("window: {:?}", window);

	let game_iter_settings = GameIteratorSettings {
		updates_per_second: 120,
		max_frames_per_second: 60,
	};

	let ref mut gl = Gl::new();
	let mut level:StructLevel = Level::new(5, 5);

	let mut env = Env {
		mousex: 0f64,
		mousey: 0f64,
		window_width: window.get_settings().size[0] as f64,
		window_height: window.get_settings().size[1] as f64,
	};

	level.make_move(2, 2);

	for event in GameIterator::new(&mut window, &game_iter_settings) {
		match event {
			Render(args) => {
				gl.viewport(0, 0, args.width as i32, args.height as i32);
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rgb(1.0, 0.0, 0.0)
					.rect(0.0, 0.0, 100.0, 100.0)
					.draw(gl);
				clear_board(9, 9, &c, gl);
				render_level(&level, &env, &c, gl);
			},
			MouseMove(args) => {
				env.mousex = args.x;
				env.mousey = args.y;
			},
			MousePress(args) => {
				println!("{:?} {:?}", args, env);
				match mouse_to_level(&level, env.mousex, env.mousey) {
					Some((x, y)) => { level.make_move(x, y); },
					_ => {}
				}
			},
			KeyPress(args) => {
				println!("{:?} {:?}", args, env);
				match args.key {
					keyboard::Space => make_ai_move(&mut level),
					keyboard::Left
					| keyboard::Right
					| keyboard::Up
					| keyboard::Down => {
						let change_level_size = |dx: uint, dy: uint| {
							let (sx, sy) = level.size();
							if sx + dx > 1 && sy + dy > 1
									&& sx + dx < 10 && sy + dy < 10 {
								level = Level::new(sx + dx, sy + dy);
								println!("new level: {}", level);
							}
						};
						match args.key {
							keyboard::Up => change_level_size(0, -1),
							keyboard::Right => change_level_size(1, 0),
							keyboard::Down => change_level_size(0, 1),
							keyboard::Left => change_level_size(-1, 0),
							_ => {},
						};
					},
					keyboard::D1 => match mouse_to_level(&level, env.mousex, env.mousey) {
						Some((x, y)) => { level.set(x, y, 0); },
						_ => {},
					},
					keyboard::D2 => match mouse_to_level(&level, env.mousex, env.mousey) {
						Some((x, y)) => { level.set(x, y, 1); },
						_ => {},
					},
					_ => {}
				}
			},
			_ => {}
		}
	}
}
<|endoftext|>


<commit_before>//! Helpers for writing Alfred script filter JSON output (Alfred 3)
//!
//! # Examples
//!
//! ### Writing items
//!
//! ```
//! # extern crate alfred;
//! # use std::io::{self, Write};
//! #
//! # fn write_items() -> io::Result<()> {
//! alfred::json::write_items(io::stdout(), &[
//!     alfred::Item::new("Item 1"),
//!     alfred::ItemBuilder::new("Item 2")
//!                         .subtitle("Subtitle")
//!                         .into_item(),
//!     alfred::ItemBuilder::new("Item 3")
//!                         .arg("Argument")
//!                         .subtitle("Subtitle")
//!                         .icon_filetype("public.folder")
//!                         .into_item()
//! ])
//! # }
//! #
//! # fn main() {
//! #     match write_items() {
//! #         Ok(()) => {},
//! #         Err(err) => {
//! #             let _ = writeln!(&mut io::stderr(), "Error writing items: {}", err);
//! #         }
//! #     }
//! # }
//! ```
//!
//! ### Writing items with variables
//!
//! ```
//! # extern crate alfred;
//! # use alfred::Modifier;
//! # use std::io::{self, Write};
//! #
//! # fn write_items() -> io::Result<()> {
//! alfred::json::Builder::with_items(&[
//!     alfred::Item::new("Item 1"),
//!     alfred::ItemBuilder::new("Item 2")
//!                         .subtitle("Subtitle")
//!                         .variable("fruit", "banana")
//!                         .into_item(),
//!     alfred::ItemBuilder::new("Item 3")
//!                         .arg("Argument")
//!                         .subtitle("Subtitle")
//!                         .icon_filetype("public.folder")
//!                         .arg_mod(Modifier::Option, "Alt Argument")
//!                         .variable_mod(Modifier::Option, "vegetable", "carrot")
//!                         .into_item()
//! ]).variable("fruit", "banana")
//!   .variable("vegetable", "carrot")
//!   .write(io::stdout())
//! # }
//! #
//! # fn main() {
//! #     match write_items() {
//! #         Ok(()) => {},
//! #         Err(err) => {
//! #             let _ = writeln!(&mut io::stderr(), "Error writing items: {}", err);
//! #         }
//! #     }
//! # }
//! ```

use ::{Item, ItemType, Modifier, Icon, ModifierData};
use serde_json as json;
use serde_json::value::Value;
use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

/// Writes a complete JSON document representing the `Item`s to the `Write`.
///
/// The `Write` is flushed after the JSON document is written.
pub fn write_items<W: Write>(w: W, items: &[Item]) -> io::Result<()> {
    Builder::with_items(items).write(w)
}

/// A helper type for writing out items with top-level variables.
///
/// Note: If you don't need top-level variables the `write_items()` function is easier to use.
#[derive(Clone,Debug,Default)]
pub struct Builder<'a> {
    /// The items that will be written out.
    pub items: &'a [Item<'a>],
    /// The variables that will be written out.
    pub variables: HashMap<&'a str, &'a str>
}

impl<'a> Builder<'a> {
    /// Returns a new `Builder` with no items.
    pub fn new() -> Builder<'a> {
        Builder { items: &[], variables: HashMap::new() }
    }

    /// Returns a new `Builder` with the given items.
    pub fn with_items(items: &'a [Item]) -> Builder<'a> {
        Builder { items, variables: HashMap::new() }
    }

    /// Writes a complete JSON document representing the items and variables to the `Write`.
    ///
    /// The `Write` is flushed after the JSON document is written.
    pub fn write<W: Write>(self, mut w: W) -> io::Result<()> {
        write!(&mut w, "{}", self.into_json())?;
        w.flush()
    }

    fn into_json(self) -> Value {
        let mut root = json::Map::new();
        // We know for a fact that our implementation of ToJson cannot return an error.
        root.insert("items".to_string(), Value::Array(self.items.into_iter()
                                                                .map(|x| x.to_json())
                                                                .collect()));
        let mut iter = self.variables.into_iter();
        if let Some(first) = iter.next() {
            let mut vars = json::Map::new();
            vars.insert(first.0.into(), Value::String(first.1.into()));
            for elt in iter {
                vars.insert(elt.0.into(), Value::String(elt.1.into()));
            }
            root.insert("variables".to_owned(), Value::Object(vars));
        }
        Value::Object(root)
    }

    /// Replaces the builder's items with `items`.
    pub fn items(mut self, items: &'a [Item]) -> Builder<'a> {
        self.set_items(items);
        self
    }

    /// Replaces the builder's variables with `variables`.
    pub fn variables(mut self, variables: HashMap<&'a str, &'a str>) -> Builder<'a> {
        self.set_variables(variables);
        self
    }

    /// Inserts a new variable into the builder's variables.
    pub fn variable(mut self, key: &'a str, value: &'a str) -> Builder<'a> {
        self.set_variable(key, value);
        self
    }

    /// Replaces the builder's items with `items`.
    pub fn set_items(&mut self, items: &'a [Item]) {
        self.items = items
    }

    /// Replaces the builder's variables with `variables`.
    pub fn set_variables(&mut self, variables: HashMap<&'a str, &'a str>) {
        self.variables = variables
    }

    /// Inserts a new variable into the builder's variables.
    pub fn set_variable(&mut self, key: &'a str, value: &'a str) {
        self.variables.insert(key, value);
    }
}

impl<'a> Item<'a> {
    fn to_json(&self) -> Value {
        let mut d = json::Map::new();
        d.insert("title".to_string(), json!(self.title));
        if let Some(ref subtitle) = self.subtitle {
            d.insert("subtitle".to_string(), json!(subtitle));
        }
        if let Some(ref icon) = self.icon {
            d.insert("icon".to_string(), icon.to_json());
        }
        if let Some(ref uid) = self.uid {
            d.insert("uid".to_string(), json!(uid));
        }
        if let Some(ref arg) = self.arg {
            d.insert("arg".to_string(), json!(arg));
        }
        match self.type_ {
            ItemType::Default => {}
            ItemType::File => {
                d.insert("type".to_string(), json!("file"));
            }
            ItemType::FileSkipCheck => {
                d.insert("type".to_string(), json!("file:skipcheck"));
            }
        }
        if !self.valid {
            d.insert("valid".to_string(), Value::Bool(false));
        }
        if let Some(ref autocomplete) = self.autocomplete {
            d.insert("autocomplete".to_string(), json!(autocomplete));
        }
        if self.text_copy.is_some() || self.text_large_type.is_some() {
            let mut text = json::Map::new();
            if let Some(ref text_copy) = self.text_copy {
                text.insert("copy".to_string(), json!(text_copy));
            }
            if let Some(ref text_large_type) = self.text_large_type {
                text.insert("largetype".to_string(), json!(text_large_type));
            }
            d.insert("text".to_string(), Value::Object(text));
        }
        if let Some(ref url) = self.quicklook_url {
            d.insert("quicklookurl".to_string(), json!(url));
        }
        if !self.modifiers.is_empty() {
            let mut mods = json::Map::with_capacity(self.modifiers.len());
            for (modifier, data) in &self.modifiers {
                let key = match *modifier {
                    Modifier::Command => "cmd",
                    Modifier::Option => "alt",
                    Modifier::Control => "ctrl",
                    Modifier::Shift => "shift",
                    Modifier::Fn => "fn"
                }.to_string();
                mods.insert(key, data.to_json());
            }
            d.insert("mods".to_string(), Value::Object(mods));
        }
        if !self.variables.is_empty() {
            let mut vars = json::Map::with_capacity(self.variables.len());
            for (key, value) in &self.variables {
                vars.insert(key.clone().into_owned(), json!(value.clone().into_owned()));
            }
            d.insert("variables".to_string(), Value::Object(vars));
        }
        Value::Object(d)
    }
}

impl<'a> Icon<'a> {
    fn to_json(&self) -> Value {
        match *self {
            Icon::Path(ref s) => json!({"path": s}),
            Icon::File(ref s) => json!({"type": "fileicon", "path": s}),
            Icon::FileType(ref s) => json!({"type": "filetype", "path": s})
        }
    }
}

impl<'a> ModifierData<'a> {
    fn to_json(&self) -> Value {
        let mut mod_ = json::Map::new();
        if let Some(ref subtitle) = self.subtitle {
            mod_.insert("subtitle".to_string(), json!(subtitle));
        }
        if let Some(ref arg) = self.arg {
            mod_.insert("arg".to_string(), json!(arg));
        }
        if let Some(valid) = self.valid {
            mod_.insert("valid".to_string(), json!(valid));
        }
        if let Some(ref icon) = self.icon {
            mod_.insert("icon".to_string(), icon.to_json());
        }
        if !self.variables.is_empty() {
            let mut vars = json::Map::with_capacity(self.variables.len());
            for (key, value) in &self.variables {
                vars.insert(key.clone().into_owned(), json!(value.clone().into_owned()));
            }
            mod_.insert("variables".to_string(), Value::Object(vars));
        }
        Value::Object(mod_)
    }
}

#[test]
fn test_to_json() {
    let item = Item::new("Item 1");
    assert_eq!(item.to_json(), json!({"title": "Item 1"}));
    let item = ::ItemBuilder::new("Item 2")
                              .subtitle("Subtitle")
                              .into_item();
    assert_eq!(item.to_json(),
              json!({
                  "title": "Item 2",
                  "subtitle": "Subtitle"
              }));
    let item = ::ItemBuilder::new("Item 3")
                              .arg("Argument")
                              .subtitle("Subtitle")
                              .icon_filetype("public.folder")
                              .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 3",
                   "subtitle": "Subtitle",
                   "arg": "Argument",
                   "icon": { "type": "filetype", "path": "public.folder" }
               }));
    let item = ::ItemBuilder::new("Item 4")
                              .arg("Argument")
                              .subtitle("Subtitle")
                              .arg_mod(Modifier::Option, "Alt Argument")
                              .valid_mod(Modifier::Option, false)
                              .icon_file_mod(Modifier::Option, "opt.png")
                              .arg_mod(Modifier::Control, "Ctrl Argument")
                              .subtitle_mod(Modifier::Control, "Ctrl Subtitle")
                              .icon_path_mod(Modifier::Control, "ctrl.png")
                              .arg_mod(Modifier::Shift, "Shift Argument")
                              .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 4",
                   "subtitle": "Subtitle",
                   "arg": "Argument",
                   "mods": {
                       "alt": {
                            "arg": "Alt Argument",
                            "valid": false,
                            "icon": { "type": "fileicon", "path": "opt.png" }
                       },
                       "ctrl": {
                           "arg": "Ctrl Argument",
                           "subtitle": "Ctrl Subtitle",
                           "icon": { "path": "ctrl.png" }
                       },
                       "shift": {
                           "arg": "Shift Argument"
                       }
                   }
               }));
    let item = ::ItemBuilder::new("Item 5")
                             .arg("Argument")
                             .variable("fruit", "banana")
                             .variable("vegetable", "carrot")
                             .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 5",
                   "arg": "Argument",
                   "variables": {
                       "fruit": "banana",
                       "vegetable": "carrot"
                   }
               }));
    let item = ::ItemBuilder::new("Item 6")
                             .subtitle("Subtitle")
                             .variable("fruit", "banana")
                             .variable_mod(Modifier::Option, "vegetable", "carrot")
                             .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 6",
                   "subtitle": "Subtitle",
                   "mods": {
                       "alt": {
                           "variables": {
                               "vegetable": "carrot"
                           }
                       }
                   },
                   "variables": {
                       "fruit": "banana"
                   }
               }));
}

#[test]
fn test_builder() {
    let json = Builder::with_items(&[
        Item::new("Item 1"),
        ::ItemBuilder::new("Item 2")
                      .subtitle("Subtitle")
                      .into_item(),
        ::ItemBuilder::new("Item 3")
                      .arg("Argument")
                      .subtitle("Subtitle")
                      .icon_filetype("public.folder")
                      .into_item()
    ]).variable("fruit", "banana")
      .variable("vegetable", "carrot")
      .into_json();
    assert_eq!(json,
               json!({
                   "items": [
                       {
                           "title": "Item 1"
                       },
                       {
                           "title": "Item 2",
                           "subtitle": "Subtitle"
                       },
                       {
                           "title": "Item 3",
                           "arg": "Argument",
                           "subtitle": "Subtitle",
                           "icon": { "type": "filetype", "path": "public.folder" }
                       }
                   ],
                   "variables": {
                       "fruit": "banana",
                       "vegetable": "carrot"
                   }
               }));
}
<commit_msg>Make into_json public<commit_after>//! Helpers for writing Alfred script filter JSON output (Alfred 3)
//!
//! # Examples
//!
//! ### Writing items
//!
//! ```
//! # extern crate alfred;
//! # use std::io::{self, Write};
//! #
//! # fn write_items() -> io::Result<()> {
//! alfred::json::write_items(io::stdout(), &[
//!     alfred::Item::new("Item 1"),
//!     alfred::ItemBuilder::new("Item 2")
//!                         .subtitle("Subtitle")
//!                         .into_item(),
//!     alfred::ItemBuilder::new("Item 3")
//!                         .arg("Argument")
//!                         .subtitle("Subtitle")
//!                         .icon_filetype("public.folder")
//!                         .into_item()
//! ])
//! # }
//! #
//! # fn main() {
//! #     match write_items() {
//! #         Ok(()) => {},
//! #         Err(err) => {
//! #             let _ = writeln!(&mut io::stderr(), "Error writing items: {}", err);
//! #         }
//! #     }
//! # }
//! ```
//!
//! ### Writing items with variables
//!
//! ```
//! # extern crate alfred;
//! # use alfred::Modifier;
//! # use std::io::{self, Write};
//! #
//! # fn write_items() -> io::Result<()> {
//! alfred::json::Builder::with_items(&[
//!     alfred::Item::new("Item 1"),
//!     alfred::ItemBuilder::new("Item 2")
//!                         .subtitle("Subtitle")
//!                         .variable("fruit", "banana")
//!                         .into_item(),
//!     alfred::ItemBuilder::new("Item 3")
//!                         .arg("Argument")
//!                         .subtitle("Subtitle")
//!                         .icon_filetype("public.folder")
//!                         .arg_mod(Modifier::Option, "Alt Argument")
//!                         .variable_mod(Modifier::Option, "vegetable", "carrot")
//!                         .into_item()
//! ]).variable("fruit", "banana")
//!   .variable("vegetable", "carrot")
//!   .write(io::stdout())
//! # }
//! #
//! # fn main() {
//! #     match write_items() {
//! #         Ok(()) => {},
//! #         Err(err) => {
//! #             let _ = writeln!(&mut io::stderr(), "Error writing items: {}", err);
//! #         }
//! #     }
//! # }
//! ```

use ::{Item, ItemType, Modifier, Icon, ModifierData};
use serde_json as json;
use serde_json::value::Value;
use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

/// Writes a complete JSON document representing the `Item`s to the `Write`.
///
/// The `Write` is flushed after the JSON document is written.
pub fn write_items<W: Write>(w: W, items: &[Item]) -> io::Result<()> {
    Builder::with_items(items).write(w)
}

/// A helper type for writing out items with top-level variables.
///
/// Note: If you don't need top-level variables the `write_items()` function is easier to use.
#[derive(Clone,Debug,Default)]
pub struct Builder<'a> {
    /// The items that will be written out.
    pub items: &'a [Item<'a>],
    /// The variables that will be written out.
    pub variables: HashMap<&'a str, &'a str>
}

impl<'a> Builder<'a> {
    /// Returns a new `Builder` with no items.
    pub fn new() -> Builder<'a> {
        Builder { items: &[], variables: HashMap::new() }
    }

    /// Returns a new `Builder` with the given items.
    pub fn with_items(items: &'a [Item]) -> Builder<'a> {
        Builder { items, variables: HashMap::new() }
    }

    /// Writes a complete JSON document representing the items and variables to the `Write`.
    ///
    /// The `Write` is flushed after the JSON document is written.
    pub fn write<W: Write>(self, mut w: W) -> io::Result<()> {
        write!(&mut w, "{}", self.into_json())?;
        w.flush()
    }

    /// Serializes items into their JSON representation
    pub fn into_json(self) -> Value {
        let mut root = json::Map::new();
        // We know for a fact that our implementation of ToJson cannot return an error.
        root.insert("items".to_string(), Value::Array(self.items.into_iter()
                                                                .map(|x| x.to_json())
                                                                .collect()));
        let mut iter = self.variables.into_iter();
        if let Some(first) = iter.next() {
            let mut vars = json::Map::new();
            vars.insert(first.0.into(), Value::String(first.1.into()));
            for elt in iter {
                vars.insert(elt.0.into(), Value::String(elt.1.into()));
            }
            root.insert("variables".to_owned(), Value::Object(vars));
        }
        Value::Object(root)
    }

    /// Replaces the builder's items with `items`.
    pub fn items(mut self, items: &'a [Item]) -> Builder<'a> {
        self.set_items(items);
        self
    }

    /// Replaces the builder's variables with `variables`.
    pub fn variables(mut self, variables: HashMap<&'a str, &'a str>) -> Builder<'a> {
        self.set_variables(variables);
        self
    }

    /// Inserts a new variable into the builder's variables.
    pub fn variable(mut self, key: &'a str, value: &'a str) -> Builder<'a> {
        self.set_variable(key, value);
        self
    }

    /// Replaces the builder's items with `items`.
    pub fn set_items(&mut self, items: &'a [Item]) {
        self.items = items
    }

    /// Replaces the builder's variables with `variables`.
    pub fn set_variables(&mut self, variables: HashMap<&'a str, &'a str>) {
        self.variables = variables
    }

    /// Inserts a new variable into the builder's variables.
    pub fn set_variable(&mut self, key: &'a str, value: &'a str) {
        self.variables.insert(key, value);
    }
}

impl<'a> Item<'a> {
    fn to_json(&self) -> Value {
        let mut d = json::Map::new();
        d.insert("title".to_string(), json!(self.title));
        if let Some(ref subtitle) = self.subtitle {
            d.insert("subtitle".to_string(), json!(subtitle));
        }
        if let Some(ref icon) = self.icon {
            d.insert("icon".to_string(), icon.to_json());
        }
        if let Some(ref uid) = self.uid {
            d.insert("uid".to_string(), json!(uid));
        }
        if let Some(ref arg) = self.arg {
            d.insert("arg".to_string(), json!(arg));
        }
        match self.type_ {
            ItemType::Default => {}
            ItemType::File => {
                d.insert("type".to_string(), json!("file"));
            }
            ItemType::FileSkipCheck => {
                d.insert("type".to_string(), json!("file:skipcheck"));
            }
        }
        if !self.valid {
            d.insert("valid".to_string(), Value::Bool(false));
        }
        if let Some(ref autocomplete) = self.autocomplete {
            d.insert("autocomplete".to_string(), json!(autocomplete));
        }
        if self.text_copy.is_some() || self.text_large_type.is_some() {
            let mut text = json::Map::new();
            if let Some(ref text_copy) = self.text_copy {
                text.insert("copy".to_string(), json!(text_copy));
            }
            if let Some(ref text_large_type) = self.text_large_type {
                text.insert("largetype".to_string(), json!(text_large_type));
            }
            d.insert("text".to_string(), Value::Object(text));
        }
        if let Some(ref url) = self.quicklook_url {
            d.insert("quicklookurl".to_string(), json!(url));
        }
        if !self.modifiers.is_empty() {
            let mut mods = json::Map::with_capacity(self.modifiers.len());
            for (modifier, data) in &self.modifiers {
                let key = match *modifier {
                    Modifier::Command => "cmd",
                    Modifier::Option => "alt",
                    Modifier::Control => "ctrl",
                    Modifier::Shift => "shift",
                    Modifier::Fn => "fn"
                }.to_string();
                mods.insert(key, data.to_json());
            }
            d.insert("mods".to_string(), Value::Object(mods));
        }
        if !self.variables.is_empty() {
            let mut vars = json::Map::with_capacity(self.variables.len());
            for (key, value) in &self.variables {
                vars.insert(key.clone().into_owned(), json!(value.clone().into_owned()));
            }
            d.insert("variables".to_string(), Value::Object(vars));
        }
        Value::Object(d)
    }
}

impl<'a> Icon<'a> {
    fn to_json(&self) -> Value {
        match *self {
            Icon::Path(ref s) => json!({"path": s}),
            Icon::File(ref s) => json!({"type": "fileicon", "path": s}),
            Icon::FileType(ref s) => json!({"type": "filetype", "path": s})
        }
    }
}

impl<'a> ModifierData<'a> {
    fn to_json(&self) -> Value {
        let mut mod_ = json::Map::new();
        if let Some(ref subtitle) = self.subtitle {
            mod_.insert("subtitle".to_string(), json!(subtitle));
        }
        if let Some(ref arg) = self.arg {
            mod_.insert("arg".to_string(), json!(arg));
        }
        if let Some(valid) = self.valid {
            mod_.insert("valid".to_string(), json!(valid));
        }
        if let Some(ref icon) = self.icon {
            mod_.insert("icon".to_string(), icon.to_json());
        }
        if !self.variables.is_empty() {
            let mut vars = json::Map::with_capacity(self.variables.len());
            for (key, value) in &self.variables {
                vars.insert(key.clone().into_owned(), json!(value.clone().into_owned()));
            }
            mod_.insert("variables".to_string(), Value::Object(vars));
        }
        Value::Object(mod_)
    }
}

#[test]
fn test_to_json() {
    let item = Item::new("Item 1");
    assert_eq!(item.to_json(), json!({"title": "Item 1"}));
    let item = ::ItemBuilder::new("Item 2")
                              .subtitle("Subtitle")
                              .into_item();
    assert_eq!(item.to_json(),
              json!({
                  "title": "Item 2",
                  "subtitle": "Subtitle"
              }));
    let item = ::ItemBuilder::new("Item 3")
                              .arg("Argument")
                              .subtitle("Subtitle")
                              .icon_filetype("public.folder")
                              .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 3",
                   "subtitle": "Subtitle",
                   "arg": "Argument",
                   "icon": { "type": "filetype", "path": "public.folder" }
               }));
    let item = ::ItemBuilder::new("Item 4")
                              .arg("Argument")
                              .subtitle("Subtitle")
                              .arg_mod(Modifier::Option, "Alt Argument")
                              .valid_mod(Modifier::Option, false)
                              .icon_file_mod(Modifier::Option, "opt.png")
                              .arg_mod(Modifier::Control, "Ctrl Argument")
                              .subtitle_mod(Modifier::Control, "Ctrl Subtitle")
                              .icon_path_mod(Modifier::Control, "ctrl.png")
                              .arg_mod(Modifier::Shift, "Shift Argument")
                              .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 4",
                   "subtitle": "Subtitle",
                   "arg": "Argument",
                   "mods": {
                       "alt": {
                            "arg": "Alt Argument",
                            "valid": false,
                            "icon": { "type": "fileicon", "path": "opt.png" }
                       },
                       "ctrl": {
                           "arg": "Ctrl Argument",
                           "subtitle": "Ctrl Subtitle",
                           "icon": { "path": "ctrl.png" }
                       },
                       "shift": {
                           "arg": "Shift Argument"
                       }
                   }
               }));
    let item = ::ItemBuilder::new("Item 5")
                             .arg("Argument")
                             .variable("fruit", "banana")
                             .variable("vegetable", "carrot")
                             .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 5",
                   "arg": "Argument",
                   "variables": {
                       "fruit": "banana",
                       "vegetable": "carrot"
                   }
               }));
    let item = ::ItemBuilder::new("Item 6")
                             .subtitle("Subtitle")
                             .variable("fruit", "banana")
                             .variable_mod(Modifier::Option, "vegetable", "carrot")
                             .into_item();
    assert_eq!(item.to_json(),
               json!({
                   "title": "Item 6",
                   "subtitle": "Subtitle",
                   "mods": {
                       "alt": {
                           "variables": {
                               "vegetable": "carrot"
                           }
                       }
                   },
                   "variables": {
                       "fruit": "banana"
                   }
               }));
}

#[test]
fn test_builder() {
    let json = Builder::with_items(&[
        Item::new("Item 1"),
        ::ItemBuilder::new("Item 2")
                      .subtitle("Subtitle")
                      .into_item(),
        ::ItemBuilder::new("Item 3")
                      .arg("Argument")
                      .subtitle("Subtitle")
                      .icon_filetype("public.folder")
                      .into_item()
    ]).variable("fruit", "banana")
      .variable("vegetable", "carrot")
      .into_json();
    assert_eq!(json,
               json!({
                   "items": [
                       {
                           "title": "Item 1"
                       },
                       {
                           "title": "Item 2",
                           "subtitle": "Subtitle"
                       },
                       {
                           "title": "Item 3",
                           "arg": "Argument",
                           "subtitle": "Subtitle",
                           "icon": { "type": "filetype", "path": "public.folder" }
                       }
                   ],
                   "variables": {
                       "fruit": "banana",
                       "vegetable": "carrot"
                   }
               }));
}
<|endoftext|>


<commit_before>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        map.insert(press_s, Arc::new(Box::new(key_s)));

        let press_f4 = KeyPress::from_key_names(vec!["Alt"],vec!["F4"]).unwrap();
        map.insert(press_f4, Arc::new(Box::new(key_f4)));

        let press_k = KeyPress::from_key_names(
            vec!["Ctrl"], vec!["k"]).unwrap();
        map.insert(press_k, Arc::new(Box::new(key_sleep)));

        let press_p = KeyPress::from_key_names(vec!["Ctrl"], vec!["p"]).unwrap();
        map.insert(press_p, Arc::new(Box::new(key_pointer_pos)));

        RwLock::new(map)
    };
}

fn key_sleep() {
    use std::thread;
    use std::time::Duration;

    use super::lua;
    use lua::LuaQuery;

    info!("keyhandler: Beginning thread::sleep keypress!");
    lua::try_send(LuaQuery::Execute("print('>entering sleep')\
                                 os.execute('sleep 5')\
                                 print('>leaving sleep')".to_string()))
                  .unwrap();
    info!("keyhandler: Finished thread::sleep keypress!");
}

fn key_pointer_pos() {
    use super::lua;
    use lua::LuaQuery;
    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                print('get_position is a func, preparing execution')
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::try_send(LuaQuery::Execute(code)).unwrap();
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<commit_msg>Add ctrl+escape which shuts everything down nicely<commit_after>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        map.insert(press_s, Arc::new(Box::new(key_s)));

        let press_f4 = KeyPress::from_key_names(vec!["Alt"],vec!["F4"]).unwrap();
        map.insert(press_f4, Arc::new(Box::new(key_f4)));

        let press_k = KeyPress::from_key_names(
            vec!["Ctrl"], vec!["k"]).unwrap();
        map.insert(press_k, Arc::new(Box::new(key_sleep)));

        let press_p = KeyPress::from_key_names(vec!["Ctrl"], vec!["p"]).unwrap();
        map.insert(press_p, Arc::new(Box::new(key_pointer_pos)));

        let press_esc = KeyPress::from_key_names(vec!["Ctrl"],
                                                 vec!["Escape"]).unwrap();
        map.insert(press_esc, Arc::new(Box::new(key_esc)));

        RwLock::new(map)
    };
}

fn key_sleep() {
    use std::thread;
    use std::time::Duration;

    use super::lua;
    use lua::LuaQuery;

    info!("keyhandler: Beginning thread::sleep keypress!");
    lua::try_send(LuaQuery::Execute("print('>entering sleep')\
                                 os.execute('sleep 5')\
                                 print('>leaving sleep')".to_string()))
                  .unwrap();
    info!("keyhandler: Finished thread::sleep keypress!");
}

fn key_pointer_pos() {
    use super::lua;
    use lua::LuaQuery;
    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                print('get_position is a func, preparing execution')
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::try_send(LuaQuery::Execute(code)).unwrap();
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

fn key_esc() {
    info!("handler: Esc keypress!");
    ::rustwlc::terminate();
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<|endoftext|>


<commit_before>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
#[macro_use]
extern crate serde_derive;
extern crate spaceapi_server;

use std::env;
use docopt::Docopt;
use spaceapi_server::SpaceapiServerBuilder;
use spaceapi_server::api;
use spaceapi_server::modifiers::StateFromPeopleNowPresent;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(Deserialize, Debug)]
struct Args {
    flag_p: u16,
    flag_i: std::net::Ipv4Addr,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::StatusBuilder::new("coredump")
        .logo("https://www.coredump.ch/wp-content/uploads/2016/11/logo.png")
        .url("https://www.coredump.ch/")
        .location(api::Location {
            address: Some("Zürcherstrasse 6, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22939,
            lon: 8.82041,
        })
        .contact(api::Contact {
            irc: Some("irc://freenode.net/#coredump".into()),
            twitter: Some("@coredump_ch".into()),
            email: Some("vorstand@lists.coredump.ch".into()),
            ..Default::default()
        })
        .add_issue_report_channel("email")
        .add_issue_report_channel("twitter")
        .spacefed(api::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        })
        .feeds(api::Feeds {
            blog: Some(api::Feed {
                type_: Some("rss".into()),
                url: "https://www.coredump.ch/feed/".into(),
            }),
            wiki: None,
            calendar: None,
            flickr: None,
        })
        .add_project("https://www.coredump.ch/projekte/")
        .add_project("https://forum.coredump.ch/c/projects")
        .add_project("https://github.com/coredump-ch/")
        .add_cam("https://webcam.coredump.ch/cams/ultimaker_0.jpg")
        .build()
        .expect("Couldn't create status object");

    status.state.message = Some("Open Mondays from 20:00".into());

    // Redis connection info
    let redis_host: String = env::var("REDIS_HOST")
        .unwrap_or("127.0.0.1".to_string());
    let redis_port: u16 = env::var("REDIS_PORT")
        .unwrap_or("6379".to_string()).parse().unwrap_or(6379);
    let redis_db: i64 = env::var("REDIS_DB")
        .unwrap_or("0".to_string()).parse().unwrap_or(0);
    let redis_url = format!("redis://{}:{}/{}", redis_host, redis_port, redis_db);

    SpaceapiServerBuilder::new(status)
        .redis_connection_info(&*redis_url)
        .add_status_modifier(StateFromPeopleNowPresent)
        .add_sensor(TemperatureSensorTemplate {
            unit: "°C".into(),
            location: "Hackerspace".into(),
            name: Some("Raspberry CPU".into()),
            description: None,
        }, "temperature_raspi".into())
        .add_sensor(TemperatureSensorTemplate {
            unit: "°C".into(),
            location: "Hackerspace".into(),
            name: Some("Room Temperature".into()),
            description: None,
        }, "temperature_room".into())
        .add_sensor(PeopleNowPresentSensorTemplate {
            location: Some("Hackerspace".into()),
            name: None,
            description: None,
            names: None,
        }, "people_now_present".into())
        .build()
        .expect("Could not build server")
        .serve((host, port)).expect("Could not start the server");
}
<commit_msg>Also accept IPv6 addresses<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
#[macro_use]
extern crate serde_derive;
extern crate spaceapi_server;

use std::env;
use docopt::Docopt;
use spaceapi_server::SpaceapiServerBuilder;
use spaceapi_server::api;
use spaceapi_server::modifiers::StateFromPeopleNowPresent;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The IP address to listen on [default: 127.0.0.1].
";

#[derive(Deserialize, Debug)]
struct Args {
    flag_p: u16,
    flag_i: std::net::IpAddr,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::StatusBuilder::new("coredump")
        .logo("https://www.coredump.ch/wp-content/uploads/2016/11/logo.png")
        .url("https://www.coredump.ch/")
        .location(api::Location {
            address: Some("Zürcherstrasse 6, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22939,
            lon: 8.82041,
        })
        .contact(api::Contact {
            irc: Some("irc://freenode.net/#coredump".into()),
            twitter: Some("@coredump_ch".into()),
            email: Some("vorstand@lists.coredump.ch".into()),
            ..Default::default()
        })
        .add_issue_report_channel("email")
        .add_issue_report_channel("twitter")
        .spacefed(api::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        })
        .feeds(api::Feeds {
            blog: Some(api::Feed {
                type_: Some("rss".into()),
                url: "https://www.coredump.ch/feed/".into(),
            }),
            wiki: None,
            calendar: None,
            flickr: None,
        })
        .add_project("https://www.coredump.ch/projekte/")
        .add_project("https://forum.coredump.ch/c/projects")
        .add_project("https://github.com/coredump-ch/")
        .add_cam("https://webcam.coredump.ch/cams/ultimaker_0.jpg")
        .build()
        .expect("Couldn't create status object");

    status.state.message = Some("Open Mondays from 20:00".into());

    // Redis connection info
    let redis_host: String = env::var("REDIS_HOST")
        .unwrap_or("127.0.0.1".to_string());
    let redis_port: u16 = env::var("REDIS_PORT")
        .unwrap_or("6379".to_string()).parse().unwrap_or(6379);
    let redis_db: i64 = env::var("REDIS_DB")
        .unwrap_or("0".to_string()).parse().unwrap_or(0);
    let redis_url = format!("redis://{}:{}/{}", redis_host, redis_port, redis_db);

    SpaceapiServerBuilder::new(status)
        .redis_connection_info(&*redis_url)
        .add_status_modifier(StateFromPeopleNowPresent)
        .add_sensor(TemperatureSensorTemplate {
            unit: "°C".into(),
            location: "Hackerspace".into(),
            name: Some("Raspberry CPU".into()),
            description: None,
        }, "temperature_raspi".into())
        .add_sensor(TemperatureSensorTemplate {
            unit: "°C".into(),
            location: "Hackerspace".into(),
            name: Some("Room Temperature".into()),
            description: None,
        }, "temperature_room".into())
        .add_sensor(PeopleNowPresentSensorTemplate {
            location: Some("Hackerspace".into()),
            name: None,
            description: None,
            names: None,
        }, "people_now_present".into())
        .build()
        .expect("Could not build server")
        .serve((host, port)).expect("Could not start the server");
}
<|endoftext|>


<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! KRPC implementation as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).

use std::collections;

use bencode::{mod, ToBencode};
use bencode::util::ByteString;

use super::Node;

/// Mapping String -> Bytes used in payload.
pub type BDict = collections::TreeMap<String, Vec<u8>>;

/// Package payload in KRPC: either Query (request) or Response or Error.
pub enum PackagePayload {
    /// Request to a node.
    Query(BDict),
    /// Response to request.
    Response(BDict),
    /// Error: code and string message.
    Error(i64, String)
}

/// KRPC package.
pub struct Package {
    /// Transaction ID generated by requester and passed back by responder.
    pub transaction_id: Vec<u8>,
    /// Package payload.
    pub payload: PackagePayload,
    /// Sender Node (note that as per BEP 0005 it is stored in payload).
    pub sender: Node
}

impl Package {
    fn bdict_to_bencode(&self, d: &BDict) -> bencode::Bencode {
        let mut result: bencode::DictMap = collections::TreeMap::new();
        for (key, value) in d.iter() {
            result.insert(ByteString::from_str(key.as_slice()),
                          value.to_bencode());
        }
        // TODO(divius): encode sender
        bencode::Dict(result)
    }
}

// FIXME(divius): should be upstream in bencode
#[inline]
fn bytes_to_bencode(bytes: &Vec<u8>) -> bencode::Bencode {
    bencode::ByteString(bytes.clone())
}

// FIXME(divius): should be upstream in bencode
#[inline]
fn str_to_bencode(s: &str) -> bencode::Bencode {
    bytes_to_bencode(&s.as_bytes().to_vec())
}

impl ToBencode for Package {
    fn to_bencode(&self) -> bencode::Bencode {
        // FIXME(divius): could be just TreeMap<String, Bencode>
        // if Bencode type implemented ToBencode. Move upstream?
        let mut result: bencode::DictMap = collections::TreeMap::new();

        result.insert(ByteString::from_str("tt"),
                      bytes_to_bencode(&self.transaction_id));
        let (typ, payload) = match self.payload {
            Query(ref d) => ("q", self.bdict_to_bencode(d)),
            Response(ref d) => ("r", self.bdict_to_bencode(d)),
            Error(code, ref s) => {
                let l = vec![code.to_bencode(), s.to_bencode()];
                ("e", bencode::List(l))
            }
        };
        // FIXME(divius): move to upstream bencode:
        // ToBencode should be implemented for &str
        result.insert(ByteString::from_str("y"), str_to_bencode(typ));
        result.insert(ByteString::from_str(typ), payload);

        bencode::Dict(result)
    }
}

#[cfg(test)]
mod test {
    use std::collections;

    use bencode::{mod, ToBencode};

    use super::BDict;
    use super::Error;
    use super::Package;
    use super::PackagePayload;
    use super::Query;
    use super::Response;

    use super::super::utils::test;

    fn new_package(payload: PackagePayload) -> Package {
        Package {
            transaction_id: vec![1, 2, 254, 255],
            sender: test::new_node(42),
            payload: payload
        }
    }

    fn common<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::DictMap {
        match *b {
            bencode::Dict(ref d) => {
                let tt_val = &d[bencode::util::ByteString::from_str("tt")];
                match *tt_val {
                    bencode::ByteString(ref v) => {
                        assert_eq!(vec![1, 2, 254, 255], *v);
                    },
                    _ => fail!("unexpected {}", tt_val)
                };

                let y_val = &d[bencode::util::ByteString::from_str("y")];
                match *y_val {
                    bencode::ByteString(ref v) => {
                        assert_eq!(typ.as_bytes(), v.as_slice());
                    },
                    _ => fail!("unexpected {}", y_val)
                };

                d
            },
            _ => fail!("unexpected {}", b)
        }
    }

    fn dict<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::DictMap {
        let d = common(b, typ);

        let typ_val = &d[bencode::util::ByteString::from_str(typ)];
        match *typ_val {
            bencode::Dict(ref m) => m,
            _ => fail!("unexpected {}", typ_val)
        }
    }

    fn list<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::ListVec {
        let d = common(b, typ);

        let typ_val = &d[bencode::util::ByteString::from_str(typ)];
        match *typ_val {
            bencode::List(ref l) => l,
            _ => fail!("unexpected {}", typ_val)
        }
    }

    #[test]
    fn test_error_to_bencode() {
        let p = new_package(Error(10, "error".to_string()));
        let enc = p.to_bencode();
        let l = list(&enc, "e");
        assert_eq!(vec![bencode::Number(10),
                        super::str_to_bencode("error")],
                   *l);
    }

    #[test]
    fn test_query_to_bencode() {
        let payload: BDict = collections::TreeMap::new();
        let p = new_package(Query(payload));
        let enc = p.to_bencode();
        dict(&enc, "q");
        // TODO(divius): Moar tests
    }

    #[test]
    fn test_response_to_bencode() {
        let payload: BDict = collections::TreeMap::new();
        let p = new_package(Response(payload));
        let enc = p.to_bencode();
        dict(&enc, "r");
        // TODO(divius): Moar tests
    }
}
<commit_msg>Numerous small improvements in krpc<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! KRPC implementation as described in
//! [BEP 0005](http://www.bittorrent.org/beps/bep_0005.html).

use std::collections;

use bencode::{mod, ToBencode};
use bencode::util::ByteString;

use super::Node;

/// Mapping String -> Bytes used in payload.
pub type PayloadDict = collections::TreeMap<String, Vec<u8>>;

/// Package payload in KRPC: either Query (request) or Response or Error.
pub enum Payload {
    /// Request to a node.
    Query(PayloadDict),
    /// Response to request.
    Response(PayloadDict),
    /// Error: code and string message.
    Error(i64, String)
}

/// KRPC package.
pub struct Package {
    /// Transaction ID generated by requester and passed back by responder.
    pub transaction_id: Vec<u8>,
    /// Package payload.
    pub payload: Payload,
    /// Sender Node (note that as per BEP 0005 it is stored in payload).
    pub sender: Node
}

impl ToBencode for Node {
    fn to_bencode(&self) -> bencode::Bencode {
        // TODO(divius): implement
        bencode::ByteString(vec![])
    }
}

impl Package {
    fn payload_dict_to_bencode(&self, d: &PayloadDict) -> bencode::Bencode {
        let mut result: bencode::DictMap = d.iter().map(|(k, v)| {
            (ByteString::from_str(k.as_slice()), v.to_bencode())
        }).collect();
        result.insert(ByteString::from_str("id"), self.sender.to_bencode());
        bencode::Dict(result)
    }
}

impl ToBencode for Package {
    fn to_bencode(&self) -> bencode::Bencode {
        let mut result: bencode::DictMap = collections::TreeMap::new();

        result.insert(ByteString::from_str("tt"),
                      bencode::ByteString(self.transaction_id.clone()));
        let (typ, payload) = match self.payload {
            Query(ref d) => ("q", self.payload_dict_to_bencode(d)),
            Response(ref d) => ("r", self.payload_dict_to_bencode(d)),
            Error(code, ref s) => {
                let l = vec![code.to_bencode(), s.to_bencode()];
                ("e", bencode::List(l))
            }
        };
        result.insert(ByteString::from_str("y"), typ.to_string().to_bencode());
        result.insert(ByteString::from_str(typ), payload);

        bencode::Dict(result)
    }
}

#[cfg(test)]
mod test {
    use std::collections;

    use bencode::{mod, ToBencode};

    use super::PayloadDict;
    use super::Error;
    use super::Package;
    use super::Payload;
    use super::Query;
    use super::Response;

    use super::super::utils::test;

    fn new_package(payload: Payload) -> Package {
        Package {
            transaction_id: vec![1, 2, 254, 255],
            sender: test::new_node(42),
            payload: payload
        }
    }

    fn common<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::DictMap {
        match *b {
            bencode::Dict(ref d) => {
                let tt_val = &d[bencode::util::ByteString::from_str("tt")];
                match *tt_val {
                    bencode::ByteString(ref v) => {
                        assert_eq!(vec![1, 2, 254, 255], *v);
                    },
                    _ => fail!("unexpected {}", tt_val)
                };

                let y_val = &d[bencode::util::ByteString::from_str("y")];
                match *y_val {
                    bencode::ByteString(ref v) => {
                        assert_eq!(typ.as_bytes(), v.as_slice());
                    },
                    _ => fail!("unexpected {}", y_val)
                };

                d
            },
            _ => fail!("unexpected {}", b)
        }
    }

    fn dict<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::DictMap {
        let d = common(b, typ);

        let typ_val = &d[bencode::util::ByteString::from_str(typ)];
        match *typ_val {
            bencode::Dict(ref m) => m,
            _ => fail!("unexpected {}", typ_val)
        }
    }

    fn list<'a>(b: &'a bencode::Bencode, typ: &str) -> &'a bencode::ListVec {
        let d = common(b, typ);

        let typ_val = &d[bencode::util::ByteString::from_str(typ)];
        match *typ_val {
            bencode::List(ref l) => l,
            _ => fail!("unexpected {}", typ_val)
        }
    }

    #[test]
    fn test_error_to_bencode() {
        let p = new_package(Error(10, "error".to_string()));
        let enc = p.to_bencode();
        let l = list(&enc, "e");
        assert_eq!(vec![bencode::Number(10),
                        "error".to_string().to_bencode()],
                   *l);
    }

    #[test]
    fn test_query_to_bencode() {
        let payload: PayloadDict = collections::TreeMap::new();
        let p = new_package(Query(payload));
        let enc = p.to_bencode();
        dict(&enc, "q");
        // TODO(divius): Moar tests
    }

    #[test]
    fn test_response_to_bencode() {
        let payload: PayloadDict = collections::TreeMap::new();
        let p = new_package(Response(payload));
        let enc = p.to_bencode();
        dict(&enc, "r");
        // TODO(divius): Moar tests
    }
}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            // TODO: GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature--collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Fix spec link<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            // TODO: GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>