<commit_before>/* automatically generated by rust-bindgen */

use glut::bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGet, glutGetWindow};
use glut::bindgen::{glutInit, glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc};
use glut::bindgen::{glutReshapeWindow, glutSetWindow, glutSwapBuffers, glutTimerFunc};
use libc::*;
use dvec::DVec;
use ptr::{null, to_unsafe_ptr};
use str::to_bytes;
use task::local_data::{local_data_get, local_data_set};
use cast::reinterpret_cast;
use vec::raw::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

pub type GLenum = i32;
pub type GLint = i32;
pub type GLfloat = f32;
pub type GLdouble = f64;

pub enum Window = c_int;

pub const DOUBLE: c_uint = 2 as c_uint;

const WINDOW_WIDTH: GLenum = 102;
const WINDOW_HEIGHT: GLenum = 103;

pub enum State {
    WindowWidth,
    WindowHeight
}

pub fn destroy<T>(_value: ~[T]) {
    // let it drop
}

pub fn init() unsafe {
    let argc = 0 as c_int;
    let command = to_bytes(~"glut");
    let argv: (*u8, *u8) = (to_ptr(command), null());
    let argv_p = reinterpret_cast(&to_unsafe_ptr(&argv));

    glutInit(to_unsafe_ptr(&argc), argv_p);

    destroy(move command);
}

pub fn create_window(name: ~str) -> Window unsafe {
    let bytes = to_bytes(name);
    return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
}

pub fn destroy_window(window: Window) unsafe {
    glutDestroyWindow(*window);
}

pub fn reshape_window(window: Window, width: c_int, height: c_int) unsafe {
    let current_window = glutGetWindow();
    glutSetWindow(*window);
    glutReshapeWindow(width, height);
    glutSetWindow(current_window);
}

pub fn display_callback_tls_key(_callback: @@fn()) {
    // Empty.
}

pub extern fn display_callback() unsafe {
    let callback = local_data_get(display_callback_tls_key).get();
    (*callback)();
}

pub fn display_func(callback: @fn()) unsafe {
    local_data_set(display_callback_tls_key, @callback);
    glutDisplayFunc(display_callback);
}

pub fn timer_callback_tls_key(_callback: @DVec<@fn()>) {
    // Empty.
}

pub extern fn timer_callback(index: int) unsafe {
    let callbacks = local_data_get(timer_callback_tls_key).get();
    ((*callbacks)[index as uint])();
}

pub fn timer_func(msecs: u32, callback: @fn()) unsafe {
    let callbacks;
    match local_data_get(timer_callback_tls_key) {
        None => {
            callbacks = @DVec();
            local_data_set(timer_callback_tls_key, copy callbacks);
        }
        Some(existing_callbacks) => {
            callbacks = existing_callbacks;
        }
    }

    callbacks.push(callback);
    let index = (callbacks.len() - 1) as c_int;
    glutTimerFunc(msecs, timer_callback, index);
}

pub fn reshape_callback_tls_key(_callback: @@fn(x: c_int, y: c_int)) {
    // Empty.
}

pub extern fn reshape_callback(++width: c_int, ++height: c_int) unsafe {
    let callback = local_data_get(reshape_callback_tls_key).get();
    (*callback)(width, height);
}

pub fn reshape_func(_window: Window, callback: @fn(x: c_int, y: c_int)) unsafe {
    local_data_set(reshape_callback_tls_key, @callback);
    glutReshapeFunc(reshape_callback);
}

#[cfg(target_os="macos")]
pub fn check_loop() unsafe {
    ext::glutCheckLoop();
}

#[cfg(target_os="linux")]
pub fn check_loop() unsafe {
    ext::glutMainLoopEvent();
}

pub fn init_display_mode(mode: c_uint) unsafe {
    glutInitDisplayMode(mode);
}

pub fn swap_buffers() unsafe {
    glutSwapBuffers();
}

pub fn post_redisplay() unsafe {
    glutPostRedisplay();
}

pub fn get(state: State) -> c_int unsafe {
    let glut_state;
    match state {
        WindowWidth => glut_state = WINDOW_WIDTH,
        WindowHeight => glut_state = WINDOW_HEIGHT
    }
    glutGet(glut_state)
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
pub extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
pub extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
pub extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
pub extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
pub extern mod bindgen {

pub fn glutInit(++argcp: *c_int, ++argv: **c_char);

pub fn glutInitDisplayMode(++mode: c_uint);

pub fn glutInitDisplayString(++string: *c_char);

pub fn glutInitWindowPosition(++x: c_int, ++y: c_int);

pub fn glutInitWindowSize(++width: c_int, ++height: c_int);

pub fn glutMainLoop();

pub fn glutCreateWindow(++title: *c_char) -> c_int;

pub fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

pub fn glutDestroyWindow(++win: c_int);

pub fn glutPostRedisplay();

pub fn glutPostWindowRedisplay(++win: c_int);

pub fn glutSwapBuffers();

pub fn glutGetWindow() -> c_int;

pub fn glutSetWindow(++win: c_int);

pub fn glutSetWindowTitle(++title: *c_char);

pub fn glutSetIconTitle(++title: *c_char);

pub fn glutPositionWindow(++x: c_int, ++y: c_int);

pub fn glutReshapeWindow(++width: c_int, ++height: c_int);

pub fn glutPopWindow();

pub fn glutPushWindow();

pub fn glutIconifyWindow();

pub fn glutShowWindow();

pub fn glutHideWindow();

pub fn glutFullScreen();

pub fn glutSetCursor(++cursor: c_int);

pub fn glutWarpPointer(++x: c_int, ++y: c_int);

pub fn glutEstablishOverlay();

pub fn glutRemoveOverlay();

pub fn glutUseLayer(++layer: GLenum);

pub fn glutPostOverlayRedisplay();

pub fn glutPostWindowOverlayRedisplay(++win: c_int);

pub fn glutShowOverlay();

pub fn glutHideOverlay();

pub fn glutCreateMenu(++arg1: *u8) -> c_int;

pub fn glutDestroyMenu(++menu: c_int);

pub fn glutGetMenu() -> c_int;

pub fn glutSetMenu(++menu: c_int);

pub fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

pub fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

pub fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

pub fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

pub fn glutRemoveMenuItem(++item: c_int);

pub fn glutAttachMenu(++button: c_int);

pub fn glutDetachMenu(++button: c_int);

pub fn glutDisplayFunc(++func: *u8);

pub fn glutReshapeFunc(++func: *u8);

pub fn glutKeyboardFunc(++func: *u8);

pub fn glutMouseFunc(++func: *u8);

pub fn glutMotionFunc(++func: *u8);

pub fn glutPassiveMotionFunc(++func: *u8);

pub fn glutEntryFunc(++func: *u8);

pub fn glutVisibilityFunc(++func: *u8);

pub fn glutIdleFunc(++func: *u8);

pub fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

pub fn glutMenuStateFunc(++func: *u8);

pub fn glutSpecialFunc(++func: *u8);

pub fn glutSpaceballMotionFunc(++func: *u8);

pub fn glutSpaceballRotateFunc(++func: *u8);

pub fn glutSpaceballButtonFunc(++func: *u8);

pub fn glutButtonBoxFunc(++func: *u8);

pub fn glutDialsFunc(++func: *u8);

pub fn glutTabletMotionFunc(++func: *u8);

pub fn glutTabletButtonFunc(++func: *u8);

pub fn glutMenuStatusFunc(++func: *u8);

pub fn glutOverlayDisplayFunc(++func: *u8);

pub fn glutWindowStatusFunc(++func: *u8);

pub fn glutKeyboardUpFunc(++func: *u8);

pub fn glutSpecialUpFunc(++func: *u8);

pub fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

pub fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

pub fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

pub fn glutCopyColormap(++win: c_int);

pub fn glutGet(++_type: GLenum) -> c_int;

pub fn glutDeviceGet(++_type: GLenum) -> c_int;

pub fn glutExtensionSupported(++name: *c_char) -> c_int;

pub fn glutGetModifiers() -> c_int;

pub fn glutLayerGet(++_type: GLenum) -> c_int;

pub fn glutGetProcAddress(++procName: *c_char) -> *c_void;

pub fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

pub fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

pub fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

pub fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

pub fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

pub fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

pub fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutWireCube(++size: GLdouble);

pub fn glutSolidCube(++size: GLdouble);

pub fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

pub fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

pub fn glutWireDodecahedron();

pub fn glutSolidDodecahedron();

pub fn glutWireTeapot(++size: GLdouble);

pub fn glutSolidTeapot(++size: GLdouble);

pub fn glutWireOctahedron();

pub fn glutSolidOctahedron();

pub fn glutWireTetrahedron();

pub fn glutSolidTetrahedron();

pub fn glutWireIcosahedron();

pub fn glutSolidIcosahedron();

pub fn glutVideoResizeGet(++param: GLenum) -> c_int;

pub fn glutSetupVideoResizing();

pub fn glutStopVideoResizing();

pub fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

pub fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

pub fn glutReportErrors();

pub fn glutIgnoreKeyRepeat(++ignore: c_int);

pub fn glutSetKeyRepeat(++repeatMode: c_int);

pub fn glutForceJoystickFunc();

pub fn glutGameModeString(++string: *c_char);

pub fn glutEnterGameMode() -> c_int;

pub fn glutLeaveGameMode();

pub fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<commit_msg>Rust upgrade.<commit_after>/* automatically generated by rust-bindgen */

use glut::bindgen::{glutCreateWindow, glutDestroyWindow, glutDisplayFunc, glutGet, glutGetWindow};
use glut::bindgen::{glutInit, glutInitDisplayMode, glutPostRedisplay, glutReshapeFunc};
use glut::bindgen::{glutReshapeWindow, glutSetWindow, glutSwapBuffers, glutTimerFunc};
use libc::*;
use dvec::DVec;
use ptr::{null, to_unsafe_ptr};
use str::to_bytes;
use task::local_data::{local_data_get, local_data_set};
use cast::reinterpret_cast;
use vec::raw::to_ptr;

/* FIXME: global variable glutStrokeRoman */

/* FIXME: global variable glutStrokeMonoRoman */

/* FIXME: global variable glutBitmap9By15 */

/* FIXME: global variable glutBitmap8By13 */

/* FIXME: global variable glutBitmapTimesRoman10 */

/* FIXME: global variable glutBitmapTimesRoman24 */

/* FIXME: global variable glutBitmapHelvetica10 */

/* FIXME: global variable glutBitmapHelvetica12 */

/* FIXME: global variable glutBitmapHelvetica18 */

pub type GLenum = i32;
pub type GLint = i32;
pub type GLfloat = f32;
pub type GLdouble = f64;

pub enum Window = c_int;

pub const DOUBLE: c_uint = 2 as c_uint;

const WINDOW_WIDTH: GLenum = 102;
const WINDOW_HEIGHT: GLenum = 103;

pub enum State {
    WindowWidth,
    WindowHeight
}

pub fn destroy<T>(_value: ~[T]) {
    // let it drop
}

pub fn init() {
    unsafe {
        let argc = 0 as c_int;
        let command = to_bytes(~"glut");
        let argv: (*u8, *u8) = (to_ptr(command), null());
        let argv_p = reinterpret_cast(&to_unsafe_ptr(&argv));

        glutInit(to_unsafe_ptr(&argc), argv_p);

        destroy(move command);
    }
}

pub fn create_window(name: ~str) -> Window {
    unsafe {
        let bytes = to_bytes(name);
        return Window(glutCreateWindow(to_ptr(bytes) as *c_char));
    }
}

pub fn destroy_window(window: Window) {
    unsafe {
        glutDestroyWindow(*window);
    }
}

pub fn reshape_window(window: Window, width: c_int, height: c_int) {
    unsafe {
        let current_window = glutGetWindow();
        glutSetWindow(*window);
        glutReshapeWindow(width, height);
        glutSetWindow(current_window);
    }
}

pub fn display_callback_tls_key(_callback: @@fn()) {
    // Empty.
}

pub extern fn display_callback() {
    unsafe {
        let callback = local_data_get(display_callback_tls_key).get();
        (*callback)();
    }
}

pub fn display_func(callback: @fn()) {
    unsafe {
        local_data_set(display_callback_tls_key, @callback);
        glutDisplayFunc(display_callback);
    }
}

pub fn timer_callback_tls_key(_callback: @DVec<@fn()>) {
    // Empty.
}

pub extern fn timer_callback(index: int) {
    unsafe {
        let callbacks = local_data_get(timer_callback_tls_key).get();
        ((*callbacks)[index as uint])();
    }
}

pub fn timer_func(msecs: u32, callback: @fn()) {
    unsafe {
        let callbacks;
        match local_data_get(timer_callback_tls_key) {
            None => {
                callbacks = @DVec();
                local_data_set(timer_callback_tls_key, copy callbacks);
            }
            Some(existing_callbacks) => {
                callbacks = existing_callbacks;
            }
        }

        callbacks.push(callback);
        let index = (callbacks.len() - 1) as c_int;
        glutTimerFunc(msecs, timer_callback, index);
    }
}

pub fn reshape_callback_tls_key(_callback: @@fn(x: c_int, y: c_int)) {
    // Empty.
}

pub extern fn reshape_callback(++width: c_int, ++height: c_int) {
    unsafe {
        let callback = local_data_get(reshape_callback_tls_key).get();
        (*callback)(width, height);
    }
}

pub fn reshape_func(_window: Window, callback: @fn(x: c_int, y: c_int)) {
    unsafe {
        local_data_set(reshape_callback_tls_key, @callback);
        glutReshapeFunc(reshape_callback);
    }
}

#[cfg(target_os="macos")]
pub fn check_loop() {
    unsafe {
        ext::glutCheckLoop();
    }
}

#[cfg(target_os="linux")]
pub fn check_loop() {
    unsafe {
        ext::glutMainLoopEvent();
    }
}

pub fn init_display_mode(mode: c_uint) {
    unsafe {
        glutInitDisplayMode(mode);
    }
}

pub fn swap_buffers() {
    unsafe {
        glutSwapBuffers();
    }
}

pub fn post_redisplay() {
    unsafe {
        glutPostRedisplay();
    }
}

pub fn get(state: State) -> c_int {
    let glut_state;
    match state {
        WindowWidth => glut_state = WINDOW_WIDTH,
        WindowHeight => glut_state = WINDOW_HEIGHT
    }
    unsafe { glutGet(glut_state) }
}

#[cfg(target_os="macos")]
#[nolink]
#[link_args="-framework GLUT"]
pub extern mod dummy {
}

#[cfg(target_os="linux")]
#[link_name="glut"]
pub extern mod dummy {
}

#[cfg(target_os="macos")]
#[nolink]
pub extern mod ext {
    // Mac GLUT extension.
    fn glutCheckLoop();
}

#[cfg(target_os="linux")]
#[nolink]
pub extern mod ext {
    // freeglut extension.
    fn glutMainLoopEvent();
}

#[nolink]
pub extern mod bindgen {

pub fn glutInit(++argcp: *c_int, ++argv: **c_char);

pub fn glutInitDisplayMode(++mode: c_uint);

pub fn glutInitDisplayString(++string: *c_char);

pub fn glutInitWindowPosition(++x: c_int, ++y: c_int);

pub fn glutInitWindowSize(++width: c_int, ++height: c_int);

pub fn glutMainLoop();

pub fn glutCreateWindow(++title: *c_char) -> c_int;

pub fn glutCreateSubWindow(++win: c_int, ++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int) -> c_int;

pub fn glutDestroyWindow(++win: c_int);

pub fn glutPostRedisplay();

pub fn glutPostWindowRedisplay(++win: c_int);

pub fn glutSwapBuffers();

pub fn glutGetWindow() -> c_int;

pub fn glutSetWindow(++win: c_int);

pub fn glutSetWindowTitle(++title: *c_char);

pub fn glutSetIconTitle(++title: *c_char);

pub fn glutPositionWindow(++x: c_int, ++y: c_int);

pub fn glutReshapeWindow(++width: c_int, ++height: c_int);

pub fn glutPopWindow();

pub fn glutPushWindow();

pub fn glutIconifyWindow();

pub fn glutShowWindow();

pub fn glutHideWindow();

pub fn glutFullScreen();

pub fn glutSetCursor(++cursor: c_int);

pub fn glutWarpPointer(++x: c_int, ++y: c_int);

pub fn glutEstablishOverlay();

pub fn glutRemoveOverlay();

pub fn glutUseLayer(++layer: GLenum);

pub fn glutPostOverlayRedisplay();

pub fn glutPostWindowOverlayRedisplay(++win: c_int);

pub fn glutShowOverlay();

pub fn glutHideOverlay();

pub fn glutCreateMenu(++arg1: *u8) -> c_int;

pub fn glutDestroyMenu(++menu: c_int);

pub fn glutGetMenu() -> c_int;

pub fn glutSetMenu(++menu: c_int);

pub fn glutAddMenuEntry(++label: *c_char, ++value: c_int);

pub fn glutAddSubMenu(++label: *c_char, ++submenu: c_int);

pub fn glutChangeToMenuEntry(++item: c_int, ++label: *c_char, ++value: c_int);

pub fn glutChangeToSubMenu(++item: c_int, ++label: *c_char, ++submenu: c_int);

pub fn glutRemoveMenuItem(++item: c_int);

pub fn glutAttachMenu(++button: c_int);

pub fn glutDetachMenu(++button: c_int);

pub fn glutDisplayFunc(++func: *u8);

pub fn glutReshapeFunc(++func: *u8);

pub fn glutKeyboardFunc(++func: *u8);

pub fn glutMouseFunc(++func: *u8);

pub fn glutMotionFunc(++func: *u8);

pub fn glutPassiveMotionFunc(++func: *u8);

pub fn glutEntryFunc(++func: *u8);

pub fn glutVisibilityFunc(++func: *u8);

pub fn glutIdleFunc(++func: *u8);

pub fn glutTimerFunc(++millis: c_uint, ++func: *u8, ++value: c_int);

pub fn glutMenuStateFunc(++func: *u8);

pub fn glutSpecialFunc(++func: *u8);

pub fn glutSpaceballMotionFunc(++func: *u8);

pub fn glutSpaceballRotateFunc(++func: *u8);

pub fn glutSpaceballButtonFunc(++func: *u8);

pub fn glutButtonBoxFunc(++func: *u8);

pub fn glutDialsFunc(++func: *u8);

pub fn glutTabletMotionFunc(++func: *u8);

pub fn glutTabletButtonFunc(++func: *u8);

pub fn glutMenuStatusFunc(++func: *u8);

pub fn glutOverlayDisplayFunc(++func: *u8);

pub fn glutWindowStatusFunc(++func: *u8);

pub fn glutKeyboardUpFunc(++func: *u8);

pub fn glutSpecialUpFunc(++func: *u8);

pub fn glutJoystickFunc(++func: *u8, ++pollInterval: c_int);

pub fn glutSetColor(++arg1: c_int, ++red: GLfloat, ++green: GLfloat, ++blue: GLfloat);

pub fn glutGetColor(++ndx: c_int, ++component: c_int) -> GLfloat;

pub fn glutCopyColormap(++win: c_int);

pub fn glutGet(++_type: GLenum) -> c_int;

pub fn glutDeviceGet(++_type: GLenum) -> c_int;

pub fn glutExtensionSupported(++name: *c_char) -> c_int;

pub fn glutGetModifiers() -> c_int;

pub fn glutLayerGet(++_type: GLenum) -> c_int;

pub fn glutGetProcAddress(++procName: *c_char) -> *c_void;

pub fn glutBitmapCharacter(++font: *c_void, ++character: c_int);

pub fn glutBitmapWidth(++font: *c_void, ++character: c_int) -> c_int;

pub fn glutStrokeCharacter(++font: *c_void, ++character: c_int);

pub fn glutStrokeWidth(++font: *c_void, ++character: c_int) -> c_int;

pub fn glutBitmapLength(++font: *c_void, ++string: *c_uchar) -> c_int;

pub fn glutStrokeLength(++font: *c_void, ++string: *c_uchar) -> c_int;

pub fn glutWireSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutSolidSphere(++radius: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutWireCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutSolidCone(++base: GLdouble, ++height: GLdouble, ++slices: GLint, ++stacks: GLint);

pub fn glutWireCube(++size: GLdouble);

pub fn glutSolidCube(++size: GLdouble);

pub fn glutWireTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

pub fn glutSolidTorus(++innerRadius: GLdouble, ++outerRadius: GLdouble, ++sides: GLint, ++rings: GLint);

pub fn glutWireDodecahedron();

pub fn glutSolidDodecahedron();

pub fn glutWireTeapot(++size: GLdouble);

pub fn glutSolidTeapot(++size: GLdouble);

pub fn glutWireOctahedron();

pub fn glutSolidOctahedron();

pub fn glutWireTetrahedron();

pub fn glutSolidTetrahedron();

pub fn glutWireIcosahedron();

pub fn glutSolidIcosahedron();

pub fn glutVideoResizeGet(++param: GLenum) -> c_int;

pub fn glutSetupVideoResizing();

pub fn glutStopVideoResizing();

pub fn glutVideoResize(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

pub fn glutVideoPan(++x: c_int, ++y: c_int, ++width: c_int, ++height: c_int);

pub fn glutReportErrors();

pub fn glutIgnoreKeyRepeat(++ignore: c_int);

pub fn glutSetKeyRepeat(++repeatMode: c_int);

pub fn glutForceJoystickFunc();

pub fn glutGameModeString(++string: *c_char);

pub fn glutEnterGameMode() -> c_int;

pub fn glutLeaveGameMode();

pub fn glutGameModeGet(++mode: GLenum) -> c_int;

}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
// use std::env;
use std::fs::create_dir_all;
use std::fs::{File, read_to_string};
use std::io::{BufRead, BufReader, Write};
use std::path::Path;

use serde::Serialize;
use serde_json::{self, Value as Json};

use handlebars::Handlebars;

use crate::common::templating::*;
use crate::common::ui::{Status, UIWriter, UI};
use crate::error::Result;

pub fn start(
    ui: &mut UI,
    template_path: String,
    default_toml_path: String,
    mock_data_path: Option<String>,
    render_dir: String,
) -> Result<()> {
    // create necessary vars
    let handlebars = Handlebars::new();
    // let mut data = HashMap::new();

    // let mut new_data = convert_to_json(&data);
    // Strip the file name out of our passed template
    let file_name = match Path::new(&template_path).file_name() {
        Some(name) => name.to_str().clone().unwrap(),
        None => panic!(format!("Something went wrong getting filename of {}", &template_path)),
    };

    ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?;
    ui.br()?;

    // Build out the variables passed.
    // data.insert("pkg_name".to_string(), "test".to_string());

    // read our template from file
    let template = read_to_string(&template_path)
        .expect(&format!("something went wrong reading: {}", template_path));

    let mock_data = match mock_data_path {
        Some(path) => read_to_string(path.to_string())
            .expect(&format!("Something went wrong reading: {}", path.to_string())),
        None => "{}".to_string(),
    };

    let json: Json = serde_json::from_str(&mock_data).unwrap();
    // println!("mock_data: {}", json);
    // println!("{}", template);
    //let content = render(template, json)?;

    let mut renderer = TemplateRenderer::new();
    renderer
        .register_template_string("testing", &template)
        .expect("Could not register template content");
    renderer
        .render("testing", &mock_data)
        .expect("Could not render template");

    // We want to render the configured variables.
    // let rendered_template = handlebars.template_render(&template, &json)?;

    // println!("#################\nRendered template:\n{}\n#############", rendered_template);
    // println!("######\nRendered template:\n{}\n#######", renderer);
    create_with_template(ui, &format!("{}/{}", render_dir, file_name), &renderer.to_string())?;
    Ok(())
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    ui.status(Status::Creating, format!("file: {}", location))?;
    // If the directory doesn't exist we need to make it.
    if let Some(directory) = path.parent() {
        create_dir_all(directory)?;
    }
    // Create and then render the template with Handlebars
    File::create(path).and_then(|mut file| file.write(template.as_bytes()))?;
    Ok(())
}
<commit_msg>should be rendering json?<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
// use std::env;
use std::fs::create_dir_all;
use std::fs::{File, read_to_string};
use std::io::{BufRead, BufReader, Write};
use std::path::Path;

use serde::Serialize;
use serde_json::{self, Value as Json};

use handlebars::Handlebars;

use crate::common::templating::*;
use crate::common::ui::{Status, UIWriter, UI};
use crate::error::Result;

pub fn start(
    ui: &mut UI,
    template_path: String,
    default_toml_path: String,
    mock_data_path: Option<String>,
    render_dir: String,
) -> Result<()> {
    // create necessary vars
    let handlebars = Handlebars::new();
    // let mut data = HashMap::new();

    // let mut new_data = convert_to_json(&data);
    // Strip the file name out of our passed template
    let file_name = match Path::new(&template_path).file_name() {
        Some(name) => name.to_str().clone().unwrap(),
        None => panic!(format!("Something went wrong getting filename of {}", &template_path)),
    };

    ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?;
    ui.br()?;

    // Build out the variables passed.
    // data.insert("pkg_name".to_string(), "test".to_string());

    // read our template from file
    let template = read_to_string(&template_path)
        .expect(&format!("something went wrong reading: {}", template_path));

    let mock_data = match mock_data_path {
        Some(path) => read_to_string(path.to_string())
            .expect(&format!("Something went wrong reading: {}", path.to_string())),
        None => "{}".to_string(),
    };

    let json: Json = serde_json::from_str(&mock_data).unwrap();
    // println!("mock_data: {}", json);
    // println!("{}", template);
    //let content = render(template, json)?;

    let mut renderer = TemplateRenderer::new();
    renderer
        .register_template_string("testing", &template)
        .expect("Could not register template content");
    renderer
        .render("testing", &json)
        .expect("Could not render template");

    // We want to render the configured variables.
    // let rendered_template = handlebars.template_render(&template, &json)?;

    // println!("#################\nRendered template:\n{}\n#############", rendered_template);
    // println!("######\nRendered template:\n{}\n#######", renderer);
    create_with_template(ui, &format!("{}/{}", render_dir, file_name), &renderer.to_string())?;
    Ok(())
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    ui.status(Status::Creating, format!("file: {}", location))?;
    // If the directory doesn't exist we need to make it.
    if let Some(directory) = path.parent() {
        create_dir_all(directory)?;
    }
    // Create and then render the template with Handlebars
    File::create(path).and_then(|mut file| file.write(template.as_bytes()))?;
    Ok(())
}
<|endoftext|>


<commit_before>use ra_db::{FileId, LocalSyntaxPtr, Cancelable};
use ra_syntax::{SyntaxNode, AstNode};
use hir::{Name, Def, ModuleSource};

use crate::{
    NavigationTarget,
    FileSymbol,
    db::RootDatabase,
};

impl NavigationTarget {
    pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            range: symbol.ptr.range(),
            ptr: Some(symbol.ptr.clone()),
        }
    }

    // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
    pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
        Ok(match def {
            Def::Struct(s) => {
                let (file_id, node) = s.source(db)?;
                Some(NavigationTarget::from_syntax(
                    s.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Enum(e) => {
                let (file_id, node) = e.source(db)?;
                Some(NavigationTarget::from_syntax(
                    e.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::EnumVariant(ev) => {
                let (file_id, node) = ev.source(db)?;
                Some(NavigationTarget::from_syntax(
                    ev.name(db)?,
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Function(f) => {
                let (file_id, node) = f.source(db)?;
                let name = f.signature(db).name().clone();
                Some(NavigationTarget::from_syntax(
                    Some(name),
                    file_id.original_file(db),
                    node.syntax(),
                ))
            }
            Def::Module(m) => {
                let (file_id, source) = m.definition_source(db)?;
                let name = m.name(db)?;
                match source {
                    ModuleSource::SourceFile(node) => {
                        Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
                    }
                    ModuleSource::Module(node) => {
                        Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
                    }
                }
            }
            Def::Item => None,
        })
    }

    fn from_syntax(name: Option<Name>, file_id: FileId, node: &SyntaxNode) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name: name.map(|n| n.to_string().into()).unwrap_or("".into()),
            kind: node.kind(),
            range: node.range(),
            ptr: Some(LocalSyntaxPtr::new(node)),
        }
    }
}
<commit_msg>refactor nav target<commit_after>use ra_db::{FileId, LocalSyntaxPtr, Cancelable};
use ra_syntax::{
    SyntaxNode, AstNode, SmolStr,
    ast
};
use hir::{Def, ModuleSource};

use crate::{
    NavigationTarget,
    FileSymbol,
    db::RootDatabase,
};

impl NavigationTarget {
    pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
        NavigationTarget {
            file_id: symbol.file_id,
            name: symbol.name.clone(),
            kind: symbol.ptr.kind(),
            range: symbol.ptr.range(),
            ptr: Some(symbol.ptr.clone()),
        }
    }

    // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
    pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
        Ok(match def {
            Def::Struct(s) => {
                let (file_id, node) = s.source(db)?;
                Some(NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                ))
            }
            Def::Enum(e) => {
                let (file_id, node) = e.source(db)?;
                Some(NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                ))
            }
            Def::EnumVariant(ev) => {
                let (file_id, node) = ev.source(db)?;
                Some(NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                ))
            }
            Def::Function(f) => {
                let (file_id, node) = f.source(db)?;
                Some(NavigationTarget::from_named(
                    file_id.original_file(db),
                    &*node,
                ))
            }
            Def::Module(m) => {
                let (file_id, source) = m.definition_source(db)?;
                let name = m
                    .name(db)?
                    .map(|it| it.to_string().into())
                    .unwrap_or_else(|| SmolStr::new(""));
                match source {
                    ModuleSource::SourceFile(node) => {
                        Some(NavigationTarget::from_syntax(file_id, name, node.syntax()))
                    }
                    ModuleSource::Module(node) => {
                        Some(NavigationTarget::from_syntax(file_id, name, node.syntax()))
                    }
                }
            }
            Def::Item => None,
        })
    }

    fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
        let name = node
            .name()
            .map(|it| it.text().clone())
            .unwrap_or_else(|| SmolStr::new(""));
        NavigationTarget::from_syntax(file_id, name, node.syntax())
    }

    fn from_syntax(file_id: FileId, name: SmolStr, node: &SyntaxNode) -> NavigationTarget {
        NavigationTarget {
            file_id,
            name,
            kind: node.kind(),
            range: node.range(),
            ptr: Some(LocalSyntaxPtr::new(node)),
        }
    }
}
<|endoftext|>


<commit_before>///! Constructors for [predefined push rules].
///!
///! [predefined push rules]: https://spec.matrix.org/v1.2/client-server-api/#predefined-rules
use indexmap::indexset;

use super::{
    Action::*, ConditionalPushRule, PatternedPushRule, PushCondition::*, RoomMemberCountIs,
    Ruleset, Tweak,
};
use crate::UserId;

impl Ruleset {
    /// The list of all [predefined push rules].
    ///
    /// [predefined push rules]: https://spec.matrix.org/v1.2/client-server-api/#predefined-rules
    ///
    /// # Parameters
    ///
    /// - `user_id`: the user for which to generate the default rules. Some rules depend on the
    ///   user's ID (for instance those to send notifications when they are mentioned).
    pub fn server_default(user_id: &UserId) -> Self {
        Self {
            content: indexset![PatternedPushRule::contains_user_name(user_id)],
            #[cfg(feature = "unstable-msc2677")]
            override_: indexset![
                ConditionalPushRule::master(),
                ConditionalPushRule::suppress_notices(),
                ConditionalPushRule::invite_for_me(user_id),
                ConditionalPushRule::member_event(),
                ConditionalPushRule::contains_display_name(),
                ConditionalPushRule::tombstone(),
                ConditionalPushRule::roomnotif(),
                ConditionalPushRule::reaction(),
            ],
            #[cfg(not(feature = "unstable-msc2677"))]
            override_: indexset![
                ConditionalPushRule::master(),
                ConditionalPushRule::suppress_notices(),
                ConditionalPushRule::invite_for_me(user_id),
                ConditionalPushRule::member_event(),
                ConditionalPushRule::contains_display_name(),
                ConditionalPushRule::tombstone(),
                ConditionalPushRule::roomnotif(),
            ],
            underride: indexset![
                ConditionalPushRule::call(),
                ConditionalPushRule::encrypted_room_one_to_one(),
                ConditionalPushRule::room_one_to_one(),
                ConditionalPushRule::message(),
                ConditionalPushRule::encrypted(),
            ],
            ..Default::default()
        }
    }
}

/// Default override push rules
impl ConditionalPushRule {
    /// Matches all events, this can be enabled to turn off all push notifications other than those
    /// generated by override rules set by the user.
    pub fn master() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: false,
            rule_id: ".m.rule.master".into(),
            conditions: vec![],
        }
    }

    /// Matches messages with a `msgtype` of `notice`.
    pub fn suppress_notices() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.suppress_notices".into(),
            conditions: vec![EventMatch {
                key: "content.msgtype".into(),
                pattern: "m.notice".into(),
            }],
        }
    }

    /// Matches any invites to a new room for this user.
    pub fn invite_for_me(user_id: &UserId) -> Self {
        Self {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.invite_for_me".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.member".into() },
                EventMatch { key: "content.membership".into(), pattern: "invite".into() },
                EventMatch { key: "state_key".into(), pattern: user_id.to_string() },
            ],
        }
    }

    /// Matches any `m.room.member_event`.
    pub fn member_event() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.member_event".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.member".into() }],
        }
    }

    /// Matches any message whose content is unencrypted and contains the user's current display
    /// name in the room in which it was sent.
    pub fn contains_display_name() -> Self {
        Self {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.contains_display_name".into(),
            conditions: vec![ContainsDisplayName],
        }
    }

    /// Matches any state event whose type is `m.room.tombstone`. This
    /// is intended to notify users of a room when it is upgraded,
    /// similar to what an `@room` notification would accomplish.
    pub fn tombstone() -> Self {
        Self {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: false,
            rule_id: ".m.rule.tombstone".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.tombstone".into() },
                EventMatch { key: "state_key".into(), pattern: "".into() },
            ],
        }
    }

    /// Matches any message whose content is unencrypted and contains the text `@room`, signifying
    /// the whole room should be notified of the event.
    pub fn roomnotif() -> Self {
        Self {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: true,
            rule_id: ".m.rule.roomnotif".into(),
            conditions: vec![
                EventMatch { key: "content.body".into(), pattern: "@room".into() },
                SenderNotificationPermission { key: "room".into() },
            ],
        }
    }

    /// Matches emoji reactions to a message
    /// MSC2677: Annotations and Reactions
    #[cfg(feature = "unstable-msc2677")]
    pub fn reaction() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.reaction".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.reaction".into() }],
        }
    }
}

/// Default content push rules
impl PatternedPushRule {
    /// Matches any message whose content is unencrypted and contains the local part of the user's
    /// Matrix ID, separated by word boundaries.
    pub fn contains_user_name(user_id: &UserId) -> Self {
        Self {
            rule_id: ".m.rules.contains_user_name".into(),
            enabled: true,
            default: true,
            pattern: user_id.localpart().into(),
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
        }
    }
}

/// Default underrides push rules
impl ConditionalPushRule {
    /// Matches any incoming VOIP call.
    pub fn call() -> Self {
        Self {
            rule_id: ".m.rules.call".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.call.invite".into() }],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("ring".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches any encrypted event sent in a room with exactly two members.
    ///
    /// Unlike other push rules, this rule cannot be matched against the content of the event by
    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
    /// either matches all events that are encrypted (in 1:1 rooms) or none.
    pub fn encrypted_room_one_to_one() -> Self {
        Self {
            rule_id: ".m.rules.encrypted_room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches any message sent in a room with exactly two members.
    pub fn room_one_to_one() -> Self {
        Self {
            rule_id: ".m.rules.room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.message".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches all chat messages.
    pub fn message() -> Self {
        Self {
            rule_id: ".m.rules.message".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.message".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        }
    }

    /// Matches all encrypted events.
    ///
    /// Unlike other push rules, this rule cannot be matched against the content of the event by
    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
    /// either matches all events that are encrypted (in group rooms) or none.
    pub fn encrypted() -> Self {
        Self {
            rule_id: ".m.rules.encrypted".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        }
    }
}
<commit_msg>fix: Correct rule IDs in predefined Rulesets<commit_after>///! Constructors for [predefined push rules].
///!
///! [predefined push rules]: https://spec.matrix.org/v1.2/client-server-api/#predefined-rules
use indexmap::indexset;

use super::{
    Action::*, ConditionalPushRule, PatternedPushRule, PushCondition::*, RoomMemberCountIs,
    Ruleset, Tweak,
};
use crate::UserId;

impl Ruleset {
    /// The list of all [predefined push rules].
    ///
    /// [predefined push rules]: https://spec.matrix.org/v1.2/client-server-api/#predefined-rules
    ///
    /// # Parameters
    ///
    /// - `user_id`: the user for which to generate the default rules. Some rules depend on the
    ///   user's ID (for instance those to send notifications when they are mentioned).
    pub fn server_default(user_id: &UserId) -> Self {
        Self {
            content: indexset![PatternedPushRule::contains_user_name(user_id)],
            #[cfg(feature = "unstable-msc2677")]
            override_: indexset![
                ConditionalPushRule::master(),
                ConditionalPushRule::suppress_notices(),
                ConditionalPushRule::invite_for_me(user_id),
                ConditionalPushRule::member_event(),
                ConditionalPushRule::contains_display_name(),
                ConditionalPushRule::tombstone(),
                ConditionalPushRule::roomnotif(),
                ConditionalPushRule::reaction(),
            ],
            #[cfg(not(feature = "unstable-msc2677"))]
            override_: indexset![
                ConditionalPushRule::master(),
                ConditionalPushRule::suppress_notices(),
                ConditionalPushRule::invite_for_me(user_id),
                ConditionalPushRule::member_event(),
                ConditionalPushRule::contains_display_name(),
                ConditionalPushRule::tombstone(),
                ConditionalPushRule::roomnotif(),
            ],
            underride: indexset![
                ConditionalPushRule::call(),
                ConditionalPushRule::encrypted_room_one_to_one(),
                ConditionalPushRule::room_one_to_one(),
                ConditionalPushRule::message(),
                ConditionalPushRule::encrypted(),
            ],
            ..Default::default()
        }
    }
}

/// Default override push rules
impl ConditionalPushRule {
    /// Matches all events, this can be enabled to turn off all push notifications other than those
    /// generated by override rules set by the user.
    pub fn master() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: false,
            rule_id: ".m.rule.master".into(),
            conditions: vec![],
        }
    }

    /// Matches messages with a `msgtype` of `notice`.
    pub fn suppress_notices() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.suppress_notices".into(),
            conditions: vec![EventMatch {
                key: "content.msgtype".into(),
                pattern: "m.notice".into(),
            }],
        }
    }

    /// Matches any invites to a new room for this user.
    pub fn invite_for_me(user_id: &UserId) -> Self {
        Self {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.invite_for_me".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.member".into() },
                EventMatch { key: "content.membership".into(), pattern: "invite".into() },
                EventMatch { key: "state_key".into(), pattern: user_id.to_string() },
            ],
        }
    }

    /// Matches any `m.room.member_event`.
    pub fn member_event() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.member_event".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.member".into() }],
        }
    }

    /// Matches any message whose content is unencrypted and contains the user's current display
    /// name in the room in which it was sent.
    pub fn contains_display_name() -> Self {
        Self {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.contains_display_name".into(),
            conditions: vec![ContainsDisplayName],
        }
    }

    /// Matches any state event whose type is `m.room.tombstone`. This
    /// is intended to notify users of a room when it is upgraded,
    /// similar to what an `@room` notification would accomplish.
    pub fn tombstone() -> Self {
        Self {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: false,
            rule_id: ".m.rule.tombstone".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.tombstone".into() },
                EventMatch { key: "state_key".into(), pattern: "".into() },
            ],
        }
    }

    /// Matches any message whose content is unencrypted and contains the text `@room`, signifying
    /// the whole room should be notified of the event.
    pub fn roomnotif() -> Self {
        Self {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: true,
            rule_id: ".m.rule.roomnotif".into(),
            conditions: vec![
                EventMatch { key: "content.body".into(), pattern: "@room".into() },
                SenderNotificationPermission { key: "room".into() },
            ],
        }
    }

    /// Matches emoji reactions to a message
    /// MSC2677: Annotations and Reactions
    #[cfg(feature = "unstable-msc2677")]
    pub fn reaction() -> Self {
        Self {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.reaction".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.reaction".into() }],
        }
    }
}

/// Default content push rules
impl PatternedPushRule {
    /// Matches any message whose content is unencrypted and contains the local part of the user's
    /// Matrix ID, separated by word boundaries.
    pub fn contains_user_name(user_id: &UserId) -> Self {
        Self {
            rule_id: ".m.rule.contains_user_name".into(),
            enabled: true,
            default: true,
            pattern: user_id.localpart().into(),
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
        }
    }
}

/// Default underrides push rules
impl ConditionalPushRule {
    /// Matches any incoming VOIP call.
    pub fn call() -> Self {
        Self {
            rule_id: ".m.rule.call".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.call.invite".into() }],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("ring".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches any encrypted event sent in a room with exactly two members.
    ///
    /// Unlike other push rules, this rule cannot be matched against the content of the event by
    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
    /// either matches all events that are encrypted (in 1:1 rooms) or none.
    pub fn encrypted_room_one_to_one() -> Self {
        Self {
            rule_id: ".m.rule.encrypted_room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches any message sent in a room with exactly two members.
    pub fn room_one_to_one() -> Self {
        Self {
            rule_id: ".m.rule.room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.message".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        }
    }

    /// Matches all chat messages.
    pub fn message() -> Self {
        Self {
            rule_id: ".m.rule.message".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.message".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        }
    }

    /// Matches all encrypted events.
    ///
    /// Unlike other push rules, this rule cannot be matched against the content of the event by
    /// nature of it being encrypted. This causes the rule to be an "all or nothing" match where it
    /// either matches all events that are encrypted (in group rooms) or none.
    pub fn encrypted() -> Self {
        Self {
            rule_id: ".m.rule.encrypted".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        }
    }
}
<|endoftext|>


<commit_before>extern crate minigrep;

use std::env;
use std::process;

use minigrep::Config;

fn main() {
    let args: Vec<String> = env::args().collect();

    let config = Config::new(&args).unwrap_or_else(|err| {
        println!("Proglem parsing arguments: {}", err);
        process::exit(1);
    });

    if let Err(e) = minigrep::run(config) {
        println!("Application error: {}", e);

        process::exit(1);
    };
}
<commit_msg>print error ot stderr instead of stdout<commit_after>extern crate minigrep;

use std::env;
use std::process;

use minigrep::Config;

fn main() {
    let args: Vec<String> = env::args().collect();

    let config = Config::new(&args).unwrap_or_else(|err| {
        println!("Problem parsing arguments: {}", err);
        process::exit(1);
    });

    if let Err(e) = minigrep::run(config) {
        eprintln!("Application error: {}", e);

        process::exit(1);
    };
}
<|endoftext|>


<commit_before>mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

use chrono::Duration;
use chrono::prelude::*;
use std::error::Error;
use std::fmt;
use util::Rounding;

#[derive(Debug)]
pub enum ParseError {
    PE(grammar::ParseError),
    Overflow,
    Hour,
    Minute,
    Second,
    Nanosecond,
}

impl From<grammar::ParseError> for ParseError {
    fn from(err: grammar::ParseError) -> ParseError {
        ParseError::PE(err)
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::PE(ref err) => err.description(),
            ParseError::Overflow => "Invalid input",
            ParseError::Hour => "The specified hours is invalid",
            ParseError::Minute => "The specified minutes is invalid",
            ParseError::Second => "The specified seconds is invalid",
            ParseError::Nanosecond => "The specified nanoseconds is invalid",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            ParseError::PE(ref err) => Some(err as &Error),
            _ => None,
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::PE(ref err) => fmt::Display::fmt(err, f),
            _ => fmt::Display::fmt(self.description(), f),
        }
    }
}

pub fn parse_rounding(fmt: &str) -> Result<Rounding, ParseError> {
    let res = try!(grammar::rounding(fmt));
    return Ok(res);
}

pub fn parse_offset(offset: &str,
                    time: DateTime<FixedOffset>)
                    -> Result<DateTime<FixedOffset>, ParseError> {
    let offset = try!(grammar::offset(offset));
    let offset = Duration::seconds(offset as i64);
    time.checked_add_signed(offset).ok_or(ParseError::Overflow)

}

#[allow(dead_code)] // This function may go away if I don't find a use for it soon
pub fn parse_time(input: &str,
                  time: DateTime<FixedOffset>)
                  -> Result<DateTime<FixedOffset>, ParseError> {
    let (hour, minute, second) = try!(grammar::time(input));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

pub fn parse_datetime(input: &str,
                      time: DateTime<FixedOffset>)
                      -> Result<DateTime<FixedOffset>, ParseError> {
    let (year, month, day, hour, minute, second, tz) =
        try!(grammar::datetime(input));

    let year = year.unwrap_or(time.year());
    let month = month.unwrap_or(time.month());
    let day = day.unwrap_or(time.day());

    // set timezone
    let tz = tz.unwrap_or(time.offset().utc_minus_local());
    let tzo = FixedOffset::west(tz);
    let time = tzo.ymd(year, month, day);

    // set the time
    let time = time.and_hms(0, 0, 0);
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

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

    #[test]
    fn parse_rounding_test() {
        assert_eq!(parse_rounding("+1D").unwrap(), Rounding::Up(86400.0));
        assert_eq!(parse_rounding("-1d").unwrap(), Rounding::Down(86400.0));
        assert_eq!(parse_rounding("=1d").unwrap(), Rounding::Half(86400.0));

        assert_eq!(parse_rounding("+1H").unwrap(), Rounding::Up(3600.0));
        assert_eq!(parse_rounding("-1h").unwrap(), Rounding::Down(3600.0));
        assert_eq!(parse_rounding("=1h").unwrap(), Rounding::Half(3600.0));

        assert_eq!(parse_rounding("+30M").unwrap(), Rounding::Up(1800.0));
        assert_eq!(parse_rounding("-30m").unwrap(), Rounding::Down(1800.0));
        assert_eq!(parse_rounding("=30m").unwrap(), Rounding::Half(1800.0));
        assert_eq!(parse_rounding("7.5").unwrap(), Rounding::Half(450.0));

        assert_eq!(parse_rounding("+30S").unwrap(), Rounding::Up(30.0));
        assert_eq!(parse_rounding("-30s").unwrap(), Rounding::Down(30.0));
        assert_eq!(parse_rounding("30s").unwrap(), Rounding::Half(30.0));
    }

    #[test]
    fn offset_test() {
        assert_eq!(grammar::offset("+2.3s").unwrap(), 2.3);
        assert_eq!(grammar::offset("-1.55h").unwrap(), -5580.0);
        assert_eq!(grammar::offset("+2:22").unwrap(), 8520.0);
        assert_eq!(grammar::offset("-2:22").unwrap(), -8520.0);
    }

    #[test]
    fn parse_offset_test() {
        let ctime = now();
        let n = ctime.checked_add_signed(Duration::seconds(5580)).unwrap();
        assert_eq!(parse_offset("+1.55h", ctime).unwrap(), n);
    }

    #[test]
    fn time_test() {
        assert_eq!(grammar::time("09:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055").unwrap(), (9, 22, 32.055));
        assert_eq!(grammar::time("9:22:32 Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055Pm").unwrap(), (21, 22, 32.055));
        assert_eq!(grammar::time("9:22 Pm").unwrap(), (21, 22, 0.0));
        // Might want to fail on these someday
        assert_eq!(grammar::time("9:22:32. Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22: Pm").unwrap(), (21, 22, 0.0));
        assert_eq!(grammar::time("99:22:32").unwrap(), (99, 22, 32.0));
    }

    #[test]
    fn parse_time_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_time("9:22:31.9617 Pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_time("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }

    #[test]
    fn datetime_test() {
        assert_eq!(grammar::datetime("4/2 9:22 Pm").unwrap(),
                   (None, Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2 9:22 Pm").unwrap(),
                   (Some(2017), Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2").unwrap(),
                   (Some(2017), Some(4), Some(2), 0, 0, 0.0, None));
        assert_eq!(grammar::datetime("9:22 Pm").unwrap(),
                   (None, None, None, 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("12:24 Pm").unwrap(),
                   (None, None, None, 12, 24, 0.0, None));
    }

    #[test]
    fn parse_datetime_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("9:22:31.9617 Pm", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_datetime("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30 9:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T00:00:00-05:00");
        // 12pm == midnight bug
        assert_eq!(parse_datetime("12:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T12:24:00-05:00");
        assert_eq!(parse_datetime("1:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T13:24:00-05:00");
        assert_eq!(parse_datetime("1:24am", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T01:24:00-05:00");
    }

    #[test]
    #[should_panic(expected = "ParseError")]
    fn parse_datetime_seperator_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("2017-4-309:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }
}
<commit_msg>Fix formating in parser.rs<commit_after>mod grammar {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

use chrono::Duration;
use chrono::prelude::*;
use std::error::Error;
use std::fmt;
use util::Rounding;

#[derive(Debug)]
pub enum ParseError {
    PE(grammar::ParseError),
    Overflow,
    Hour,
    Minute,
    Second,
    Nanosecond,
}

impl From<grammar::ParseError> for ParseError {
    fn from(err: grammar::ParseError) -> ParseError {
        ParseError::PE(err)
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::PE(ref err) => err.description(),
            ParseError::Overflow => "Invalid input",
            ParseError::Hour => "The specified hours is invalid",
            ParseError::Minute => "The specified minutes is invalid",
            ParseError::Second => "The specified seconds is invalid",
            ParseError::Nanosecond => "The specified nanoseconds is invalid",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            ParseError::PE(ref err) => Some(err as &Error),
            _ => None,
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::PE(ref err) => fmt::Display::fmt(err, f),
            _ => fmt::Display::fmt(self.description(), f),
        }
    }
}

pub fn parse_rounding(fmt: &str) -> Result<Rounding, ParseError> {
    let res = try!(grammar::rounding(fmt));
    return Ok(res);
}

pub fn parse_offset(offset: &str,
                    time: DateTime<FixedOffset>)
                    -> Result<DateTime<FixedOffset>, ParseError> {
    let offset = try!(grammar::offset(offset));
    let offset = Duration::seconds(offset as i64);
    time.checked_add_signed(offset).ok_or(ParseError::Overflow)

}

#[allow(dead_code)] // This function may go away if I don't find a use for it soon
pub fn parse_time(input: &str,
                  time: DateTime<FixedOffset>)
                  -> Result<DateTime<FixedOffset>, ParseError> {
    let (hour, minute, second) = try!(grammar::time(input));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

pub fn parse_datetime(input: &str,
                      time: DateTime<FixedOffset>)
                      -> Result<DateTime<FixedOffset>, ParseError> {
    let (year, month, day, hour, minute, second, tz) =
        try!(grammar::datetime(input));

    let year = year.unwrap_or(time.year());
    let month = month.unwrap_or(time.month());
    let day = day.unwrap_or(time.day());

    // set timezone
    let tz = tz.unwrap_or(time.offset().utc_minus_local());
    let tzo = FixedOffset::west(tz);
    let time = tzo.ymd(year, month, day);

    // set the time
    let time = time.and_hms(0, 0, 0);
    let time = try!(time.with_hour(hour).ok_or(ParseError::Hour));
    let time = try!(time.with_minute(minute).ok_or(ParseError::Minute));
    let time = try!(time.with_second(second as u32).ok_or(ParseError::Second));
    let nanosecond = second.fract() * 1_000_000_000.0;
    let time = try!(time.with_nanosecond(nanosecond as u32)
        .ok_or(ParseError::Nanosecond));
    Ok(time)
}

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

    #[test]
    fn parse_rounding_test() {
        assert_eq!(parse_rounding("+1D").unwrap(), Rounding::Up(86400.0));
        assert_eq!(parse_rounding("-1d").unwrap(), Rounding::Down(86400.0));
        assert_eq!(parse_rounding("=1d").unwrap(), Rounding::Half(86400.0));

        assert_eq!(parse_rounding("+1H").unwrap(), Rounding::Up(3600.0));
        assert_eq!(parse_rounding("-1h").unwrap(), Rounding::Down(3600.0));
        assert_eq!(parse_rounding("=1h").unwrap(), Rounding::Half(3600.0));

        assert_eq!(parse_rounding("+30M").unwrap(), Rounding::Up(1800.0));
        assert_eq!(parse_rounding("-30m").unwrap(), Rounding::Down(1800.0));
        assert_eq!(parse_rounding("=30m").unwrap(), Rounding::Half(1800.0));
        assert_eq!(parse_rounding("7.5").unwrap(), Rounding::Half(450.0));

        assert_eq!(parse_rounding("+30S").unwrap(), Rounding::Up(30.0));
        assert_eq!(parse_rounding("-30s").unwrap(), Rounding::Down(30.0));
        assert_eq!(parse_rounding("30s").unwrap(), Rounding::Half(30.0));
    }

    #[test]
    fn offset_test() {
        assert_eq!(grammar::offset("+2.3s").unwrap(), 2.3);
        assert_eq!(grammar::offset("-1.55h").unwrap(), -5580.0);
        assert_eq!(grammar::offset("+2:22").unwrap(), 8520.0);
        assert_eq!(grammar::offset("-2:22").unwrap(), -8520.0);
    }

    #[test]
    fn parse_offset_test() {
        let ctime = now();
        let n = ctime.checked_add_signed(Duration::seconds(5580)).unwrap();
        assert_eq!(parse_offset("+1.55h", ctime).unwrap(), n);
    }

    #[test]
    fn time_test() {
        assert_eq!(grammar::time("09:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055").unwrap(), (9, 22, 32.055));
        assert_eq!(grammar::time("9:22:32 Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22:32.055Pm").unwrap(), (21, 22, 32.055));
        assert_eq!(grammar::time("9:22 Pm").unwrap(), (21, 22, 0.0));
        // Might want to fail on these someday
        assert_eq!(grammar::time("9:22:32. Am").unwrap(), (9, 22, 32.0));
        assert_eq!(grammar::time("9:22: Pm").unwrap(), (21, 22, 0.0));
        assert_eq!(grammar::time("99:22:32").unwrap(), (99, 22, 32.0));
    }

    #[test]
    fn parse_time_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_time("9:22:31.9617 Pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_time("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }

    #[test]
    fn datetime_test() {
        assert_eq!(grammar::datetime("4/2 9:22 Pm").unwrap(),
                   (None, Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2 9:22 Pm").unwrap(),
                   (Some(2017), Some(4), Some(2), 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("2017-4/2").unwrap(),
                   (Some(2017), Some(4), Some(2), 0, 0, 0.0, None));
        assert_eq!(grammar::datetime("9:22 Pm").unwrap(),
                   (None, None, None, 21, 22, 0.0, None));
        assert_eq!(grammar::datetime("12:24 Pm").unwrap(),
                   (None, None, None, 12, 24, 0.0, None));
    }

    #[test]
    fn parse_datetime_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("9:22:31.9617 Pm", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T21:22:31.961700416-05:00");
        assert_eq!(parse_datetime("9:22", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30 9:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
        assert_eq!(parse_datetime("2017-4-30", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T00:00:00-05:00");
        // 12pm == midnight bug
        assert_eq!(parse_datetime("12:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T12:24:00-05:00");
        assert_eq!(parse_datetime("1:24pm", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T13:24:00-05:00");
        assert_eq!(parse_datetime("1:24am", ctime).unwrap().to_rfc3339(),
                   "2017-04-30T01:24:00-05:00");
    }

    #[test]
    #[should_panic(expected = "ParseError")]
    fn parse_datetime_seperator_test() {
        let ctime: DateTime<FixedOffset> =
            "2017-04-30T15:55:31.961764802-05:00".parse().unwrap();
        assert_eq!(parse_datetime("2017-4-309:22", ctime)
                       .unwrap()
                       .to_rfc3339(),
                   "2017-04-30T09:22:00-05:00");
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum Hashline {
    OpenEnv(Environment),
    PlainLine(String),
}

#[derive(Debug, PartialEq)]
pub struct Environment {
    indent_depth: usize,
    name: String,
    opts: String,
    comment: String,
    is_list_like: bool,
}

impl Environment {
    pub fn latex_begin(&self) -> String {
        format!(
            r"{dummy:ind$}\begin{{{name}}}{opts}{comment_sep}{comment}",
            name = self.name,
            opts = self.opts,
            comment = self.comment,
            dummy = "",
            ind = self.indent_depth,
            comment_sep = if self.comment.is_empty() { "" } else { " " },
        )
    }

    pub fn latex_end(&self) -> String {
        format!(
            r"{dummy:ind$}\end{{{name}}}",
            name = self.name,
            dummy = "",
            ind = self.indent_depth,
        )
    }

    pub fn indent_depth(&self) -> usize {
        self.indent_depth
    }

    pub fn is_list_like(&self) -> bool {
        self.is_list_like
    }
}

#[inline]
fn list_env_parser(input: &str) -> nom::IResult<&str, ()> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::opt;

    let (input, _) = opt(is_a(" "))(input)?;
    let (input, _) = alt((tag("itemize"), tag("enumerate"), tag("description")))(input)?;
    Ok((input, ()))
}

#[inline]
fn escaped_colon(input: &str) -> nom::IResult<&str, &str> {
    use nom::bytes::complete::tag;
    use nom::sequence::preceded;

    preceded(tag("\\"), tag(":"))(input)
}

#[inline]
fn name_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((escaped_colon, tag("\\"), is_not("\\:%([{ \t")))(input)
}

#[inline]
fn opts_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((escaped_colon, tag("\\%"), tag("\\"), is_not("\\:%")))(input)
}

#[inline]
fn args_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((tag("\\%"), tag("\\"), is_not("\\%")))(input)
}

fn hashline_parser(input: &str) -> nom::IResult<&str, Hashline> {
    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::{opt, rest};
    use nom::multi::{fold_many0, fold_many1};

    let (input, res) = opt(is_a(" "))(input)?;
    let ws = res.unwrap_or("");
    let (input, _) = tag("# ")(input)?;
    let (input, name) = fold_many1(
        name_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, opts) = fold_many0(
        opts_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, _) = tag(":")(input)?;
    let (input, args) = fold_many0(
        args_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, comment) = rest(input)?;
    Ok((input, hashline_helper(&ws, &name, &opts, &args, comment)))
}

#[inline]
fn hashline_helper(ws: &str, name: &str, opts: &str, args: &str, comment: &str) -> Hashline {
    use self::Hashline::{OpenEnv, PlainLine};

    // It is ok to unwrap here, since we have checked for UTF-8 when we read the file
    let name_trimmed = name.trim();
    let opts_trimmed = opts.trim();
    let args_trimmed = args.trim();
    let comment_trimmed = comment.trim();

    if args_trimmed.is_empty() {
        // If no args are given, it's an environment
        let env = Environment {
            indent_depth: ws.len(),
            name: name_trimmed.to_string(),
            opts: opts_trimmed.to_string(),
            comment: comment_trimmed.to_string(),
            is_list_like: list_env_parser(name).is_ok(),
        };
        OpenEnv(env)
    } else {
        // If there are some args, it's a single-line command
        PlainLine(format!(
            r"{indent}\{name}{opts}{{{args}}}{comment_sep}{comment}",
            indent = ws,
            name = name_trimmed,
            opts = opts_trimmed,
            args = args_trimmed,
            comment_sep = if comment_trimmed.is_empty() { "" } else { " " },
            comment = comment_trimmed,
        ))
    }
}

// Hashline processing
#[inline]
fn process_hashline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    match hashline_parser(line.as_ref()) {
        Ok((_, r)) => Some(r),
        Err(_) => None,
    }
}

// Itemline parsers
fn itemline_parser(input: &str) -> nom::IResult<&str, Hashline> {
    use self::Hashline::PlainLine;

    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::{opt, rest};

    let (input, indent) = opt(is_a(" "))(input)?;
    let (input, _) = tag("*")(input)?;
    let (input, item) = rest(input)?;

    Ok((
        input,
        PlainLine(format!(
            r"{indent}\item{item_sep}{content}",
            indent = indent.unwrap_or(""),
            content = item.trim(),
            item_sep = if item.trim().is_empty() { "" } else { " " },
        )),
    ))
}

// Itemline processing
#[inline]
fn process_itemline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    match itemline_parser(line.as_ref()) {
        Ok((_, r)) => Some(r),
        Err(_) => None,
    }
}

// Fully process line
pub fn process_line<T>(line: T, list_like_active: bool) -> Hashline
where
    T: AsRef<str>,
{
    use self::Hashline::PlainLine;

    match (process_hashline(&line), list_like_active) {
        (Some(r), _) => r,
        (None, true) => {
            process_itemline(&line).unwrap_or_else(|| PlainLine(line.as_ref().to_string()))
        }
        (None, false) => PlainLine(line.as_ref().to_string()),
    }
}

// LCOV_EXCL_START
#[cfg(test)]
mod tests {
    #[test]
    fn hashline_helper_plain_lines() {
        use super::{hashline_helper, Hashline};

        assert_eq!(
            hashline_helper("", "foo", "", "bar", ""),
            Hashline::PlainLine("\\foo{bar}".to_string())
        );
        assert_eq!(
            hashline_helper("  ", "foo", "", "bar", "qux"),
            Hashline::PlainLine("  \\foo{bar} qux".to_string())
        );
        assert_eq!(
            hashline_helper("    ", "foo", "bar", "qux", ""),
            Hashline::PlainLine("    \\foobar{qux}".to_string())
        );
    }

    #[test]
    fn hashline_helper_environments() {
        use super::{hashline_helper, Environment, Hashline};

        let env_ref_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("", "foo", "bar", "", ""),
            Hashline::OpenEnv(env_ref_1)
        );

        let env_ref_2 = Environment {
            indent_depth: 2,
            name: "foo".to_string(),
            opts: "".to_string(),
            comment: "bar".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("  ", "foo", "", "", "bar"),
            Hashline::OpenEnv(env_ref_2)
        );

        let env_ref_3 = Environment {
            indent_depth: 4,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "qux".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("    ", "foo", "bar", "", "qux"),
            Hashline::OpenEnv(env_ref_3)
        );

        let env_ref_4 = Environment {
            indent_depth: 0,
            name: "itemize".to_string(),
            opts: "bar".to_string(),
            comment: "qux".to_string(),
            is_list_like: true,
        };
        assert_eq!(
            hashline_helper("", "itemize", "bar", "", "qux"),
            Hashline::OpenEnv(env_ref_4)
        );
    }

    #[test]
    fn process_itemline() {
        use super::{process_itemline, Hashline};

        // Valid itemlines
        assert_eq!(
            process_itemline("*"),
            Some(Hashline::PlainLine("\\item".to_string()))
        );
        assert_eq!(
            process_itemline("*  "),
            Some(Hashline::PlainLine("\\item".to_string()))
        );
        assert_eq!(
            process_itemline("  *"),
            Some(Hashline::PlainLine("  \\item".to_string()))
        );
        assert_eq!(
            process_itemline("  *  "),
            Some(Hashline::PlainLine("  \\item".to_string()))
        );
        assert_eq!(
            process_itemline("* foo"),
            Some(Hashline::PlainLine("\\item foo".to_string()))
        );
        assert_eq!(
            process_itemline("  * bar"),
            Some(Hashline::PlainLine("  \\item bar".to_string()))
        );
        assert_eq!(
            process_itemline("****"),
            Some(Hashline::PlainLine("\\item ***".to_string()))
        );

        // Not an itemline
        assert_eq!(process_itemline("  baz"), None);
        assert_eq!(process_itemline("qux *"), None);
        assert_eq!(process_itemline("  abc * def"), None);
        assert_eq!(process_itemline("  \\*  "), None);
        assert_eq!(process_itemline("\\*  "), None);
    }

    #[test]
    fn environment_methods() {
        use super::Environment;

        let env_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "% baz".to_string(),
            is_list_like: true,
        };

        assert_eq!(env_1.latex_begin(), "\\begin{foo}bar % baz");
        assert_eq!(env_1.latex_end(), "\\end{foo}");
        assert_eq!(env_1.is_list_like(), true);
        assert_eq!(env_1.indent_depth(), 0);

        let env_2 = Environment {
            indent_depth: 2,
            name: "abc".to_string(),
            opts: "def".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };

        assert_eq!(env_2.latex_begin(), "  \\begin{abc}def");
        assert_eq!(env_2.latex_end(), "  \\end{abc}");
        assert_eq!(env_2.is_list_like(), false);
        assert_eq!(env_2.indent_depth(), 2);
    }

    #[test]
    fn list_env_parser() {
        use super::list_env_parser;
        use nom::error::ErrorKind::Tag;
        use nom::Err::Error;

        assert_eq!(list_env_parser("itemize"), Ok(("", ())));
        assert_eq!(list_env_parser("enumerate*"), Ok(("*", ())));
        assert_eq!(list_env_parser("    description  *"), Ok(("  *", ())));
        assert_eq!(list_env_parser("item"), Err(Error(("item", Tag))));
        assert_eq!(list_env_parser("   foobar"), Err(Error(("foobar", Tag))));
    }

    #[test]
    fn escaped_colon() {
        use super::escaped_colon;
        use nom::error::ErrorKind::Tag;
        use nom::Err::Error;

        assert_eq!(escaped_colon(r"\:"), Ok(("", ":")));
        assert_eq!(escaped_colon(""), Err(Error(("", Tag))));
        assert_eq!(escaped_colon("ab"), Err(Error(("ab", Tag))));
    }

    #[test]
    fn name_parser() {
        use super::name_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(name_parser("abc"), Ok(("", "abc")));
        assert_eq!(name_parser(r"abc\:"), Ok((r"\:", "abc")));
        assert_eq!(name_parser(r"\:abc"), Ok(("abc", ":")));
        assert_eq!(name_parser(" "), Err(Error((" ", IsNot))));
        assert_eq!(name_parser(""), Err(Error(("", IsNot))));

        for e in vec![":E", "%E", "(E", "[E", "{E", " E", "\tE"] {
            assert_eq!(name_parser(e), Err(Error((e, IsNot))));
        }
    }

    #[test]
    fn opts_parser() {
        use super::opts_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(opts_parser(r"abc"), Ok(("", "abc")));
        assert_eq!(opts_parser(r"\:abc"), Ok(("abc", ":")));
        assert_eq!(opts_parser(r"\%abc"), Ok(("abc", r"\%")));
        assert_eq!(opts_parser(r"(abc"), Ok(("", "(abc")));
        assert_eq!(opts_parser(r"[abc"), Ok(("", "[abc")));
        assert_eq!(opts_parser(r" abc"), Ok(("", " abc")));
        assert_eq!(opts_parser(""), Err(Error(("", IsNot))));

        for e in vec![":E", "%E"] {
            assert_eq!(opts_parser(e), Err(Error((e, IsNot))));
        }
    }

    #[test]
    fn args_parser() {
        use super::args_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(args_parser(r"abc"), Ok(("", "abc")));
        assert_eq!(args_parser(r"\:abc"), Ok((":abc", r"\")));
        assert_eq!(args_parser(r"\%abc"), Ok(("abc", r"\%")));
        assert_eq!(args_parser(r"(abc"), Ok(("", "(abc")));
        assert_eq!(args_parser(r"[abc"), Ok(("", "[abc")));
        assert_eq!(args_parser(r" abc"), Ok(("", " abc")));
        assert_eq!(args_parser(""), Err(Error(("", IsNot))));
        assert_eq!(args_parser("%E"), Err(Error(("%E", IsNot))));
    }
}
// LCOV_EXCL_STOP
<commit_msg>Add unit tests for escaped colon<commit_after>#[derive(Debug, PartialEq)]
pub enum Hashline {
    OpenEnv(Environment),
    PlainLine(String),
}

#[derive(Debug, PartialEq)]
pub struct Environment {
    indent_depth: usize,
    name: String,
    opts: String,
    comment: String,
    is_list_like: bool,
}

impl Environment {
    pub fn latex_begin(&self) -> String {
        format!(
            r"{dummy:ind$}\begin{{{name}}}{opts}{comment_sep}{comment}",
            name = self.name,
            opts = self.opts,
            comment = self.comment,
            dummy = "",
            ind = self.indent_depth,
            comment_sep = if self.comment.is_empty() { "" } else { " " },
        )
    }

    pub fn latex_end(&self) -> String {
        format!(
            r"{dummy:ind$}\end{{{name}}}",
            name = self.name,
            dummy = "",
            ind = self.indent_depth,
        )
    }

    pub fn indent_depth(&self) -> usize {
        self.indent_depth
    }

    pub fn is_list_like(&self) -> bool {
        self.is_list_like
    }
}

#[inline]
fn list_env_parser(input: &str) -> nom::IResult<&str, ()> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::opt;

    let (input, _) = opt(is_a(" "))(input)?;
    let (input, _) = alt((tag("itemize"), tag("enumerate"), tag("description")))(input)?;
    Ok((input, ()))
}

#[inline]
fn escaped_colon(input: &str) -> nom::IResult<&str, &str> {
    use nom::bytes::complete::tag;
    use nom::sequence::preceded;

    preceded(tag("\\"), tag(":"))(input)
}

#[inline]
fn name_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((escaped_colon, tag("\\"), is_not("\\:%([{ \t")))(input)
}

#[inline]
fn opts_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((escaped_colon, tag("\\%"), tag("\\"), is_not("\\:%")))(input)
}

#[inline]
fn args_parser(input: &str) -> nom::IResult<&str, &str> {
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag};

    alt((tag("\\%"), tag("\\"), is_not("\\%")))(input)
}

fn hashline_parser(input: &str) -> nom::IResult<&str, Hashline> {
    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::{opt, rest};
    use nom::multi::{fold_many0, fold_many1};

    let (input, res) = opt(is_a(" "))(input)?;
    let ws = res.unwrap_or("");
    let (input, _) = tag("# ")(input)?;
    let (input, name) = fold_many1(
        name_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, opts) = fold_many0(
        opts_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, _) = tag(":")(input)?;
    let (input, args) = fold_many0(
        args_parser,
        String::with_capacity(input.len()),
        |mut acc: String, item| {
            acc.push_str(item);
            acc
        },
    )(input)?;
    let (input, comment) = rest(input)?;
    Ok((input, hashline_helper(&ws, &name, &opts, &args, comment)))
}

#[inline]
fn hashline_helper(ws: &str, name: &str, opts: &str, args: &str, comment: &str) -> Hashline {
    use self::Hashline::{OpenEnv, PlainLine};

    // It is ok to unwrap here, since we have checked for UTF-8 when we read the file
    let name_trimmed = name.trim();
    let opts_trimmed = opts.trim();
    let args_trimmed = args.trim();
    let comment_trimmed = comment.trim();

    if args_trimmed.is_empty() {
        // If no args are given, it's an environment
        let env = Environment {
            indent_depth: ws.len(),
            name: name_trimmed.to_string(),
            opts: opts_trimmed.to_string(),
            comment: comment_trimmed.to_string(),
            is_list_like: list_env_parser(name).is_ok(),
        };
        OpenEnv(env)
    } else {
        // If there are some args, it's a single-line command
        PlainLine(format!(
            r"{indent}\{name}{opts}{{{args}}}{comment_sep}{comment}",
            indent = ws,
            name = name_trimmed,
            opts = opts_trimmed,
            args = args_trimmed,
            comment_sep = if comment_trimmed.is_empty() { "" } else { " " },
            comment = comment_trimmed,
        ))
    }
}

// Hashline processing
#[inline]
fn process_hashline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    match hashline_parser(line.as_ref()) {
        Ok((_, r)) => Some(r),
        Err(_) => None,
    }
}

// Itemline parsers
fn itemline_parser(input: &str) -> nom::IResult<&str, Hashline> {
    use self::Hashline::PlainLine;

    use nom::bytes::complete::{is_a, tag};
    use nom::combinator::{opt, rest};

    let (input, indent) = opt(is_a(" "))(input)?;
    let (input, _) = tag("*")(input)?;
    let (input, item) = rest(input)?;

    Ok((
        input,
        PlainLine(format!(
            r"{indent}\item{item_sep}{content}",
            indent = indent.unwrap_or(""),
            content = item.trim(),
            item_sep = if item.trim().is_empty() { "" } else { " " },
        )),
    ))
}

// Itemline processing
#[inline]
fn process_itemline<T: AsRef<str>>(line: T) -> Option<Hashline> {
    match itemline_parser(line.as_ref()) {
        Ok((_, r)) => Some(r),
        Err(_) => None,
    }
}

// Fully process line
pub fn process_line<T>(line: T, list_like_active: bool) -> Hashline
where
    T: AsRef<str>,
{
    use self::Hashline::PlainLine;

    match (process_hashline(&line), list_like_active) {
        (Some(r), _) => r,
        (None, true) => {
            process_itemline(&line).unwrap_or_else(|| PlainLine(line.as_ref().to_string()))
        }
        (None, false) => PlainLine(line.as_ref().to_string()),
    }
}

// LCOV_EXCL_START
#[cfg(test)]
mod tests {
    #[test]
    fn hashline_helper_plain_lines() {
        use super::{hashline_helper, Hashline};

        assert_eq!(
            hashline_helper("", "foo", "", "bar", ""),
            Hashline::PlainLine("\\foo{bar}".to_string())
        );
        assert_eq!(
            hashline_helper("  ", "foo", "", "bar", "qux"),
            Hashline::PlainLine("  \\foo{bar} qux".to_string())
        );
        assert_eq!(
            hashline_helper("    ", "foo", "bar", "qux", ""),
            Hashline::PlainLine("    \\foobar{qux}".to_string())
        );
    }

    #[test]
    fn hashline_helper_environments() {
        use super::{hashline_helper, Environment, Hashline};

        let env_ref_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("", "foo", "bar", "", ""),
            Hashline::OpenEnv(env_ref_1)
        );

        let env_ref_2 = Environment {
            indent_depth: 2,
            name: "foo".to_string(),
            opts: "".to_string(),
            comment: "bar".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("  ", "foo", "", "", "bar"),
            Hashline::OpenEnv(env_ref_2)
        );

        let env_ref_3 = Environment {
            indent_depth: 4,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "qux".to_string(),
            is_list_like: false,
        };
        assert_eq!(
            hashline_helper("    ", "foo", "bar", "", "qux"),
            Hashline::OpenEnv(env_ref_3)
        );

        let env_ref_4 = Environment {
            indent_depth: 0,
            name: "itemize".to_string(),
            opts: "bar".to_string(),
            comment: "qux".to_string(),
            is_list_like: true,
        };
        assert_eq!(
            hashline_helper("", "itemize", "bar", "", "qux"),
            Hashline::OpenEnv(env_ref_4)
        );
    }

    #[test]
    fn process_itemline() {
        use super::{process_itemline, Hashline};

        // Valid itemlines
        assert_eq!(
            process_itemline("*"),
            Some(Hashline::PlainLine("\\item".to_string()))
        );
        assert_eq!(
            process_itemline("*  "),
            Some(Hashline::PlainLine("\\item".to_string()))
        );
        assert_eq!(
            process_itemline("  *"),
            Some(Hashline::PlainLine("  \\item".to_string()))
        );
        assert_eq!(
            process_itemline("  *  "),
            Some(Hashline::PlainLine("  \\item".to_string()))
        );
        assert_eq!(
            process_itemline("* foo"),
            Some(Hashline::PlainLine("\\item foo".to_string()))
        );
        assert_eq!(
            process_itemline("  * bar"),
            Some(Hashline::PlainLine("  \\item bar".to_string()))
        );
        assert_eq!(
            process_itemline("****"),
            Some(Hashline::PlainLine("\\item ***".to_string()))
        );

        // Not an itemline
        assert_eq!(process_itemline("  baz"), None);
        assert_eq!(process_itemline("qux *"), None);
        assert_eq!(process_itemline("  abc * def"), None);
        assert_eq!(process_itemline("  \\*  "), None);
        assert_eq!(process_itemline("\\*  "), None);
    }

    #[test]
    fn environment_methods() {
        use super::Environment;

        let env_1 = Environment {
            indent_depth: 0,
            name: "foo".to_string(),
            opts: "bar".to_string(),
            comment: "% baz".to_string(),
            is_list_like: true,
        };

        assert_eq!(env_1.latex_begin(), "\\begin{foo}bar % baz");
        assert_eq!(env_1.latex_end(), "\\end{foo}");
        assert_eq!(env_1.is_list_like(), true);
        assert_eq!(env_1.indent_depth(), 0);

        let env_2 = Environment {
            indent_depth: 2,
            name: "abc".to_string(),
            opts: "def".to_string(),
            comment: "".to_string(),
            is_list_like: false,
        };

        assert_eq!(env_2.latex_begin(), "  \\begin{abc}def");
        assert_eq!(env_2.latex_end(), "  \\end{abc}");
        assert_eq!(env_2.is_list_like(), false);
        assert_eq!(env_2.indent_depth(), 2);
    }

    #[test]
    fn list_env_parser() {
        use super::list_env_parser;
        use nom::error::ErrorKind::Tag;
        use nom::Err::Error;

        assert_eq!(list_env_parser("itemize"), Ok(("", ())));
        assert_eq!(list_env_parser("enumerate*"), Ok(("*", ())));
        assert_eq!(list_env_parser("    description  *"), Ok(("  *", ())));
        assert_eq!(list_env_parser("item"), Err(Error(("item", Tag))));
        assert_eq!(list_env_parser("   foobar"), Err(Error(("foobar", Tag))));
    }

    #[test]
    fn escaped_colon() {
        use super::escaped_colon;
        use nom::error::ErrorKind::Tag;
        use nom::Err::Error;

        assert_eq!(escaped_colon(r"\:"), Ok(("", ":")));
        assert_eq!(escaped_colon(r"\"), Err(Error((r"", Tag))));
        assert_eq!(escaped_colon(r":\"), Err(Error((r":\", Tag))));
        assert_eq!(escaped_colon(r"\\"), Err(Error((r"\", Tag))));
        assert_eq!(escaped_colon(r"\a"), Err(Error((r"a", Tag))));
        assert_eq!(escaped_colon(r"\;"), Err(Error((r";", Tag))));
        assert_eq!(escaped_colon(""), Err(Error(("", Tag))));
        assert_eq!(escaped_colon("ab"), Err(Error(("ab", Tag))));
    }

    #[test]
    fn name_parser() {
        use super::name_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(name_parser("abc"), Ok(("", "abc")));
        assert_eq!(name_parser(r"abc\:"), Ok((r"\:", "abc")));
        assert_eq!(name_parser(r"\:abc"), Ok(("abc", ":")));
        assert_eq!(name_parser(" "), Err(Error((" ", IsNot))));
        assert_eq!(name_parser(""), Err(Error(("", IsNot))));

        for e in vec![":E", "%E", "(E", "[E", "{E", " E", "\tE"] {
            assert_eq!(name_parser(e), Err(Error((e, IsNot))));
        }
    }

    #[test]
    fn opts_parser() {
        use super::opts_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(opts_parser(r"abc"), Ok(("", "abc")));
        assert_eq!(opts_parser(r"\:abc"), Ok(("abc", ":")));
        assert_eq!(opts_parser(r"\%abc"), Ok(("abc", r"\%")));
        assert_eq!(opts_parser(r"(abc"), Ok(("", "(abc")));
        assert_eq!(opts_parser(r"[abc"), Ok(("", "[abc")));
        assert_eq!(opts_parser(r" abc"), Ok(("", " abc")));
        assert_eq!(opts_parser(""), Err(Error(("", IsNot))));

        for e in vec![":E", "%E"] {
            assert_eq!(opts_parser(e), Err(Error((e, IsNot))));
        }
    }

    #[test]
    fn args_parser() {
        use super::args_parser;
        use nom::error::ErrorKind::IsNot;
        use nom::Err::Error;

        assert_eq!(args_parser(r"abc"), Ok(("", "abc")));
        assert_eq!(args_parser(r"\:abc"), Ok((":abc", r"\")));
        assert_eq!(args_parser(r"\%abc"), Ok(("abc", r"\%")));
        assert_eq!(args_parser(r"(abc"), Ok(("", "(abc")));
        assert_eq!(args_parser(r"[abc"), Ok(("", "[abc")));
        assert_eq!(args_parser(r" abc"), Ok(("", " abc")));
        assert_eq!(args_parser(""), Err(Error(("", IsNot))));
        assert_eq!(args_parser("%E"), Err(Error(("%E", IsNot))));
    }
}
// LCOV_EXCL_STOP
<|endoftext|>