<commit_before>#[macro_use]
extern crate log;

#[cfg(windows)]
extern crate pdcurses;
#[cfg(unix)]
extern crate ncurses;

use std::ffi::CString;

#[cfg(windows)]
use pdcurses as curses;
#[cfg(windows)]
pub use pdcurses::chtype;
#[cfg(unix)]
use ncurses::ll as curses;
#[cfg(unix)]
pub use ncurses::ll::chtype;

mod input;
pub use self::input::*;

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use self::windows::*;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::*;

pub const OK: i32 = 0;
pub const ERR: i32 = -1;

#[derive(Copy, Clone, Debug)]
pub struct Window {
    #[cfg(windows)]
    _window: *mut curses::WINDOW,
    #[cfg(unix)]
    _window: curses::WINDOW,
}

impl Window {
    /// Sets the current attributes of the given window to attributes.
    pub fn attrset(&self, attributes: chtype) -> i32 {
        _attrset(self._window, attributes)
    }

    ///Not only change the background, but apply it immediately to every cell in the window.
    pub fn bkgd(&self, ch: chtype) -> i32 {
        unsafe { curses::wbkgd(self._window, ch) }
    }

    pub fn draw_box(&self, verch: chtype, horch: chtype) -> i32 {
        _draw_box(self._window, verch, horch)
    }

    /// Copies blanks (i.e. the background chtype) to every cell of the window.
    pub fn erase(&self) -> i32 {
        unsafe { curses::werase(self._window) }
    }

    /// Read a character from the terminal associated with the window.
    ///
    /// In nodelay mode, if there is no input waiting, None is returned. In delay mode,
    /// the program will hang until the system  passes text through to the program. Depending on
    /// the setting of cbreak(), this will be after one character or after the first newline.
    /// Unless noecho() has been set, the character will also be echoed into the designated window.
    ///
    /// If keypad() is TRUE, and a function key is pressed, the token for that function key will be
    /// returned instead of the raw characters.
    /// If nodelay(win, TRUE) has been called on the window and no input is waiting, None is
    /// returned.
    pub fn getch(&self) -> Option<Input> {
        let i = unsafe { curses::wgetch(self._window) };
        if i < 0 {
            None
        } else if i <= u8::max_value() as i32 {
            Some(Input::Character(i as u8 as char))
        } else {
            Some(to_special_keycode(i))
        }
    }

    /// Return the maximum x value of this Window, in other words the number of columns.
    pub fn get_max_x(&self) -> i32 {
        unsafe { curses::getmaxx(self._window) }
    }

    /// Return the maximum y value of this Window, in other words the number of rows.
    pub fn get_max_y(&self) -> i32 {
        unsafe { curses::getmaxy(self._window) }
    }

    /// Controls whether getch() returns function/special keys as single key codes (e.g., the left
    /// arrow key as KEY_LEFT).
    ///
    /// Per X/Open, the default for keypad mode is OFF. You'll probably want it on. With keypad
    /// mode off, if a special key is pressed, getch() does nothing or returns ERR.
    pub fn keypad(&self, use_keypad: bool) -> i32 {
        unsafe { curses::keypad(self._window, use_keypad as u8) }
    }

    /// The cursor associated with the window is moved to the given location.
    ///
    /// This does not move the physical cursor of the terminal until refresh() is called.  The
    /// position specified is relative to the upper left corner of the window, which is (0,0).
    pub fn mv(&self, y: i32, x: i32) -> i32 {
        unsafe { curses::wmove(self._window, y, x) }
    }

    /// moves the cursor to the specified position and adds ch to the specified window
    pub fn mvaddch(&self, y: i32, x: i32, ch: char) -> i32 {
        unsafe { curses::mvwaddch(self._window, y, x, ch as chtype) }
    }

    /// Write all the characters of the string str to the given window. The functionality is
    /// similar to calling waddch() once for each character in the string.
    pub fn mvaddstr(&self, y: i32, x: i32, string: &str) -> i32 {
        let s = CString::new(string).unwrap();
        unsafe { curses::mvwaddstr(self._window, y, x, s.as_ptr()) }
    }

    ///Add a string to the window at the current cursor position.
    pub fn printw(&self, string: &str) -> i32 {
        let s = CString::new(string).unwrap();
        unsafe { curses::wprintw(self._window, s.as_ptr()) }
    }

    /// Copies the named window to the physical terminal screen, taking into account what
    /// is already there in order to optimize cursor movement.
    ///
    /// This function must be called to get any output on the terminal, as other routines only
    /// manipulate data structures. Unless leaveok() has been enabled, the physical cursor of the
    /// terminal is left at the location of the window's cursor.
    pub fn refresh(&self) -> i32 {
        unsafe { curses::wrefresh(self._window) }
    }

    /// Controls whether wgetch() is a non-blocking call. If the option is enabled, and
    /// no input is ready, wgetch() will return ERR. If disabled, wgetch() will hang until input is
    /// ready.
    pub fn nodelay(&self, enabled: bool) -> i32 {
        unsafe { curses::nodelay(self._window, enabled as u8) as i32 }
    }

    /// Set blocking or non-blocking reads for the specified window.
    ///
    /// The delay is measured in milliseconds. If it's negative, a blocking read is used; if zero,
    /// then non-blocking reads are done -- if no input is waiting, ERR is returned immediately.
    /// If the delay is positive, the read blocks for the delay period; if the period expires,
    /// ERR is returned.
    pub fn timeout(&self, milliseconds: i32) {
        unsafe { curses::wtimeout(self._window, milliseconds) }
    }
}

/// Set cbreak mode.
///
/// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
/// character processing is not performed.  In nocbreak mode, typed characters are buffered until
/// a newline or carriage return. Interrupt and flow control characters are unaffected by this
/// mode.
pub fn cbreak() -> i32 {
    unsafe { curses::cbreak() }
}

/// Alters the appearance of the cursor.
///
///  A visibility of 0 makes it disappear; 1 makes it appear "normal" (usually an underline) and 2
/// makes it "highly visible" (usually a block).
pub fn curs_set(visibility: i32) -> i32 {
    unsafe { curses::curs_set(visibility) }
}

/// Should be called before exiting or escaping from curses mode temporarily.
///
/// It will restore tty modes, move the cursor to the lower left corner of the screen and reset the
/// terminal into the proper non-visual mode.  To resume curses after a temporary escape, call
/// refresh() or doupdate().
pub fn endwin() -> i32 {
    unsafe { curses::endwin() }
}

/// Indicates if the terminal supports, and can maniplulate color.
pub fn has_colors() -> bool {
    unsafe { curses::has_colors() > 0 }
}

/// Initialize the curses system, this must be the first function that is called.
///
/// Returns a Window struct that is used to access Window specific functions.
pub fn initscr() -> Window {
    let window_pointer = unsafe { curses::initscr() };
    Window { _window: window_pointer }
}

/// Changes the definition of a color-pair.
///
/// It takes three arguments: the number of the color-pair to be redefined, and the new values of
/// the foreground and background colors. The pair number must be between 0 and COLOR_PAIRS - 1,
/// inclusive. The foreground and background must be between 0 and COLORS - 1, inclusive. If the
/// color pair was previously initialized, the screen is refreshed, and all occurrences of that
/// color-pair are changed to the new definition.
pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 {
    unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 }
}

/// Suspends the program for the specified number of milliseconds.
pub fn napms(ms: i32) -> i32 {
    unsafe { curses::napms(ms) }
}

/// Creates a new window with the given number of lines, nlines and columns, ncols.
///
/// The upper left corner of the window is at line begy, column begx. If nlines is zero, it
/// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling
/// newwin(0, 0, 0, 0).
pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window {
    let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) };
    Window { _window: window_pointer }
}

/// Enables the translation of a carriage return into a newline on input.
///
/// nonl() disables this. Initially, the translation does occur.
pub fn nl() -> i32 {
    unsafe { curses::nl() }
}

/// Disables echoing typed characters.
///
/// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
/// type-ahead.
pub fn noecho() -> i32 {
    unsafe { curses::noecho() }
}

/// Attempts to resize the screen to the given size.
///
/// resize_term() is effectively two functions: When called with nonzero values for nlines and
/// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely
/// adjusts the internal structures to match the current size after the screen is resized by the
/// user. If you want to support user resizing, you should check for getch() returning KEY_RESIZE,
/// and/or call is_termresized() at appropriate times; if either condition occurs, call
/// resize_term(0, 0). Then, with either user or programmatic resizing, you'll have to resize any
/// windows you've created.
pub fn resize_term(nlines: i32, ncols: i32) -> i32 {
    _resize_term(nlines, ncols)
}

/// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan,
/// and white), and two global variables; COLORS and COLOR_PAIRS (respectively defining the
/// maximum number of colors and color-pairs the terminal is capable of displaying).
pub fn start_color() -> i32 {
    unsafe { curses::start_color() as i32 }
}

/// Allows the use of -1 as a foreground or background color with init_pair().
///
/// Calls assume_default_colors(-1, -1); -1 represents the foreground or background color that
/// the terminal had at startup.
pub fn use_default_colors() -> i32 {
    unsafe { curses::use_default_colors() }
}
<commit_msg>Moved nodelay function to the right place<commit_after>#[macro_use]
extern crate log;

#[cfg(windows)]
extern crate pdcurses;
#[cfg(unix)]
extern crate ncurses;

use std::ffi::CString;

#[cfg(windows)]
use pdcurses as curses;
#[cfg(windows)]
pub use pdcurses::chtype;
#[cfg(unix)]
use ncurses::ll as curses;
#[cfg(unix)]
pub use ncurses::ll::chtype;

mod input;
pub use self::input::*;

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use self::windows::*;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::*;

pub const OK: i32 = 0;
pub const ERR: i32 = -1;

#[derive(Copy, Clone, Debug)]
pub struct Window {
    #[cfg(windows)]
    _window: *mut curses::WINDOW,
    #[cfg(unix)]
    _window: curses::WINDOW,
}

impl Window {
    /// Sets the current attributes of the given window to attributes.
    pub fn attrset(&self, attributes: chtype) -> i32 {
        _attrset(self._window, attributes)
    }

    ///Not only change the background, but apply it immediately to every cell in the window.
    pub fn bkgd(&self, ch: chtype) -> i32 {
        unsafe { curses::wbkgd(self._window, ch) }
    }

    pub fn draw_box(&self, verch: chtype, horch: chtype) -> i32 {
        _draw_box(self._window, verch, horch)
    }

    /// Copies blanks (i.e. the background chtype) to every cell of the window.
    pub fn erase(&self) -> i32 {
        unsafe { curses::werase(self._window) }
    }

    /// Read a character from the terminal associated with the window.
    ///
    /// In nodelay mode, if there is no input waiting, None is returned. In delay mode,
    /// the program will hang until the system  passes text through to the program. Depending on
    /// the setting of cbreak(), this will be after one character or after the first newline.
    /// Unless noecho() has been set, the character will also be echoed into the designated window.
    ///
    /// If keypad() is TRUE, and a function key is pressed, the token for that function key will be
    /// returned instead of the raw characters.
    /// If nodelay(win, TRUE) has been called on the window and no input is waiting, None is
    /// returned.
    pub fn getch(&self) -> Option<Input> {
        let i = unsafe { curses::wgetch(self._window) };
        if i < 0 {
            None
        } else if i <= u8::max_value() as i32 {
            Some(Input::Character(i as u8 as char))
        } else {
            Some(to_special_keycode(i))
        }
    }

    /// Return the maximum x value of this Window, in other words the number of columns.
    pub fn get_max_x(&self) -> i32 {
        unsafe { curses::getmaxx(self._window) }
    }

    /// Return the maximum y value of this Window, in other words the number of rows.
    pub fn get_max_y(&self) -> i32 {
        unsafe { curses::getmaxy(self._window) }
    }

    /// Controls whether getch() returns function/special keys as single key codes (e.g., the left
    /// arrow key as KEY_LEFT).
    ///
    /// Per X/Open, the default for keypad mode is OFF. You'll probably want it on. With keypad
    /// mode off, if a special key is pressed, getch() does nothing or returns ERR.
    pub fn keypad(&self, use_keypad: bool) -> i32 {
        unsafe { curses::keypad(self._window, use_keypad as u8) }
    }

    /// The cursor associated with the window is moved to the given location.
    ///
    /// This does not move the physical cursor of the terminal until refresh() is called.  The
    /// position specified is relative to the upper left corner of the window, which is (0,0).
    pub fn mv(&self, y: i32, x: i32) -> i32 {
        unsafe { curses::wmove(self._window, y, x) }
    }

    /// moves the cursor to the specified position and adds ch to the specified window
    pub fn mvaddch(&self, y: i32, x: i32, ch: char) -> i32 {
        unsafe { curses::mvwaddch(self._window, y, x, ch as chtype) }
    }

    /// Write all the characters of the string str to the given window. The functionality is
    /// similar to calling waddch() once for each character in the string.
    pub fn mvaddstr(&self, y: i32, x: i32, string: &str) -> i32 {
        let s = CString::new(string).unwrap();
        unsafe { curses::mvwaddstr(self._window, y, x, s.as_ptr()) }
    }

    /// Controls whether wgetch() is a non-blocking call. If the option is enabled, and
    /// no input is ready, wgetch() will return ERR. If disabled, wgetch() will hang until input is
    /// ready.
    pub fn nodelay(&self, enabled: bool) -> i32 {
        unsafe { curses::nodelay(self._window, enabled as u8) as i32 }
    }

    ///Add a string to the window at the current cursor position.
    pub fn printw(&self, string: &str) -> i32 {
        let s = CString::new(string).unwrap();
        unsafe { curses::wprintw(self._window, s.as_ptr()) }
    }

    /// Copies the named window to the physical terminal screen, taking into account what
    /// is already there in order to optimize cursor movement.
    ///
    /// This function must be called to get any output on the terminal, as other routines only
    /// manipulate data structures. Unless leaveok() has been enabled, the physical cursor of the
    /// terminal is left at the location of the window's cursor.
    pub fn refresh(&self) -> i32 {
        unsafe { curses::wrefresh(self._window) }
    }

    /// Set blocking or non-blocking reads for the specified window.
    ///
    /// The delay is measured in milliseconds. If it's negative, a blocking read is used; if zero,
    /// then non-blocking reads are done -- if no input is waiting, ERR is returned immediately.
    /// If the delay is positive, the read blocks for the delay period; if the period expires,
    /// ERR is returned.
    pub fn timeout(&self, milliseconds: i32) {
        unsafe { curses::wtimeout(self._window, milliseconds) }
    }
}

/// Set cbreak mode.
///
/// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
/// character processing is not performed.  In nocbreak mode, typed characters are buffered until
/// a newline or carriage return. Interrupt and flow control characters are unaffected by this
/// mode.
pub fn cbreak() -> i32 {
    unsafe { curses::cbreak() }
}

/// Alters the appearance of the cursor.
///
///  A visibility of 0 makes it disappear; 1 makes it appear "normal" (usually an underline) and 2
/// makes it "highly visible" (usually a block).
pub fn curs_set(visibility: i32) -> i32 {
    unsafe { curses::curs_set(visibility) }
}

/// Should be called before exiting or escaping from curses mode temporarily.
///
/// It will restore tty modes, move the cursor to the lower left corner of the screen and reset the
/// terminal into the proper non-visual mode.  To resume curses after a temporary escape, call
/// refresh() or doupdate().
pub fn endwin() -> i32 {
    unsafe { curses::endwin() }
}

/// Indicates if the terminal supports, and can maniplulate color.
pub fn has_colors() -> bool {
    unsafe { curses::has_colors() > 0 }
}

/// Initialize the curses system, this must be the first function that is called.
///
/// Returns a Window struct that is used to access Window specific functions.
pub fn initscr() -> Window {
    let window_pointer = unsafe { curses::initscr() };
    Window { _window: window_pointer }
}

/// Changes the definition of a color-pair.
///
/// It takes three arguments: the number of the color-pair to be redefined, and the new values of
/// the foreground and background colors. The pair number must be between 0 and COLOR_PAIRS - 1,
/// inclusive. The foreground and background must be between 0 and COLORS - 1, inclusive. If the
/// color pair was previously initialized, the screen is refreshed, and all occurrences of that
/// color-pair are changed to the new definition.
pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 {
    unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 }
}

/// Suspends the program for the specified number of milliseconds.
pub fn napms(ms: i32) -> i32 {
    unsafe { curses::napms(ms) }
}

/// Creates a new window with the given number of lines, nlines and columns, ncols.
///
/// The upper left corner of the window is at line begy, column begx. If nlines is zero, it
/// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling
/// newwin(0, 0, 0, 0).
pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window {
    let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) };
    Window { _window: window_pointer }
}

/// Enables the translation of a carriage return into a newline on input.
///
/// nonl() disables this. Initially, the translation does occur.
pub fn nl() -> i32 {
    unsafe { curses::nl() }
}

/// Disables echoing typed characters.
///
/// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
/// type-ahead.
pub fn noecho() -> i32 {
    unsafe { curses::noecho() }
}

/// Attempts to resize the screen to the given size.
///
/// resize_term() is effectively two functions: When called with nonzero values for nlines and
/// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely
/// adjusts the internal structures to match the current size after the screen is resized by the
/// user. If you want to support user resizing, you should check for getch() returning KEY_RESIZE,
/// and/or call is_termresized() at appropriate times; if either condition occurs, call
/// resize_term(0, 0). Then, with either user or programmatic resizing, you'll have to resize any
/// windows you've created.
pub fn resize_term(nlines: i32, ncols: i32) -> i32 {
    _resize_term(nlines, ncols)
}

/// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan,
/// and white), and two global variables; COLORS and COLOR_PAIRS (respectively defining the
/// maximum number of colors and color-pairs the terminal is capable of displaying).
pub fn start_color() -> i32 {
    unsafe { curses::start_color() as i32 }
}

/// Allows the use of -1 as a foreground or background color with init_pair().
///
/// Calls assume_default_colors(-1, -1); -1 represents the foreground or background color that
/// the terminal had at startup.
pub fn use_default_colors() -> i32 {
    unsafe { curses::use_default_colors() }
}
<|endoftext|>


<commit_before>#![allow(unused_features)]
#![feature(asm, libc, rustc_private, page_size, core_simd, core, alloc, rt)]

#[macro_use]
extern crate log;
extern crate libc;
extern crate mmap;

pub use context::Context;
pub use stack::Stack;

pub mod context;
pub mod stack;
mod sys;
mod thunk;
<commit_msg>also exports the thunk<commit_after>#![allow(unused_features)]
#![feature(asm, libc, rustc_private, page_size, core_simd, core, alloc, rt)]

#[macro_use]
extern crate log;
extern crate libc;
extern crate mmap;

pub use context::Context;
pub use stack::Stack;

pub mod context;
pub mod stack;
mod sys;
pub mod thunk;
<|endoftext|>


<commit_before>// This file is part of tmx
// Copyright 2017 Sébastien Watteau
//
// 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::error;

//! TMX reading crate.
//!
//! This is a crate for reading TMX files.
//!
//! ```
//! use std::str::FromStr;
//! use tmx::*;
//!
//! let xml = "<map></<map>";
//! let map = Map::from_str(&xml);
//! ```

extern crate xml;

#[cfg(test)]
#[macro_use] extern crate assert_matches;

mod error;
mod model;

pub use error::Error;
pub use model::*;

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

<commit_msg>Added some basic documentation<commit_after>// This file is part of tmx
// Copyright 2017 Sébastien Watteau
//
// 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::error;

//! A simple crate for reading [Tiled](http://www.mapeditor.org/) files.
//!
//! # Getting Started
//!
//! Reading a `.tmx` (map) file:
//!
//! ```
//! extern crate tmx;
//!
//! fn main() {
//!     match tmx::Map::open("some_file.tmx") {
//!         Ok(map) => println!("Got a map!"),
//!         Err(e) => println!("Got an error: {}", e)
//!     };
//! }
//! ```
//!
//! Reading a `.tsx` (tileset) file:
//!
//! ```
//! extern crate tmx;
//!
//! fn main() {
//!     match tmx::Tileset::open("some_file.tsx") {
//!         Ok(tileset) => println!("Got a tileset!"),
//!         Err(e) => println!("Got an error: {}", e)
//!     };
//! }
//! ```
//!
//! Reading data directly from a string:
//!
//! ```
//! extern crate tmx;
//!
//! use std::str::FromStr;
//!
//! let empty_map = tmx::Map::from_str(r#"<map version="1.0"/>"#);
//! ```

extern crate xml;

#[cfg(test)]
#[macro_use] extern crate assert_matches;

mod error;
mod model;

pub use error::Error;
pub use model::*;

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

<|endoftext|>


<commit_before>
pub fn puzzle(input: &str) -> usize {
    0
}

#[derive(Clone, PartialEq)]
pub enum WhichChip {
    Low,
    High,
}

pub struct Bot {
    chip1: Option<usize>,
    chip2: Option<usize>,
    commands: Vec<(usize, WhichChip)>
}

impl Bot {
    pub fn new() -> Bot {
        Bot { chip1: None, chip2: None, commands: vec![], }
    }

    pub fn has_two_chips(&self) -> bool {
        match (self.chip1, self.chip2) {
            (Some(_), Some(_)) => true,
            _ => false,
        }
    }

    pub fn receive_chip(&mut self, chip: usize) {
        if self.chip1.is_none() {
            self.chip1 = Some(chip);
        } else if self.chip2.is_none() {
            self.chip2 = Some(chip);
        } else {
            panic!("Cannot hold more than two chips");
        }
    }

    pub fn receive_command(&mut self, which_bot: usize, which_chip: WhichChip) {
        self.commands.push((which_bot, which_chip));
    }
}

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

    #[test]
    fn new_bot_does_not_have_two_chips() {
        let bot = Bot::new();
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_a_chip_still_not_two() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_two_chips() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        bot.receive_chip(4);
        assert!(bot.has_two_chips());
    }
}
<commit_msg>Make a bot router that takes commands and distributes them<commit_after>use std::collections::HashMap;

pub fn puzzle(input: &str) -> usize {
    0
}

#[derive(Clone, PartialEq, Debug)]
pub enum WhichChip {
    Low,
    High,
}

#[derive(PartialEq, Debug)]
pub struct Bot {
    chip1: Option<usize>,
    chip2: Option<usize>,
    commands: Vec<(usize, WhichChip)>
}

impl Bot {
    pub fn new() -> Bot {
        Bot { chip1: None, chip2: None, commands: vec![], }
    }

    pub fn has_two_chips(&self) -> bool {
        match (self.chip1, self.chip2) {
            (Some(_), Some(_)) => true,
            _ => false,
        }
    }

    pub fn receive_chip(&mut self, chip: usize) {
        if self.chip1.is_none() {
            self.chip1 = Some(chip);
        } else if self.chip2.is_none() {
            self.chip2 = Some(chip);
        } else {
            panic!("Cannot hold more than two chips");
        }
    }

    pub fn receive_command(&mut self, which_bot: usize, which_chip: WhichChip) {
        self.commands.push((which_bot, which_chip));
    }
}

pub struct BotRouter {
    bots: HashMap<usize, Bot>,
}

impl BotRouter {
    pub fn exec_command(&mut self, input: &str) {
        let pieces: Vec<&str> = input.split_whitespace().collect();

        if pieces[0] == "value" {
            self.value_to_bot(
                pieces[5].parse().expect("can't parse bot key"),
                pieces[1].parse().expect("can't parse chip value")
            );
        } else if pieces[0] == "bot" {
            self.command_to_bot(
                pieces[1].parse().expect("can't parse bot key"),
                pieces[6].parse().expect("can't parse low bot key"),
                pieces[11].parse().expect("can't parse high bot key"),
            );
        }
    }

    pub fn value_to_bot(&mut self, bot_key: usize, value: usize) {
        let bot = self.bots.entry(bot_key).or_insert(Bot::new());
        bot.receive_chip(value);
    }

    pub fn command_to_bot(&mut self, bot_key: usize,
                          low_bot_key: usize, high_bot_key: usize) {
        let bot = self.bots.entry(bot_key).or_insert(Bot::new());
        bot.receive_command(low_bot_key, WhichChip::Low);
        bot.receive_command(high_bot_key, WhichChip::High);
    }
}

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

    #[test]
    fn new_bot_does_not_have_two_chips() {
        let bot = Bot::new();
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_a_chip_still_not_two() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        assert!( ! bot.has_two_chips() );
    }

    #[test]
    fn bot_gets_two_chips() {
        let mut bot = Bot::new();
        bot.receive_chip(1);
        bot.receive_chip(4);
        assert!(bot.has_two_chips());
    }

    #[test]
    fn router_can_give_values() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("value 5 goes to bot 2");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot { chip1: Some(5), chip2: None, commands: vec![] })
        );
    }

    #[test]
    fn router_can_give_commands_that_get_stored() {
        let mut br = BotRouter { bots: HashMap::new() };
        br.exec_command("bot 2 gives low to bot 1 and high to bot 0");
        assert_eq!(
            br.bots.get(&2),
            Some(&Bot {
                chip1: None,
                chip2: None,
                commands: vec![(1, WhichChip::Low), (0, WhichChip::High)]
            })
        );
    }
}
<|endoftext|>


<commit_before>//! A library for event threading

#![crate_type = "lib"]
#![crate_name = "event"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![cfg_attr(test, feature(test))]

#[cfg(test)]
extern crate test;
extern crate input;
extern crate event_loop;
extern crate window;

use std::cell::RefCell;
use std::rc::Rc;
use window::Window;

pub use event_loop as events;
pub use events::{
    Events,
    UpdateArgs,
    RenderArgs,
    AfterRenderArgs,
    IdleArgs,
};
pub use generic_event::GenericEvent;
pub use update::UpdateEvent;
pub use render::RenderEvent;
pub use after_render::AfterRenderEvent;
pub use idle::IdleEvent;
pub use event::Event;
pub use press::PressEvent;
pub use release::ReleaseEvent;
pub use mouse::{ MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent };
pub use text::TextEvent;
pub use resize::ResizeEvent;
pub use focus::FocusEvent;

pub mod generic_event;
mod update;
mod render;
mod after_render;
mod idle;
mod event;
mod press;
mod release;
mod mouse;
mod text;
mod resize;
mod focus;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct EventId(pub &'static str);

const FOCUS: EventId = EventId("piston/focus");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const RELEASE: EventId = EventId("piston/release");
const PRESS: EventId = EventId("piston/press");
const IDLE: EventId = EventId("piston/idle");
const AFTER_RENDER: EventId = EventId("piston/after_render");
const RENDER: EventId = EventId("piston/render");
const UPDATE: EventId = EventId("piston/update");

/// Creates event iterator from window.
pub fn events<W>(window: Rc<RefCell<W>>) -> event_loop::Events<W, Event<<W as Window>::Event>>
    where
        W: Window,
{
    event_loop::Events::new(window)
}
<commit_msg>Add trait Events<commit_after>//! A library for event threading

#![crate_type = "lib"]
#![crate_name = "event"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![cfg_attr(test, feature(test))]

#[cfg(test)]
extern crate test;
extern crate input;
extern crate event_loop;
extern crate window;

use std::cell::RefCell;
use std::rc::Rc;
use window::Window;

pub use event_loop as events;
pub use events::{
    UpdateArgs,
    RenderArgs,
    AfterRenderArgs,
    IdleArgs,
};
pub use generic_event::GenericEvent;
pub use update::UpdateEvent;
pub use render::RenderEvent;
pub use after_render::AfterRenderEvent;
pub use idle::IdleEvent;
pub use event::Event;
pub use press::PressEvent;
pub use release::ReleaseEvent;
pub use mouse::{ MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent };
pub use text::TextEvent;
pub use resize::ResizeEvent;
pub use focus::FocusEvent;

pub mod generic_event;
mod update;
mod render;
mod after_render;
mod idle;
mod event;
mod press;
mod release;
mod mouse;
mod text;
mod resize;
mod focus;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct EventId(pub &'static str);

const FOCUS: EventId = EventId("piston/focus");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const RELEASE: EventId = EventId("piston/release");
const PRESS: EventId = EventId("piston/press");
const IDLE: EventId = EventId("piston/idle");
const AFTER_RENDER: EventId = EventId("piston/after_render");
const RENDER: EventId = EventId("piston/render");
const UPDATE: EventId = EventId("piston/update");

/// A trait for create event iterator from window.
pub trait Events<W> where W: Window {
    /// Creates event iterator from window.
    fn events(self) -> events::Events<W, Event<W::Event>>;
}

impl<W> Events<W> for Rc<RefCell<W>> where W: Window {
    fn events(self) -> events::Events<W, Event<W::Event>> {
        events::Events::new(self)
    }
}
<|endoftext|>


<commit_before>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
<commit_msg>implement rudimentary header writing<commit_after>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(io)]

use std::io;
use std::io::{Seek, Write};
use std::marker;

trait WriteExt: io::Write {
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

trait Sample {
    fn write<W: io::Write>(self, writer: &mut W) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W) -> io::Result<()> {
        writer.write_le_u16(self)
    }
}

struct WavWriter<W, S> {
    writer: W,
    wrote_header: bool,
    phantom_sample: marker::PhantomData<fn(S)>
}

impl<W, S> WavWriter<W, S>
where W: io::Write + io::Seek,
      S: Sample {

    pub fn with_bps(writer: W,
                    n_channels: u16,
                    sample_rate: u32,
                    bits_per_sample: u32)
                    -> WavWriter<W, S> {
        unimplemented!();
    }

    pub fn new(writer: W,
               n_channels: u16,
               sample_rate: u32)
               -> WavWriter<W, S> {
        use std::mem::size_of;
        WavWriter::with_bps(writer,
                            n_channels,
                            sample_rate,
                            size_of::<S> as u32 * 8)
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        let mut header = [0u8; 44];

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            buffer.seek(io::SeekFrom::Current(4));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt\0".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header
            try!(buffer.write_le_u16(1));  // PCM encoded audio
            try!(buffer.write_le_u16(2)); // TODO: num channels
            try!(buffer.write_le_u32(44100)); // TODO: sample rate
            try!(buffer.write_le_u32(0)); // TODO: sr * bps * n_chan / 8
            try!(buffer.write_le_u16(16)); // TODO: block align
            try!(buffer.write_le_u32(16)); // TODO: bits per sample
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    pub fn write_sample(sample: S) -> io::Result<()> {
        // TODO
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::convert::AsRef;
use std::ffi::CStr;
use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;

use std::sync::mpsc::Sender;

pub struct FsEvent {
    paths: cf::CFMutableArrayRef,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
    sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

pub type FsEventCallback = fn(Vec<Event>);

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INOTE_META_MOD) {
            let _d = write!(f, "INOTE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLIMK) {
            let _d = write!(f, "IS_SYMLIMK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

pub fn is_api_available() -> (bool, &'static str) {
    let ma = cf::system_version_major();
    let mi = cf::system_version_minor();

    if ma == 10 && mi < 5 {
        (
            false,
            "This version of OSX does not support the FSEvent library, cannot proceed",
        )
    } else {
        (true, "ok")
    }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
    let ptr = info as *mut libc::c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: cf::NULL,
        copy_description: cf::NULL,
    }
}

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

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
    pub fn new(sender: Sender<Event>) -> FsEvent {
        let fsevent: FsEvent;

        unsafe {
            fsevent = FsEvent {
                paths: cf::CFArrayCreateMutable(
                    cf::kCFAllocatorDefault,
                    0,
                    &cf::kCFTypeArrayCallBacks,
                ),
                since_when: fs::kFSEventStreamEventIdSinceNow,
                latency: 0.0,
                flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
                sender,
            };
        }
        fsevent
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&self, source: &str) -> Result<()> {
        unsafe {
            let mut err = ptr::null_mut();
            let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
            if !err.is_null() {
                let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                let mut buf = [0; 1024];
                cf::CFStringGetCString(
                    cf_str,
                    buf.as_mut_ptr(),
                    buf.len() as cf::CFIndex,
                    cf::kCFStringEncodingUTF8,
                );
                Err(Error {
                    msg: CStr::from_ptr(buf.as_ptr())
                        .to_str()
                        .unwrap_or("Unknown error")
                        .to_string(),
                })
            } else {
                cf::CFArrayAppendValue(self.paths, cf_path);
                cf::CFRelease(cf_path);
                Ok(())
            }
        }
    }
    pub fn observe(&self) {
        let stream_context = default_stream_context(self);

        let cb = callback as *mut _;

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                cb,
                &stream_context,
                self.paths,
                self.since_when,
                self.latency,
                self.flags,
            );

            // fs::FSEventStreamShow(stream);

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }
    }
}

#[allow(unused_variables)]
unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,                // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void,          // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,            // const FSEventStreamEventId eventIds[]
) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let paths: &[*const libc::c_char] =
        std::mem::transmute(slice::from_raw_parts(event_paths, num));
    let flags = from_raw_parts_mut(e_ptr, num);
    let ids = from_raw_parts_mut(i_ptr, num);

    for p in 0..num {
        let i = CStr::from_ptr(paths[p]).to_bytes();
        let path = from_utf8(i).expect("Invalid UTF8 string.");
        let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32).expect(
            format!(
                "Unable to decode StreamFlags: {} for {}",
                flags[p] as u32, path
            ).as_ref(),
        );
        // println!("{}: {}", ids[p], flag);

        let event = Event {
            event_id: ids[p],
            flag,
            path: path.to_string(),
        };
        let _s = (*fs_event).sender.send(event);
    }
}
<commit_msg>Remove unused `FsEventCallback`.<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[macro_use]
extern crate bitflags;

extern crate fsevent_sys as fsevent;
extern crate libc;

use fsevent::core_foundation as cf;
use fsevent::fsevent as fs;

use std::convert::AsRef;
use std::ffi::CStr;
use std::ptr;
use std::slice;
use std::slice::from_raw_parts_mut;
use std::str::from_utf8;

use std::sync::mpsc::Sender;

pub struct FsEvent {
    paths: cf::CFMutableArrayRef,
    since_when: fs::FSEventStreamEventId,
    latency: cf::CFTimeInterval,
    flags: fs::FSEventStreamCreateFlags,
    sender: Sender<Event>,
}

#[derive(Debug)]
pub struct Event {
    pub event_id: u64,
    pub flag: StreamFlags,
    pub path: String,
}

// Synchronize with
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Headers/FSEvents.h
bitflags! {
  #[repr(C)]
  pub struct StreamFlags: u32 {
    const NONE = 0x00000000;
    const MUST_SCAN_SUBDIRS = 0x00000001;
    const USER_DROPPED = 0x00000002;
    const KERNEL_DROPPED = 0x00000004;
    const IDS_WRAPPED = 0x00000008;
    const HISTORY_DONE = 0x00000010;
    const ROOT_CHANGED = 0x00000020;
    const MOUNT = 0x00000040;
    const UNMOUNT = 0x00000080;
    const ITEM_CREATED = 0x00000100;
    const ITEM_REMOVED = 0x00000200;
    const INOTE_META_MOD = 0x00000400;
    const ITEM_RENAMED = 0x00000800;
    const ITEM_MODIFIED = 0x00001000;
    const FINDER_INFO_MOD = 0x00002000;
    const ITEM_CHANGE_OWNER = 0x00004000;
    const ITEM_XATTR_MOD = 0x00008000;
    const IS_FILE = 0x00010000;
    const IS_DIR = 0x00020000;
    const IS_SYMLIMK = 0x00040000;
    const OWN_EVENT = 0x00080000;
    const IS_HARDLINK = 0x00100000;
    const IS_LAST_HARDLINK = 0x00200000;
    const ITEM_CLONED = 0x400000;
  }
}

impl std::fmt::Display for StreamFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.contains(StreamFlags::MUST_SCAN_SUBDIRS) {
            let _d = write!(f, "MUST_SCAN_SUBDIRS ");
        }
        if self.contains(StreamFlags::USER_DROPPED) {
            let _d = write!(f, "USER_DROPPED ");
        }
        if self.contains(StreamFlags::KERNEL_DROPPED) {
            let _d = write!(f, "KERNEL_DROPPED ");
        }
        if self.contains(StreamFlags::IDS_WRAPPED) {
            let _d = write!(f, "IDS_WRAPPED ");
        }
        if self.contains(StreamFlags::HISTORY_DONE) {
            let _d = write!(f, "HISTORY_DONE ");
        }
        if self.contains(StreamFlags::ROOT_CHANGED) {
            let _d = write!(f, "ROOT_CHANGED ");
        }
        if self.contains(StreamFlags::MOUNT) {
            let _d = write!(f, "MOUNT ");
        }
        if self.contains(StreamFlags::UNMOUNT) {
            let _d = write!(f, "UNMOUNT ");
        }
        if self.contains(StreamFlags::ITEM_CREATED) {
            let _d = write!(f, "ITEM_CREATED ");
        }
        if self.contains(StreamFlags::ITEM_REMOVED) {
            let _d = write!(f, "ITEM_REMOVED ");
        }
        if self.contains(StreamFlags::INOTE_META_MOD) {
            let _d = write!(f, "INOTE_META_MOD ");
        }
        if self.contains(StreamFlags::ITEM_RENAMED) {
            let _d = write!(f, "ITEM_RENAMED ");
        }
        if self.contains(StreamFlags::ITEM_MODIFIED) {
            let _d = write!(f, "ITEM_MODIFIED ");
        }
        if self.contains(StreamFlags::FINDER_INFO_MOD) {
            let _d = write!(f, "FINDER_INFO_MOD ");
        }
        if self.contains(StreamFlags::ITEM_CHANGE_OWNER) {
            let _d = write!(f, "ITEM_CHANGE_OWNER ");
        }
        if self.contains(StreamFlags::ITEM_XATTR_MOD) {
            let _d = write!(f, "ITEM_XATTR_MOD ");
        }
        if self.contains(StreamFlags::IS_FILE) {
            let _d = write!(f, "IS_FILE ");
        }
        if self.contains(StreamFlags::IS_DIR) {
            let _d = write!(f, "IS_DIR ");
        }
        if self.contains(StreamFlags::IS_SYMLIMK) {
            let _d = write!(f, "IS_SYMLIMK ");
        }
        if self.contains(StreamFlags::OWN_EVENT) {
            let _d = write!(f, "OWN_EVENT ");
        }
        if self.contains(StreamFlags::IS_LAST_HARDLINK) {
            let _d = write!(f, "IS_LAST_HARDLINK ");
        }
        if self.contains(StreamFlags::IS_HARDLINK) {
            let _d = write!(f, "IS_HARDLINK ");
        }
        if self.contains(StreamFlags::ITEM_CLONED) {
            let _d = write!(f, "ITEM_CLONED ");
        }
        write!(f, "")
    }
}

pub fn is_api_available() -> (bool, &'static str) {
    let ma = cf::system_version_major();
    let mi = cf::system_version_minor();

    if ma == 10 && mi < 5 {
        (
            false,
            "This version of OSX does not support the FSEvent library, cannot proceed",
        )
    } else {
        (true, "ok")
    }
}

fn default_stream_context(info: *const FsEvent) -> fs::FSEventStreamContext {
    let ptr = info as *mut libc::c_void;
    fs::FSEventStreamContext {
        version: 0,
        info: ptr,
        retain: cf::NULL,
        copy_description: cf::NULL,
    }
}

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

#[derive(Debug)]
pub struct Error {
    msg: String,
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        &self.msg
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.msg.fmt(f)
    }
}

impl FsEvent {
    pub fn new(sender: Sender<Event>) -> FsEvent {
        let fsevent: FsEvent;

        unsafe {
            fsevent = FsEvent {
                paths: cf::CFArrayCreateMutable(
                    cf::kCFAllocatorDefault,
                    0,
                    &cf::kCFTypeArrayCallBacks,
                ),
                since_when: fs::kFSEventStreamEventIdSinceNow,
                latency: 0.0,
                flags: fs::kFSEventStreamCreateFlagFileEvents | fs::kFSEventStreamCreateFlagNoDefer,
                sender,
            };
        }
        fsevent
    }

    // https://github.com/thibaudgg/rb-fsevent/blob/master/ext/fsevent_watch/main.c
    pub fn append_path(&self, source: &str) -> Result<()> {
        unsafe {
            let mut err = ptr::null_mut();
            let cf_path = cf::str_path_to_cfstring_ref(source, &mut err);
            if !err.is_null() {
                let cf_str = cf::CFCopyDescription(err as cf::CFRef);
                let mut buf = [0; 1024];
                cf::CFStringGetCString(
                    cf_str,
                    buf.as_mut_ptr(),
                    buf.len() as cf::CFIndex,
                    cf::kCFStringEncodingUTF8,
                );
                Err(Error {
                    msg: CStr::from_ptr(buf.as_ptr())
                        .to_str()
                        .unwrap_or("Unknown error")
                        .to_string(),
                })
            } else {
                cf::CFArrayAppendValue(self.paths, cf_path);
                cf::CFRelease(cf_path);
                Ok(())
            }
        }
    }
    pub fn observe(&self) {
        let stream_context = default_stream_context(self);

        let cb = callback as *mut _;

        unsafe {
            let stream = fs::FSEventStreamCreate(
                cf::kCFAllocatorDefault,
                cb,
                &stream_context,
                self.paths,
                self.since_when,
                self.latency,
                self.flags,
            );

            // fs::FSEventStreamShow(stream);

            fs::FSEventStreamScheduleWithRunLoop(
                stream,
                cf::CFRunLoopGetCurrent(),
                cf::kCFRunLoopDefaultMode,
            );

            fs::FSEventStreamStart(stream);
            cf::CFRunLoopRun();

            fs::FSEventStreamFlushSync(stream);
            fs::FSEventStreamStop(stream);
        }
    }
}

#[allow(unused_variables)]
unsafe fn callback(
    stream_ref: fs::FSEventStreamRef,
    info: *mut libc::c_void,
    num_events: libc::size_t,                // size_t numEvents
    event_paths: *const *const libc::c_char, // void *eventPaths
    event_flags: *mut libc::c_void,          // const FSEventStreamEventFlags eventFlags[]
    event_ids: *mut libc::c_void,            // const FSEventStreamEventId eventIds[]
) {
    let num = num_events as usize;
    let e_ptr = event_flags as *mut u32;
    let i_ptr = event_ids as *mut u64;
    let fs_event = info as *mut FsEvent;

    let paths: &[*const libc::c_char] =
        std::mem::transmute(slice::from_raw_parts(event_paths, num));
    let flags = from_raw_parts_mut(e_ptr, num);
    let ids = from_raw_parts_mut(i_ptr, num);

    for p in 0..num {
        let i = CStr::from_ptr(paths[p]).to_bytes();
        let path = from_utf8(i).expect("Invalid UTF8 string.");
        let flag: StreamFlags = StreamFlags::from_bits(flags[p] as u32).expect(
            format!(
                "Unable to decode StreamFlags: {} for {}",
                flags[p] as u32, path
            ).as_ref(),
        );
        // println!("{}: {}", ids[p], flag);

        let event = Event {
            event_id: ids[p],
            flag,
            path: path.to_string(),
        };
        let _s = (*fs_event).sender.send(event);
    }
}
<|endoftext|>


<commit_before>//!A light HTTP framework with REST-like features. The main purpose of Rustful
//!is to create a simple, modular and non-intrusive foundation for HTTP
//!applications. It has a mainly stateless structure, which naturally allows
//!it to run both as one single server and as multiple instances in a cluster.
//!
//!A new server is created using the [`Server`][server] type, which contains
//!all the necessary settings as fields:
//!
//!```no_run
//!#[macro_use]
//!extern crate rustful;
//!use rustful::{Server, Handler, Context, Response, TreeRouter};
//!
//!struct Greeting(&'static str);
//!
//!impl Handler for Greeting {
//!    fn handle_request(&self, context: Context, response: Response) {
//!        //Check if the client accessed /hello/:name or /good_bye/:name
//!        if let Some(name) = context.variables.get("name") {
//!            //Use the value of :name
//!            response.send(format!("{}, {}", self.0, name));
//!        } else {
//!            response.send(self.0)
//!        }
//!    }
//!}
//!
//!# fn main() {
//!let my_router = insert_routes!{
//!    //Create a new TreeRouter
//!    TreeRouter::new() => {
//!        //Receive GET requests to /hello and /hello/:name
//!        "hello" => {
//!            Get: Greeting("hello"),
//!            ":name" => Get: Greeting("hello")
//!        },
//!        //Receive GET requests to /good_bye and /good_bye/:name
//!        "good_bye" => {
//!            Get: Greeting("good bye"),
//!            ":name" => Get: Greeting("good bye")
//!        }
//!    }
//!};
//!
//!Server {
//!    //Use a closure to handle requests.
//!    handlers: my_router,
//!    //Set the listening port to `8080`.
//!    host: 8080.into(),
//!    //Fill out everything else with default values.
//!    ..Server::default()
//!}.run();
//!# }
//!```
//!
//![server]: server/struct.Server.html

#![crate_name = "rustful"]

#![crate_type = "rlib"]

#![doc(html_root_url = "http://ogeon.github.io/docs/rustful/master/")]

#![cfg_attr(all(test, feature = "benchmark"), feature(test))]
#![cfg_attr(feature = "strict", deny(missing_docs))]
#![cfg_attr(feature = "strict", deny(warnings))]

#[cfg(test)]
#[cfg(feature = "benchmark")]
extern crate test;

#[cfg(test)]
extern crate tempdir;

#[cfg(feature = "rustc-serialize")]
extern crate rustc_serialize;

#[cfg(feature = "multipart")]
extern crate multipart;

extern crate url;
extern crate time;
extern crate hyper;
extern crate anymap;
extern crate phf;

pub use hyper::mime;
pub use hyper::method::Method;
pub use hyper::status::StatusCode;
pub use hyper::header;
pub use hyper::Result as HttpResult;
pub use hyper::Error as HttpError;
pub use hyper::version::HttpVersion;

pub use self::server::Server;
pub use self::context::Context;
pub use self::response::Response;
pub use self::response::Error;
pub use self::handler::Handler;
pub use self::router::Router;
pub use self::log::Log;
pub use self::router::TreeRouter;

mod utils;
#[macro_use]
#[doc(hidden)]
pub mod macros;

pub mod server;
pub mod router;
pub mod handler;
pub mod context;
pub mod response;
pub mod filter;
pub mod log;
pub mod file;

use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr};
use std::str::FromStr;
use std::any::TypeId;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::borrow::Borrow;
use std::hash::Hash;

use anymap::Map;
use anymap::any::{Any, UncheckedAnyExt};

///HTTP or HTTPS.
pub enum Scheme {
    ///Standard HTTP.
    Http,

    ///HTTP with SSL encryption.
    #[cfg(feature = "ssl")]
    Https {
        ///Path to SSL certificate.
        cert: std::path::PathBuf,

        ///Path to key file.
        key: std::path::PathBuf
    }
}

///A host address and a port.
///
///Can be conveniently converted from an existing address-port pair or just a port:
///
///```
///use std::net::Ipv4Addr;
///use rustful::Host;
///
///let host1: Host = (Ipv4Addr::new(0, 0, 0, 0), 80).into();
///let host2: Host = 80.into();
///
///assert_eq!(host1, host2);
///```
#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
pub struct Host(SocketAddr);

impl Host {
    ///Create a `Host` with the address `0.0.0.0:port`. This is the same as `port.into()`.
    pub fn any_v4(port: u16) -> Host {
        Host(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port)))
    }

    ///Change the port of the host address.
    pub fn port(&mut self, port: u16) {
        self.0 = match self.0 {
            SocketAddr::V4(addr) => SocketAddr::V4(SocketAddrV4::new(addr.ip().clone(), port)),
            SocketAddr::V6(addr) => {
                SocketAddr::V6(SocketAddrV6::new(addr.ip().clone(), port, addr.flowinfo(), addr.scope_id()))
            }
        };
    }
}

impl From<Host> for SocketAddr {
    fn from(host: Host) -> SocketAddr {
        host.0
    }
}

impl From<u16> for Host {
    fn from(port: u16) -> Host {
        Host::any_v4(port)
    }
}

impl From<SocketAddr> for Host {
    fn from(addr: SocketAddr) -> Host {
        Host(addr)
    }
}

impl From<SocketAddrV4> for Host {
    fn from(addr: SocketAddrV4) -> Host {
        Host(SocketAddr::V4(addr))
    }
}

impl From<SocketAddrV6> for Host {
    fn from(addr: SocketAddrV6) -> Host {
        Host(SocketAddr::V6(addr))
    }
}

impl From<(Ipv4Addr, u16)> for Host {
    fn from((ip, port): (Ipv4Addr, u16)) -> Host {
        Host(SocketAddr::V4(SocketAddrV4::new(ip, port)))
    }
}

impl FromStr for Host {
    type Err = <SocketAddr as FromStr>::Err;

    fn from_str(s: &str) -> Result<Host, Self::Err> {
        s.parse().map(|s| Host(s))
    }
}

///A somewhat lazy container for globally accessible data.
///
///It will try to be as simple as possible and allocate as little as possible,
///depending on the number of stored values.
///
/// * No value: Nothing is allocated and nothing is searched for during
///access.
///
/// * One value: One `Box` is allocated. Searching for a value will only
///consist of a comparison of `TypeId` and a downcast.
///
/// * Multiple values: An `AnyMap` is created, as well as a `Box` for each
///value. Searching for a value has the full overhead of `AnyMap`.
///
///`Global` can be created from a boxed value, from tuples or using the
///`Default` trait. More values can then be added using `insert(value)`.
///
///```
///# use rustful::Global;
///let mut g1: Global = Box::new(5).into();
///assert_eq!(g1.get(), Some(&5));
///assert_eq!(g1.get::<&str>(), None);
///
///let old = g1.insert(10);
///assert_eq!(old, Some(5));
///assert_eq!(g1.get(), Some(&10));
///
///g1.insert("cat");
///assert_eq!(g1.get(), Some(&10));
///assert_eq!(g1.get(), Some(&"cat"));
///
///let g2: Global = (5, "cat").into();
///assert_eq!(g2.get(), Some(&5));
///assert_eq!(g2.get(), Some(&"cat"));
///```
pub struct Global(GlobalState);

impl Global {
    ///Borrow a value of type `T` if the there is one.
    pub fn get<T: Any + Send + Sync>(&self) -> Option<&T> {
        match self.0 {
            GlobalState::None => None,
            GlobalState::One(id, ref a) => if id == TypeId::of::<T>() {
                //Here be dragons!
                unsafe { Some(a.downcast_ref_unchecked()) }
            } else {
                None
            },
            GlobalState::Many(ref map) => map.get()
        }
    }

    ///Insert a new value, returning the previous value of the same type, if
    ///any.
    pub fn insert<T: Any + Send + Sync>(&mut self, value: T) -> Option<T> {
        match self.0 {
            GlobalState::None => {
                *self = Box::new(value).into();
                None
            },
            GlobalState::One(id, _) => if id == TypeId::of::<T>() {
                if let GlobalState::One(_, ref mut previous_value) = self.0 {
                    let mut v = Box::new(value) as Box<Any + Send + Sync>;
                    std::mem::swap(previous_value, &mut v);
                    Some(unsafe { *v.downcast_unchecked() })
                } else {
                    unreachable!()
                }
            } else {
                //Here be more dragons!
                let mut other = GlobalState::Many(Map::new());
                std::mem::swap(&mut self.0, &mut other);
                if let GlobalState::Many(ref mut map) = self.0 {
                    if let GlobalState::One(id, previous_value) = other {
                        let mut raw = map.as_mut();
                        unsafe { raw.insert(id, previous_value); }
                    }

                    map.insert(value)
                } else {
                    unreachable!()
                }
            },
            GlobalState::Many(ref mut map) => {
                map.insert(value)
            }
        }
    }
}

impl<T: Any + Send + Sync> From<Box<T>> for Global {
    fn from(data: Box<T>) -> Global {
        Global(GlobalState::One(TypeId::of::<T>(), data))
    }
}

macro_rules! from_tuple {
    ($first: ident, $($t: ident),+) => (
        impl<$first: Any + Send + Sync, $($t: Any + Send + Sync),+> From<($first, $($t),+)> for Global {
            #[allow(non_snake_case)]
            fn from(tuple: ($first, $($t),+))-> Global {
                let ($first, $($t),+) = tuple;
                let mut map = Map::new();
                map.insert($first);
                $(
                    map.insert($t);
                )+

                Global(GlobalState::Many(map))
            }
        }

        from_tuple!($($t),+);
    );
    ($ty: ident) => (
        impl<$ty: Any + Send + Sync> From<($ty,)> for Global {
            fn from(tuple: ($ty,)) -> Global {
                Box::new(tuple.0).into()
            }
        }
    );
}

impl From<()> for Global {
    fn from(_: ()) -> Global {
        Global(GlobalState::None)
    }
}

from_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);

impl Default for Global {
    fn default() -> Global {
        Global(GlobalState::None)
    }
}

enum GlobalState {
    None,
    One(TypeId, Box<Any + Send + Sync>),
    Many(Map<Any + Send + Sync>),
}

pub struct Parameters<K, V>(HashMap<K, V>);

impl<K: Hash + Eq, V: AsRef<str>> Parameters<K, V> {
    pub fn parse<Q: ?Sized, T>(&self, key: &Q) -> Result<T, Option<T::Err>> where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr
    {
        if let Some(val) = self.0.get(key) {
            val.as_ref().parse().map_err(|e| Some(e))
        } else {
            Err(None)
        }
    }

    pub fn parse_or<Q: ?Sized, T>(&self, key: &Q, or: T) -> T where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr
    {
        self.parse(key).unwrap_or(or)
    }

    pub fn parse_or_else<Q: ?Sized, T, F>(&self, key: &Q, or_else: F) -> T where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr,
        F: FnOnce(Option<T::Err>) -> T
    {
        self.parse(key).unwrap_or_else(or_else)
    }
}

impl<K, V> Deref for Parameters<K, V> {
    type Target = HashMap<K, V>;

    fn deref(&self) -> &HashMap<K, V> {
        &self.0
    }
}

impl<K, V> DerefMut for Parameters<K, V> {
    fn deref_mut(&mut self) -> &mut HashMap<K, V> {
        &mut self.0
    }
}

impl<K, V> Into<HashMap<K, V>> for Parameters<K, V> {
    fn into(self) -> HashMap<K, V> {
        self.0
    }
}

impl<K, V> From<HashMap<K, V>> for Parameters<K, V> {
    fn from(map: HashMap<K, V>) -> Parameters<K, V> {
        Parameters(map)
    }
}
<commit_msg>Add documentation to Parameters<commit_after>//!A light HTTP framework with REST-like features. The main purpose of Rustful
//!is to create a simple, modular and non-intrusive foundation for HTTP
//!applications. It has a mainly stateless structure, which naturally allows
//!it to run both as one single server and as multiple instances in a cluster.
//!
//!A new server is created using the [`Server`][server] type, which contains
//!all the necessary settings as fields:
//!
//!```no_run
//!#[macro_use]
//!extern crate rustful;
//!use rustful::{Server, Handler, Context, Response, TreeRouter};
//!
//!struct Greeting(&'static str);
//!
//!impl Handler for Greeting {
//!    fn handle_request(&self, context: Context, response: Response) {
//!        //Check if the client accessed /hello/:name or /good_bye/:name
//!        if let Some(name) = context.variables.get("name") {
//!            //Use the value of :name
//!            response.send(format!("{}, {}", self.0, name));
//!        } else {
//!            response.send(self.0)
//!        }
//!    }
//!}
//!
//!# fn main() {
//!let my_router = insert_routes!{
//!    //Create a new TreeRouter
//!    TreeRouter::new() => {
//!        //Receive GET requests to /hello and /hello/:name
//!        "hello" => {
//!            Get: Greeting("hello"),
//!            ":name" => Get: Greeting("hello")
//!        },
//!        //Receive GET requests to /good_bye and /good_bye/:name
//!        "good_bye" => {
//!            Get: Greeting("good bye"),
//!            ":name" => Get: Greeting("good bye")
//!        }
//!    }
//!};
//!
//!Server {
//!    //Use a closure to handle requests.
//!    handlers: my_router,
//!    //Set the listening port to `8080`.
//!    host: 8080.into(),
//!    //Fill out everything else with default values.
//!    ..Server::default()
//!}.run();
//!# }
//!```
//!
//![server]: server/struct.Server.html

#![crate_name = "rustful"]

#![crate_type = "rlib"]

#![doc(html_root_url = "http://ogeon.github.io/docs/rustful/master/")]

#![cfg_attr(all(test, feature = "benchmark"), feature(test))]
#![cfg_attr(feature = "strict", deny(missing_docs))]
#![cfg_attr(feature = "strict", deny(warnings))]

#[cfg(test)]
#[cfg(feature = "benchmark")]
extern crate test;

#[cfg(test)]
extern crate tempdir;

#[cfg(feature = "rustc-serialize")]
extern crate rustc_serialize;

#[cfg(feature = "multipart")]
extern crate multipart;

extern crate url;
extern crate time;
extern crate hyper;
extern crate anymap;
extern crate phf;

pub use hyper::mime;
pub use hyper::method::Method;
pub use hyper::status::StatusCode;
pub use hyper::header;
pub use hyper::Result as HttpResult;
pub use hyper::Error as HttpError;
pub use hyper::version::HttpVersion;

pub use self::server::Server;
pub use self::context::Context;
pub use self::response::Response;
pub use self::response::Error;
pub use self::handler::Handler;
pub use self::router::Router;
pub use self::log::Log;
pub use self::router::TreeRouter;

mod utils;
#[macro_use]
#[doc(hidden)]
pub mod macros;

pub mod server;
pub mod router;
pub mod handler;
pub mod context;
pub mod response;
pub mod filter;
pub mod log;
pub mod file;

use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr};
use std::str::FromStr;
use std::any::TypeId;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::borrow::Borrow;
use std::hash::Hash;

use anymap::Map;
use anymap::any::{Any, UncheckedAnyExt};

///HTTP or HTTPS.
pub enum Scheme {
    ///Standard HTTP.
    Http,

    ///HTTP with SSL encryption.
    #[cfg(feature = "ssl")]
    Https {
        ///Path to SSL certificate.
        cert: std::path::PathBuf,

        ///Path to key file.
        key: std::path::PathBuf
    }
}

///A host address and a port.
///
///Can be conveniently converted from an existing address-port pair or just a port:
///
///```
///use std::net::Ipv4Addr;
///use rustful::Host;
///
///let host1: Host = (Ipv4Addr::new(0, 0, 0, 0), 80).into();
///let host2: Host = 80.into();
///
///assert_eq!(host1, host2);
///```
#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
pub struct Host(SocketAddr);

impl Host {
    ///Create a `Host` with the address `0.0.0.0:port`. This is the same as `port.into()`.
    pub fn any_v4(port: u16) -> Host {
        Host(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port)))
    }

    ///Change the port of the host address.
    pub fn port(&mut self, port: u16) {
        self.0 = match self.0 {
            SocketAddr::V4(addr) => SocketAddr::V4(SocketAddrV4::new(addr.ip().clone(), port)),
            SocketAddr::V6(addr) => {
                SocketAddr::V6(SocketAddrV6::new(addr.ip().clone(), port, addr.flowinfo(), addr.scope_id()))
            }
        };
    }
}

impl From<Host> for SocketAddr {
    fn from(host: Host) -> SocketAddr {
        host.0
    }
}

impl From<u16> for Host {
    fn from(port: u16) -> Host {
        Host::any_v4(port)
    }
}

impl From<SocketAddr> for Host {
    fn from(addr: SocketAddr) -> Host {
        Host(addr)
    }
}

impl From<SocketAddrV4> for Host {
    fn from(addr: SocketAddrV4) -> Host {
        Host(SocketAddr::V4(addr))
    }
}

impl From<SocketAddrV6> for Host {
    fn from(addr: SocketAddrV6) -> Host {
        Host(SocketAddr::V6(addr))
    }
}

impl From<(Ipv4Addr, u16)> for Host {
    fn from((ip, port): (Ipv4Addr, u16)) -> Host {
        Host(SocketAddr::V4(SocketAddrV4::new(ip, port)))
    }
}

impl FromStr for Host {
    type Err = <SocketAddr as FromStr>::Err;

    fn from_str(s: &str) -> Result<Host, Self::Err> {
        s.parse().map(|s| Host(s))
    }
}

///A somewhat lazy container for globally accessible data.
///
///It will try to be as simple as possible and allocate as little as possible,
///depending on the number of stored values.
///
/// * No value: Nothing is allocated and nothing is searched for during
///access.
///
/// * One value: One `Box` is allocated. Searching for a value will only
///consist of a comparison of `TypeId` and a downcast.
///
/// * Multiple values: An `AnyMap` is created, as well as a `Box` for each
///value. Searching for a value has the full overhead of `AnyMap`.
///
///`Global` can be created from a boxed value, from tuples or using the
///`Default` trait. More values can then be added using `insert(value)`.
///
///```
///# use rustful::Global;
///let mut g1: Global = Box::new(5).into();
///assert_eq!(g1.get(), Some(&5));
///assert_eq!(g1.get::<&str>(), None);
///
///let old = g1.insert(10);
///assert_eq!(old, Some(5));
///assert_eq!(g1.get(), Some(&10));
///
///g1.insert("cat");
///assert_eq!(g1.get(), Some(&10));
///assert_eq!(g1.get(), Some(&"cat"));
///
///let g2: Global = (5, "cat").into();
///assert_eq!(g2.get(), Some(&5));
///assert_eq!(g2.get(), Some(&"cat"));
///```
pub struct Global(GlobalState);

impl Global {
    ///Borrow a value of type `T` if the there is one.
    pub fn get<T: Any + Send + Sync>(&self) -> Option<&T> {
        match self.0 {
            GlobalState::None => None,
            GlobalState::One(id, ref a) => if id == TypeId::of::<T>() {
                //Here be dragons!
                unsafe { Some(a.downcast_ref_unchecked()) }
            } else {
                None
            },
            GlobalState::Many(ref map) => map.get()
        }
    }

    ///Insert a new value, returning the previous value of the same type, if
    ///any.
    pub fn insert<T: Any + Send + Sync>(&mut self, value: T) -> Option<T> {
        match self.0 {
            GlobalState::None => {
                *self = Box::new(value).into();
                None
            },
            GlobalState::One(id, _) => if id == TypeId::of::<T>() {
                if let GlobalState::One(_, ref mut previous_value) = self.0 {
                    let mut v = Box::new(value) as Box<Any + Send + Sync>;
                    std::mem::swap(previous_value, &mut v);
                    Some(unsafe { *v.downcast_unchecked() })
                } else {
                    unreachable!()
                }
            } else {
                //Here be more dragons!
                let mut other = GlobalState::Many(Map::new());
                std::mem::swap(&mut self.0, &mut other);
                if let GlobalState::Many(ref mut map) = self.0 {
                    if let GlobalState::One(id, previous_value) = other {
                        let mut raw = map.as_mut();
                        unsafe { raw.insert(id, previous_value); }
                    }

                    map.insert(value)
                } else {
                    unreachable!()
                }
            },
            GlobalState::Many(ref mut map) => {
                map.insert(value)
            }
        }
    }
}

impl<T: Any + Send + Sync> From<Box<T>> for Global {
    fn from(data: Box<T>) -> Global {
        Global(GlobalState::One(TypeId::of::<T>(), data))
    }
}

macro_rules! from_tuple {
    ($first: ident, $($t: ident),+) => (
        impl<$first: Any + Send + Sync, $($t: Any + Send + Sync),+> From<($first, $($t),+)> for Global {
            #[allow(non_snake_case)]
            fn from(tuple: ($first, $($t),+))-> Global {
                let ($first, $($t),+) = tuple;
                let mut map = Map::new();
                map.insert($first);
                $(
                    map.insert($t);
                )+

                Global(GlobalState::Many(map))
            }
        }

        from_tuple!($($t),+);
    );
    ($ty: ident) => (
        impl<$ty: Any + Send + Sync> From<($ty,)> for Global {
            fn from(tuple: ($ty,)) -> Global {
                Box::new(tuple.0).into()
            }
        }
    );
}

impl From<()> for Global {
    fn from(_: ()) -> Global {
        Global(GlobalState::None)
    }
}

from_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);

impl Default for Global {
    fn default() -> Global {
        Global(GlobalState::None)
    }
}

enum GlobalState {
    None,
    One(TypeId, Box<Any + Send + Sync>),
    Many(Map<Any + Send + Sync>),
}

///An extended `HashMap` with extra functionality for value partsing.
pub struct Parameters<K, V>(HashMap<K, V>);

impl<K: Hash + Eq, V: AsRef<str>> Parameters<K, V> {
    ///Try to parse an entry as `T`, if it exists. The error will be `None` if
    ///the entry does not exist, and `Some` if it does exists, but the parsing
    ///failed.
    ///
    ///```
    ///# use rustful::{Context, Response};
    ///fn my_handler(context: Context, response: Response) {
    ///    let age: Result<u8, _> = context.variables.parse("age");
    ///    match age {
    ///        Ok(age) => response.send(format!("age: {}", age)),
    ///        Err(Some(_)) => response.send("age must be a positive number"),
    ///        Err(None) => response.send("no age provided")
    ///    }
    ///}
    ///```
    pub fn parse<Q: ?Sized, T>(&self, key: &Q) -> Result<T, Option<T::Err>> where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr
    {
        if let Some(val) = self.0.get(key) {
            val.as_ref().parse().map_err(|e| Some(e))
        } else {
            Err(None)
        }
    }

    ///Try to parse an entry as `T`, if it exists, or return the default in
    ///`or`.
    ///
    ///```
    ///# use rustful::{Context, Response};
    ///fn my_handler(context: Context, response: Response) {
    ///    let page = context.variables.parse_or("page", 0u8);
    ///    response.send(format!("current page: {}", page));
    ///}
    ///```
    pub fn parse_or<Q: ?Sized, T>(&self, key: &Q, or: T) -> T where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr
    {
        self.parse(key).unwrap_or(or)
    }

    ///Try to parse an entry as `T`, if it exists, or create a new one using
    ///`or_else`. The `or_else` function will receive the parsing error if the
    ///value existed, but was impossible to parse.
    ///
    ///```
    ///# use rustful::{Context, Response};
    ///# fn do_heavy_stuff() -> u8 {0}
    ///fn my_handler(context: Context, response: Response) {
    ///    let science = context.variables.parse_or_else("science", |_| do_heavy_stuff());
    ///    response.send(format!("science value: {}", science));
    ///}
    ///```
    pub fn parse_or_else<Q: ?Sized, T, F>(&self, key: &Q, or_else: F) -> T where
        K: Borrow<Q>,
        Q: Hash + Eq,
        T: FromStr,
        F: FnOnce(Option<T::Err>) -> T
    {
        self.parse(key).unwrap_or_else(or_else)
    }
}

impl<K, V> Deref for Parameters<K, V> {
    type Target = HashMap<K, V>;

    fn deref(&self) -> &HashMap<K, V> {
        &self.0
    }
}

impl<K, V> DerefMut for Parameters<K, V> {
    fn deref_mut(&mut self) -> &mut HashMap<K, V> {
        &mut self.0
    }
}

impl<K, V> Into<HashMap<K, V>> for Parameters<K, V> {
    fn into(self) -> HashMap<K, V> {
        self.0
    }
}

impl<K, V> From<HashMap<K, V>> for Parameters<K, V> {
    fn from(map: HashMap<K, V>) -> Parameters<K, V> {
        Parameters(map)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;

use std::ffi::CString;
mod postgres;

use postgres::{
    LogicalDecodingContext,
    OutputPluginOptions,
    ReorderBufferTXN,
    Relation,
    ReorderBufferChange,
    TupleDesc,
    HeapTuple,
    Struct_HeapTupleData,
    OUTPUT_PLUGIN_TEXTUAL_OUTPUT,
    REORDER_BUFFER_CHANGE_INSERT,
    REORDER_BUFFER_CHANGE_UPDATE,
    REORDER_BUFFER_CHANGE_DELETE,
};

#[derive(Debug)]
pub struct WrappedPG {
    pub num_attributes: i32,
    pub fields:         Vec<Field>,
}

#[derive(Debug)]
pub struct Field {
    pub name:  String,
    pub value: String,
}

extern {
  fn OutputPluginPrepareWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn OutputPluginWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn appendStringInfoString(str: *mut postgres::Struct_StringInfoData, s: *const i8);
}

#[no_mangle]
pub extern fn pg_decode_startup(ctx: &LogicalDecodingContext, opt: &mut OutputPluginOptions, is_init: bool) {
	opt.output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

#[no_mangle]
pub extern fn pg_decode_change(ctx:      &LogicalDecodingContext,
                               txn:      &ReorderBufferTXN,
                               relation: Relation,
                               change:   &mut ReorderBufferChange) {

    let action_string = match change.action {
        REORDER_BUFFER_CHANGE_INSERT => { "Insert " },
        REORDER_BUFFER_CHANGE_UPDATE => { "Update " },
        REORDER_BUFFER_CHANGE_DELETE => { "Delete " },
        _                            => { "Other " },
    };

    let c_action_string = CString::new(action_string).unwrap();

    unsafe {
        OutputPluginPrepareWrite(ctx, true);
        appendStringInfoString(ctx.out, c_action_string.as_ptr());
    }

    match change.action {
        REORDER_BUFFER_CHANGE_INSERT => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*(*change.data.tp()).newtuple).tuple }
            );

            let output         = format!("{:?}", tuple);
            let c_tuple_string = CString::new(&output[..]).unwrap();

            unsafe {
                appendStringInfoString(ctx.out, c_tuple_string.as_ptr());
            }
        },
        // REORDER_BUFFER_CHANGE_UPDATE => { "Update".to_string() },
        // REORDER_BUFFER_CHANGE_DELETE => { "Delete".to_string() },
        _                            => {},
    };

    unsafe { OutputPluginWrite(ctx, true); }
}

// type TupleDesc = *mut Struct_tupleDesc
//   which is: struct Struct_tupleDesc {
//                      natts: ::libc::c_int,
//                      attrs: *mut Form_pg_attribute,
//                      tdtypeid: Oid,
pub fn pg_tuple_to_rspgod_tuple(description:TupleDesc, tuple:Struct_HeapTupleData) -> WrappedPG {
    let num_attributes = unsafe { (*description).natts };
    let mut fields     = vec![];

    for n in 0..num_attributes {
        // for each attribute
        //   get any value off of it (eg attnum)
        let attnum = unsafe { 5 };
        let thing  = format!("{}", attnum);
        fields.push(Field { name: thing.clone(), value: thing.clone() });
    }

    WrappedPG {
        num_attributes: num_attributes,
        fields:         fields,
    }
}
    // tuple_to_avro_row (from bottledwater)
    //   this works by modifying a pointer to the (avro_value_t *output_value)
    //   or returning (at the end, or via the `check` macro) an error int
    // -----------------------------------------------------
    // int err = 0, field = 0;
    // check(err, avro_value_reset(output_val));
    // for (int i = 0; i < tupdesc->natts; i++) {
    //     avro_value_t field_val;
    //     bool isnull;
    //     Datum datum;
    //     Form_pg_attribute attr = tupdesc->attrs[i];
    //     if (attr->attisdropped) continue; /* skip dropped columns */
    //     check(err, avro_value_get_by_index(output_val, field, &field_val, NULL));
    //     datum = heap_getattr(tuple, i + 1, tupdesc, &isnull);
    //     if (isnull) {
    //         check(err, avro_value_set_branch(&field_val, 0, NULL));
    //     } else {
    //         check(err, update_avro_with_datum(&field_val, attr->atttypid, datum));
    //     }
    //     field++;
    // }
    // return err;

    // /* ----------------
    //  *		heap_getattr
    //  *
    //  *		Extract an attribute of a heap tuple and return it as a Datum.
    //  *		This works for either system or user attributes.  The given attnum
    //  *		is properly range-checked.
    //  *
    //  *		If the field in question has a NULL value, we return a zero Datum
    //  *		and set *isnull == true.  Otherwise, we set *isnull == false.
    //  *
    //  *		<tup> is the pointer to the heap tuple.  <attnum> is the attribute
    //  *		number of the column (field) caller wants.  <tupleDesc> is a
    //  *		pointer to the structure describing the row and all its fields.
    //  * ----------------
    //  */
    // #define heap_getattr(tup, attnum, tupleDesc, isnull) \
    // 	( \
    // 		((attnum) > 0) ? \
    // 		( \
    // 			((attnum) > (int) HeapTupleHeaderGetNatts((tup)->t_data)) ? \
    // 			( \
    // 				(*(isnull) = true), \
    // 				(Datum)NULL \
    // 			) \
    // 			: \
    // 				fastgetattr((tup), (attnum), (tupleDesc), (isnull)) \
    // 		) \
    // 		: \
    // 			heap_getsysattr((tup), (attnum), (tupleDesc), (isnull)) \
    // 	)
//
    // /* ----------------
    //  *		fastgetattr
    //  *
    //  *		Fetch a user attribute's value as a Datum (might be either a
    //  *		value, or a pointer into the data area of the tuple).
    //  *
    //  *		This must not be used when a system attribute might be requested.
    //  *		Furthermore, the passed attnum MUST be valid.  Use heap_getattr()
    //  *		instead, if in doubt.
    //  *
    //  *		This gets called many times, so we macro the cacheable and NULL
    //  *		lookups, and call nocachegetattr() for the rest.
    //  * ----------------
    //  */
    //
    // #if !defined(DISABLE_COMPLEX_MACRO)
    //
    // #define fastgetattr(tup, attnum, tupleDesc, isnull)					\
    // (																	\
    // 	AssertMacro((attnum) > 0),										\
    // 	(*(isnull) = false),											\
    // 	HeapTupleNoNulls(tup) ?											\
    // 	(																\
    // 		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ?			\
    // 		(															\
    // 			fetchatt((tupleDesc)->attrs[(attnum)-1],				\
    // 				(char *) (tup)->t_data + (tup)->t_data->t_hoff +	\
    // 					(tupleDesc)->attrs[(attnum)-1]->attcacheoff)	\
    // 		)															\
    // 		:															\
    // 			nocachegetattr((tup), (attnum), (tupleDesc))			\
    // 	)																\
    // 	:																\
    // 	(																\
    // 		att_isnull((attnum)-1, (tup)->t_data->t_bits) ?				\
    // 		(															\
    // 			(*(isnull) = true),										\
    // 			(Datum)NULL												\
    // 		)															\
    // 		:															\
    // 		(															\
    // 			nocachegetattr((tup), (attnum), (tupleDesc))			\
    // 		)															\
    // 	)																\
    // )
    // #else							/* defined(DISABLE_COMPLEX_MACRO) */
    //
    // extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
    // 			bool *isnull);
    // #endif   /* defined(DISABLE_COMPLEX_MACRO) */

#[no_mangle]
pub extern fn pg_decode_commit_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN, commit_lsn: u64) {
}

#[no_mangle]
pub extern fn pg_decode_begin_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN) {
}

#[no_mangle]
pub extern fn pg_decode_shutdown(ctx: &LogicalDecodingContext) {
}

<commit_msg>Data comes from the attribute<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;

use std::ffi::CString;
mod postgres;

use postgres::{
    LogicalDecodingContext,
    OutputPluginOptions,
    ReorderBufferTXN,
    Relation,
    ReorderBufferChange,
    TupleDesc,
    HeapTuple,
    Struct_HeapTupleData,
    OUTPUT_PLUGIN_TEXTUAL_OUTPUT,
    REORDER_BUFFER_CHANGE_INSERT,
    REORDER_BUFFER_CHANGE_UPDATE,
    REORDER_BUFFER_CHANGE_DELETE,
};

#[derive(Debug)]
pub struct WrappedPG {
    pub num_attributes: i32,
    pub fields:         Vec<Field>,
}

#[derive(Debug)]
pub struct Field {
    pub name:  String,
    pub value: String,
}

extern {
  fn OutputPluginPrepareWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn OutputPluginWrite(ctx: &LogicalDecodingContext, last_write: bool);
  fn appendStringInfoString(str: *mut postgres::Struct_StringInfoData, s: *const i8);
}

#[no_mangle]
pub extern fn pg_decode_startup(ctx: &LogicalDecodingContext, opt: &mut OutputPluginOptions, is_init: bool) {
	opt.output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
}

#[no_mangle]
pub extern fn pg_decode_change(ctx:      &LogicalDecodingContext,
                               txn:      &ReorderBufferTXN,
                               relation: Relation,
                               change:   &mut ReorderBufferChange) {

    let action_string = match change.action {
        REORDER_BUFFER_CHANGE_INSERT => { "Insert " },
        REORDER_BUFFER_CHANGE_UPDATE => { "Update " },
        REORDER_BUFFER_CHANGE_DELETE => { "Delete " },
        _                            => { "Other " },
    };

    let c_action_string = CString::new(action_string).unwrap();

    unsafe {
        OutputPluginPrepareWrite(ctx, true);
        appendStringInfoString(ctx.out, c_action_string.as_ptr());
    }

    match change.action {
        REORDER_BUFFER_CHANGE_INSERT => {
            let tuple = pg_tuple_to_rspgod_tuple(
                unsafe { (*relation).rd_att },
                unsafe { (*(*change.data.tp()).newtuple).tuple }
            );

            let output         = format!("{:?}", tuple);
            let c_tuple_string = CString::new(&output[..]).unwrap();

            unsafe {
                appendStringInfoString(ctx.out, c_tuple_string.as_ptr());
            }
        },
        // REORDER_BUFFER_CHANGE_UPDATE => { "Update".to_string() },
        // REORDER_BUFFER_CHANGE_DELETE => { "Delete".to_string() },
        _                            => {},
    };

    unsafe { OutputPluginWrite(ctx, true); }
}

// type TupleDesc = *mut Struct_tupleDesc
//   which is: struct Struct_tupleDesc {
//                      natts: ::libc::c_int,
//                      attrs: *mut Form_pg_attribute,
//                      tdtypeid: Oid,
pub fn pg_tuple_to_rspgod_tuple(description:TupleDesc, tuple:Struct_HeapTupleData) -> WrappedPG {
    let raw_desc       = unsafe { *description };
    let num_attributes = raw_desc.natts;
    let mut fields     = vec![];

    for n in 0..num_attributes {
        // for each attribute
        //   get any value off of it (eg attnum)
        let attnum = unsafe { (**raw_desc.attrs.offset(n as isize)).attnum };
        let thing  = format!("{}", attnum);
        fields.push(Field { name: thing.clone(), value: thing.clone() });
    }

    WrappedPG {
        num_attributes: num_attributes,
        fields:         fields,
    }
}
    // tuple_to_avro_row (from bottledwater)
    //   this works by modifying a pointer to the (avro_value_t *output_value)
    //   or returning (at the end, or via the `check` macro) an error int
    // -----------------------------------------------------
    // int err = 0, field = 0;
    // check(err, avro_value_reset(output_val));
    // for (int i = 0; i < tupdesc->natts; i++) {
    //     avro_value_t field_val;
    //     bool isnull;
    //     Datum datum;
    //     Form_pg_attribute attr = tupdesc->attrs[i];
    //     if (attr->attisdropped) continue; /* skip dropped columns */
    //     check(err, avro_value_get_by_index(output_val, field, &field_val, NULL));
    //     datum = heap_getattr(tuple, i + 1, tupdesc, &isnull);
    //     if (isnull) {
    //         check(err, avro_value_set_branch(&field_val, 0, NULL));
    //     } else {
    //         check(err, update_avro_with_datum(&field_val, attr->atttypid, datum));
    //     }
    //     field++;
    // }
    // return err;

    // /* ----------------
    //  *		heap_getattr
    //  *
    //  *		Extract an attribute of a heap tuple and return it as a Datum.
    //  *		This works for either system or user attributes.  The given attnum
    //  *		is properly range-checked.
    //  *
    //  *		If the field in question has a NULL value, we return a zero Datum
    //  *		and set *isnull == true.  Otherwise, we set *isnull == false.
    //  *
    //  *		<tup> is the pointer to the heap tuple.  <attnum> is the attribute
    //  *		number of the column (field) caller wants.  <tupleDesc> is a
    //  *		pointer to the structure describing the row and all its fields.
    //  * ----------------
    //  */
    // #define heap_getattr(tup, attnum, tupleDesc, isnull) \
    // 	( \
    // 		((attnum) > 0) ? \
    // 		( \
    // 			((attnum) > (int) HeapTupleHeaderGetNatts((tup)->t_data)) ? \
    // 			( \
    // 				(*(isnull) = true), \
    // 				(Datum)NULL \
    // 			) \
    // 			: \
    // 				fastgetattr((tup), (attnum), (tupleDesc), (isnull)) \
    // 		) \
    // 		: \
    // 			heap_getsysattr((tup), (attnum), (tupleDesc), (isnull)) \
    // 	)
//
    // /* ----------------
    //  *		fastgetattr
    //  *
    //  *		Fetch a user attribute's value as a Datum (might be either a
    //  *		value, or a pointer into the data area of the tuple).
    //  *
    //  *		This must not be used when a system attribute might be requested.
    //  *		Furthermore, the passed attnum MUST be valid.  Use heap_getattr()
    //  *		instead, if in doubt.
    //  *
    //  *		This gets called many times, so we macro the cacheable and NULL
    //  *		lookups, and call nocachegetattr() for the rest.
    //  * ----------------
    //  */
    //
    // #if !defined(DISABLE_COMPLEX_MACRO)
    //
    // #define fastgetattr(tup, attnum, tupleDesc, isnull)					\
    // (																	\
    // 	AssertMacro((attnum) > 0),										\
    // 	(*(isnull) = false),											\
    // 	HeapTupleNoNulls(tup) ?											\
    // 	(																\
    // 		(tupleDesc)->attrs[(attnum)-1]->attcacheoff >= 0 ?			\
    // 		(															\
    // 			fetchatt((tupleDesc)->attrs[(attnum)-1],				\
    // 				(char *) (tup)->t_data + (tup)->t_data->t_hoff +	\
    // 					(tupleDesc)->attrs[(attnum)-1]->attcacheoff)	\
    // 		)															\
    // 		:															\
    // 			nocachegetattr((tup), (attnum), (tupleDesc))			\
    // 	)																\
    // 	:																\
    // 	(																\
    // 		att_isnull((attnum)-1, (tup)->t_data->t_bits) ?				\
    // 		(															\
    // 			(*(isnull) = true),										\
    // 			(Datum)NULL												\
    // 		)															\
    // 		:															\
    // 		(															\
    // 			nocachegetattr((tup), (attnum), (tupleDesc))			\
    // 		)															\
    // 	)																\
    // )
    // #else							/* defined(DISABLE_COMPLEX_MACRO) */
    //
    // extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
    // 			bool *isnull);
    // #endif   /* defined(DISABLE_COMPLEX_MACRO) */

#[no_mangle]
pub extern fn pg_decode_commit_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN, commit_lsn: u64) {
}

#[no_mangle]
pub extern fn pg_decode_begin_txn(ctx: &LogicalDecodingContext, txn: &ReorderBufferTXN) {
}

#[no_mangle]
pub extern fn pg_decode_shutdown(ctx: &LogicalDecodingContext) {
}

<|endoftext|>