<commit_before>use scene::{Scene, BoxedScene, SceneCommand};
use opengl_graphics::GlGraphics;
use event::{RenderArgs, UpdateArgs};
use input::{Button, Key};
use graphics;
use graphics::Transformed;
use entity::{Entity, RcEntity};
use keyhandler::KeyHandler;
use std::cell::RefCell;

#[derive(Clone)]
enum CellState {
    Empty,
    Dirt,
    Stone,
    Wall
}

struct World {
    cells: Vec<CellState>,
    entities: Vec<RcEntity>,
    player: RcEntity,
    width: u32,
    height: u32
}

impl World {
    pub fn new(width: u32, height: u32) -> World {
        let mut entities = vec![];
        let mut cells = vec![CellState::Dirt; (width * height) as usize];
        let player = Entity::new(1,1);
        let borrow = player.clone();
        entities.push(player);
        cells[1] = CellState::Empty;
        cells[width as usize] = CellState::Empty;
        cells[width as usize + 1] = CellState::Empty;
        cells[width as usize + 2] = CellState::Empty;
        cells[(width as usize * 2) + 1] = CellState::Empty;

        World {
            cells: cells,
            entities: entities,
            width: width,
            height: height,
            player: borrow
        }
    }

    pub fn render(&self, context: &graphics::Context, gl: &mut GlGraphics, tick: u64) {
        for entity in self.entities.iter() {
            entity.borrow().render(context, gl, tick);
        }
    }
}

pub struct GameScene {
    quit: bool,
    world: World,
    keyhandler: KeyHandler,
    tick: u64,
    camera_pos: (f64, f64)
}

impl GameScene {
    pub fn new() -> BoxedScene {
        Box::new(GameScene {
            quit: false,
            world: World::new(100, 100),
            keyhandler: KeyHandler::new(),
            tick: 0,
            camera_pos: (0.0, 0.0)
        })
    }
}

impl Scene for GameScene {
    fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const BROWN: [f32; 4] = [0.2, 0.2, 0.0, 1.0];
        const GREY: [f32; 4] = [0.2, 0.2, 0.2, 1.0];
        const WHITE: [f32; 4] = [1.0; 4];
        const CELL_SIZE: u32 = 32;

        let (camera_x, camera_y) = self.camera_pos;

        let context = &graphics::Context::abs(args.width as f64, args.height as f64)
            .trans(((args.width / 2) - (CELL_SIZE / 2)) as f64, ((args.height / 2) - (CELL_SIZE / 2)) as f64) //Camera is in the centre of the screen
            .trans(-camera_x, -camera_y);

        gl.draw(args.viewport(), |_, gl| {
            graphics::clear(BLACK, gl);
            for (i, cell) in self.world.cells.iter().enumerate() {
                let x = (i as u32 % self.world.width) * CELL_SIZE;
                let y = (i as u32 / self.world.height) * CELL_SIZE;

                match *cell {
                    CellState::Dirt => {
                        graphics::rectangle(BROWN, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    },
                    CellState::Stone => {
                        graphics::rectangle(GREY, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    },
                    CellState::Wall => {
                        graphics::rectangle(WHITE, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    }
                    _ => ()
                }
            };
            self.world.render(context, gl, self.tick);
        });

    }
    fn think(&mut self, args: &UpdateArgs) -> Option<SceneCommand> {
        self.tick += (args.dt * 100000.0) as u64;
        self.keyhandler.think(self.tick);

        if self.tick / 1000 % 10 == 0 {
            //FIXME: Make this use weak references once we have them
            let entity = self.world.player.clone();
            //Move existing
            entity.borrow_mut().think(self.tick);
            //Handle player input
            //FIXME: Make player input less painful
            match self.keyhandler.last_key() {
                Some((key, tick)) => {
                    let difference = self.tick - tick;
                    if difference < 8000 || difference > 20000 {
                        entity.borrow_mut().input(key);
                    }
                },
                None => ()
            }
        }

        if self.quit {
            Some(SceneCommand::PopScene)
        } else {
            None
        }
    }

    fn press(&mut self, button: &Button) {
        match button {
            &Button::Keyboard(key) => {
                self.keyhandler.press(key)
            },
            _ => ()
        };
        //self.quit = true;
    }

    fn release(&mut self, button: &Button) {
        match button {
            &Button::Keyboard(key) => {
                self.keyhandler.release(key)
            },
            _ => ()
        };
    }
}
<commit_msg>Working at fetching points<commit_after>use scene::{Scene, BoxedScene, SceneCommand};
use opengl_graphics::GlGraphics;
use event::{RenderArgs, UpdateArgs};
use input::{Button, Key};
use graphics;
use graphics::Transformed;
use entity::{Entity, RcEntity};
use keyhandler::KeyHandler;
use std::cell::RefCell;

#[derive(Clone)]
enum CellState {
    Empty,
    Dirt,
    Stone,
    Wall
}

struct World {
    cells: Vec<CellState>,
    entities: Vec<RcEntity>,
    player: RcEntity,
    width: u32,
    height: u32
}

impl World {
    pub fn new(width: u32, height: u32) -> World {
        let mut entities = vec![];
        let mut cells = vec![CellState::Dirt; (width * height) as usize];
        let player = Entity::new(1,1);
        let borrow = player.clone();
        entities.push(player);
        cells[1] = CellState::Empty;
        cells[width as usize] = CellState::Empty;
        cells[width as usize + 1] = CellState::Empty;
        cells[width as usize + 2] = CellState::Empty;
        cells[(width as usize * 2) + 1] = CellState::Empty;

        World {
            cells: cells,
            entities: entities,
            width: width,
            height: height,
            player: borrow
        }
    }

    pub fn render(&self, context: &graphics::Context, gl: &mut GlGraphics, tick: u64) {
        for entity in self.entities.iter() {
            entity.borrow().render(context, gl, tick);
        }
    }

    pub fn at_pos(&self, x: u32, y: u32) -> (CellState, Option<RcEntity>) {
        let index = x + (y * self.world.width);
        return (self.world.cells[index], None);
    }

    pub fn set_pos(&mut self, x: u32, y: u32, state: CellState) {
        let index = x + (y * self.world.width);
        self.world.cells[index] = state;
    }
}

pub struct GameScene {
    quit: bool,
    world: World,
    keyhandler: KeyHandler,
    tick: u64,
    camera_pos: (f64, f64)
}

impl GameScene {
    pub fn new() -> BoxedScene {
        Box::new(GameScene {
            quit: false,
            world: World::new(10, 10),
            keyhandler: KeyHandler::new(),
            tick: 0,
            camera_pos: (0.0, 0.0)
        })
    }
}

impl Scene for GameScene {
    fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const BROWN: [f32; 4] = [0.2, 0.2, 0.0, 1.0];
        const GREY: [f32; 4] = [0.2, 0.2, 0.2, 1.0];
        const WHITE: [f32; 4] = [1.0; 4];
        const CELL_SIZE: u32 = 32;

        let (camera_x, camera_y) = self.camera_pos;

        let context = &graphics::Context::abs(args.width as f64, args.height as f64)
            .trans(((args.width / 2) - (CELL_SIZE / 2)) as f64, ((args.height / 2) - (CELL_SIZE / 2)) as f64) //Camera is in the centre of the screen
            .trans(-camera_x, -camera_y);

        gl.draw(args.viewport(), |_, gl| {
            graphics::clear(BLACK, gl);
            for (i, cell) in self.world.cells.iter().enumerate() {
                let x = (i as u32 % self.world.width) * CELL_SIZE;
                let y = (i as u32 / self.world.height) * CELL_SIZE;

                match *cell {
                    CellState::Dirt => {
                        graphics::rectangle(BROWN, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    },
                    CellState::Stone => {
                        graphics::rectangle(GREY, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    },
                    CellState::Wall => {
                        graphics::rectangle(WHITE, graphics::rectangle::square(x as f64, y as f64, CELL_SIZE as f64), context.transform, gl);
                    }
                    _ => ()
                }
            };
            self.world.render(context, gl, self.tick);
        });

    }
    fn think(&mut self, args: &UpdateArgs) -> Option<SceneCommand> {
        self.tick += (args.dt * 100000.0) as u64;
        self.keyhandler.think(self.tick);

        if self.tick / 1000 % 10 == 0 {
            //FIXME: Make this use weak references once we have them
            let entity = self.world.player.clone();
            //Move existing
            entity.borrow_mut().think(self.tick);
            //Handle player input
            //FIXME: Make player input less painful
            match self.keyhandler.last_key() {
                Some((key, tick)) => {
                    let difference = self.tick - tick;
                    if difference < 8000 || difference > 20000 {
                        entity.borrow_mut().input(key);
                    }
                },
                None => ()
            }
        }

        if self.quit {
            Some(SceneCommand::PopScene)
        } else {
            None
        }
    }

    fn press(&mut self, button: &Button) {
        match button {
            &Button::Keyboard(key) => {
                self.keyhandler.press(key)
            },
            _ => ()
        };
        //self.quit = true;
    }

    fn release(&mut self, button: &Button) {
        match button {
            &Button::Keyboard(key) => {
                self.keyhandler.release(key)
            },
            _ => ()
        };
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! Private functions and items to be used with the high-level library wrapper.

use std::cast;
use std::libc::*;
use std::local_data;
use std::str;

use super::*;

// Global callbacks

static error_fun_tls_key: local_data::Key<ErrorFun> = &local_data::Key;

pub extern "C" fn error_callback(error: c_int, description: *c_char) {
    unsafe {
        do local_data::get(error_fun_tls_key) |data| {
            do data.map |&ref cb| {
                (**cb)(error, str::raw::from_c_str(description))
            };
        }
    }
}

pub fn set_error_fun(cbfun: ErrorFun, f: &fn(ffi::GLFWerrorfun) ) {
    local_data::set(error_fun_tls_key, cbfun);
    f(error_callback);
}

static monitor_fun_tls_key: local_data::Key<MonitorFun> = &local_data::Key;

pub extern "C" fn monitor_callback(monitor: *ffi::GLFWmonitor, event: c_int) {
    do local_data::get(monitor_fun_tls_key) |data| {
        do data.map |&ref cb| {
            (**cb)(&Monitor { ptr: monitor }, event)
        };
    }
}

pub fn set_monitor_fun(cbfun: MonitorFun, f: &fn(ffi::GLFWmonitorfun) ) {
    local_data::set(monitor_fun_tls_key, cbfun);
    f(monitor_callback);
}

// External window callbacks
#[fixed_stack_segment]
unsafe fn get_fns(window: *ffi::GLFWwindow) -> &WindowFns {
    cast::transmute(ffi::glfwGetWindowUserPointer(window))
}

macro_rules! window_callback(
    (fn $name:ident () => $field:ident()) => (
         pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe {
                let window = Window { ptr: window, is_shared: false };
                window.get_fns().$field.map(|cb| (*cb)(&window));
                cast::forget(window);
            }
         }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $field:ident($($arg_conv:expr),*)) => (
         pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe {
                let window = Window { ptr: window, is_shared: false };
                window.get_fns().$field.map(|cb| (*cb)(&window $(, $arg_conv)*));
                cast::forget(window);
            }
         }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => pos_fun(xpos as int, ypos as int))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => size_fun(width as int, height as int))
window_callback!(fn window_close_callback()                                                 => close_fun())
window_callback!(fn window_refresh_callback()                                               => refresh_fun())
window_callback!(fn window_focus_callback(focused: c_int)                                   => focus_fun(focused as bool))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => iconify_fun(iconified as bool))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => framebuffer_size_fun(width as int, height as int))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => mouse_button_fun(button, action, KeyMods(mods)))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => cursor_pos_fun(xpos as float, ypos as float))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => cursor_enter_fun(entered as bool))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => scroll_fun(xpos as float, ypos as float))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => key_fun(key, scancode, action, KeyMods(mods)))
window_callback!(fn char_callback(character: c_uint)                                        => char_fun(character as char))
<commit_msg>Update char conversion<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! Private functions and items to be used with the high-level library wrapper.

use std::cast;
use std::libc::*;
use std::local_data;
use std::str;

use super::*;

// Global callbacks

static error_fun_tls_key: local_data::Key<ErrorFun> = &local_data::Key;

pub extern "C" fn error_callback(error: c_int, description: *c_char) {
    unsafe {
        do local_data::get(error_fun_tls_key) |data| {
            do data.map |&ref cb| {
                (**cb)(error, str::raw::from_c_str(description))
            };
        }
    }
}

pub fn set_error_fun(cbfun: ErrorFun, f: &fn(ffi::GLFWerrorfun) ) {
    local_data::set(error_fun_tls_key, cbfun);
    f(error_callback);
}

static monitor_fun_tls_key: local_data::Key<MonitorFun> = &local_data::Key;

pub extern "C" fn monitor_callback(monitor: *ffi::GLFWmonitor, event: c_int) {
    do local_data::get(monitor_fun_tls_key) |data| {
        do data.map |&ref cb| {
            (**cb)(&Monitor { ptr: monitor }, event)
        };
    }
}

pub fn set_monitor_fun(cbfun: MonitorFun, f: &fn(ffi::GLFWmonitorfun) ) {
    local_data::set(monitor_fun_tls_key, cbfun);
    f(monitor_callback);
}

// External window callbacks
#[fixed_stack_segment]
unsafe fn get_fns(window: *ffi::GLFWwindow) -> &WindowFns {
    cast::transmute(ffi::glfwGetWindowUserPointer(window))
}

macro_rules! window_callback(
    (fn $name:ident () => $field:ident()) => (
         pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe {
                let window = Window { ptr: window, is_shared: false };
                window.get_fns().$field.map(|cb| (*cb)(&window));
                cast::forget(window);
            }
         }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $field:ident($($arg_conv:expr),*)) => (
         pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe {
                let window = Window { ptr: window, is_shared: false };
                window.get_fns().$field.map(|cb| (*cb)(&window $(, $arg_conv)*));
                cast::forget(window);
            }
         }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => pos_fun(xpos as int, ypos as int))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => size_fun(width as int, height as int))
window_callback!(fn window_close_callback()                                                 => close_fun())
window_callback!(fn window_refresh_callback()                                               => refresh_fun())
window_callback!(fn window_focus_callback(focused: c_int)                                   => focus_fun(focused as bool))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => iconify_fun(iconified as bool))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => framebuffer_size_fun(width as int, height as int))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => mouse_button_fun(button, action, KeyMods(mods)))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => cursor_pos_fun(xpos as float, ypos as float))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => cursor_enter_fun(entered as bool))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => scroll_fun(xpos as float, ypos as float))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => key_fun(key, scancode, action, KeyMods(mods)))
window_callback!(fn char_callback(character: c_uint)                                        => char_fun(::std::char::from_u32(character).unwrap()))
<|endoftext|>


<commit_before>//! Issues interface

extern crate serde_json;

use super::{Github, Result};
use comments::Comments;
use users::User;
use labels::Label;
use super::{SortDirection, State as StdState};
use std::fmt;
use std::collections::HashMap;
use url::form_urlencoded;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Assigned,
    Created,
    Mentioned,
    Subscribed,
    All,
}

impl fmt::Display for Filter {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Filter::Assigned => "assigned",
                   Filter::Created => "created",
                   Filter::Mentioned => "mentioned",
                   Filter::Subscribed => "subscribed",
                   Filter::All => "all",
               })
    }
}

impl Default for Filter {
    fn default() -> Filter {
        Filter::Assigned
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

pub struct IssueLabels<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""),
                                try!(serde_json::to_string(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""),
                                      try!(serde_json::to_string(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

pub struct IssueRef<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_str(),
                         self.repo.as_str(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueOptions) -> Result<Issue> {
        let data = try!(serde_json::to_string(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn comments(&self) -> Comments {
        Comments::new(self.github,
                      self.owner.clone(),
                      self.repo.clone(),
                      self.number)
    }
}

pub struct Issues<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_str(), self.repo.as_str(), number)
    }

    pub fn create(&self, is: &IssueOptions) -> Result<Issue> {
        let data = try!(serde_json::to_string(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, options: &IssueListOptions) -> Result<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Issue>>(&uri.join("?"))
    }
}

// representations

// todo: simplify with param
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::new()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
#[derive(Default)]
pub struct IssueListOptionsBuilder {
    params: HashMap<&'static str, String>,
}

impl IssueListOptionsBuilder {
    pub fn new() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder { ..Default::default() }
    }

    pub fn state(&mut self, state: StdState) -> &mut IssueListOptionsBuilder {
        self.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut IssueListOptionsBuilder {
        self.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut IssueListOptionsBuilder {
        self.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut IssueListOptionsBuilder
        where A: Into<String>
    {
        self.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut IssueListOptionsBuilder
        where C: Into<String>
    {
        self.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut IssueListOptionsBuilder
        where M: Into<String>
    {
        self.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut IssueListOptionsBuilder
        where L: Into<String>
    {
        self.params.insert("labels",
                           labels.into_iter().map(|l| l.into()).collect::<Vec<_>>().join(","));
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut IssueListOptionsBuilder
        where S: Into<String>
    {
        self.params.insert("since", since.into());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions { params: self.params.clone() }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(title: T,
                           body: Option<B>,
                           assignee: Option<A>,
                           milestone: Option<u64>,
                           labels: Vec<L>)
                           -> IssueOptions
        where T: Into<String>,
              B: Into<String>,
              A: Into<String>,
              L: Into<String>
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone: milestone,
            labels: labels.into_iter().map(|l| l.into()).collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: String,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

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

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (
                IssueListOptions::builder().build(),
                None
            ),
            (
                IssueListOptions::builder().state(StdState::Closed).build(),
                Some("state=closed".to_owned())
             ),
            (
                IssueListOptions::builder().labels(vec!["foo", "bar"]).build(),
                Some("labels=foo%2Cbar".to_owned())
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn filter_default() {
        let default: Filter = Default::default();
        assert_eq!(default, Filter::Assigned)
    }

    #[test]
    fn filter_display() {
        for (k, v) in vec![
            (Filter::Assigned, "assigned"),
            (Filter::Created, "created"),
            (Filter::Mentioned, "mentioned"),
            (Filter::Subscribed, "subscribed"),
            (Filter::All, "all"),
        ] {
            assert_eq!(k.to_string(), v)
        }
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![(Sort::Created, "created"),
                           (Sort::Updated, "updated"),
                           (Sort::Comments, "comments")] {
            assert_eq!(k.to_string(), v)
        }
    }
}
<commit_msg>remove used filter type, add docs<commit_after>//! Issues interface

extern crate serde_json;

use super::{Github, Result};
use comments::Comments;
use users::User;
use labels::Label;
use super::{SortDirection, State as StdState};
use std::fmt;
use std::collections::HashMap;
use url::form_urlencoded;

#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    Created,
    Updated,
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   Sort::Created => "created",
                   Sort::Updated => "updated",
                   Sort::Comments => "comments",
               })
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

/// Provides access to label operations available for a single issues
pub struct IssueLabels<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueLabels<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}/labels{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github
            .post::<Vec<Label>>(&self.path(""),
                                try!(serde_json::to_string(&labels)).as_bytes())
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github
            .delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(&self.path(""),
                                      try!(serde_json::to_string(&labels)).as_bytes())
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github
            .delete(&self.path(""))
    }
}

/// Provides access to operations available for a single issue
/// Typically accessed from `github.repo(.., ..).issues().get(number)`
pub struct IssueRef<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueRef<'a>
        where O: Into<String>,
              R: Into<String>
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues/{}{}",
                self.owner,
                self.repo,
                self.number,
                more)
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(self.github,
                         self.owner.as_str(),
                         self.repo.as_str(),
                         self.number)
    }

    pub fn edit(&self, is: &IssueOptions) -> Result<Issue> {
        let data = try!(serde_json::to_string(&is));
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn comments(&self) -> Comments {
        Comments::new(self.github,
                      self.owner.clone(),
                      self.repo.clone(),
                      self.number)
    }
}

/// Provides access to operations available for a repository issues
/// Typically accessed via `github.repo(..., ...).issues()`
pub struct Issues<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Issues<'a>
        where O: Into<String>,
              R: Into<String>
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_str(), self.repo.as_str(), number)
    }

    pub fn create(&self, is: &IssueOptions) -> Result<Issue> {
        let data = try!(serde_json::to_string(&is));
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, options: &IssueListOptions) -> Result<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Issue>>(&uri.join("?"))
    }
}

// representations

// todo: simplify with param
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::new()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
#[derive(Default)]
pub struct IssueListOptionsBuilder {
    params: HashMap<&'static str, String>,
}

impl IssueListOptionsBuilder {
    pub fn new() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder { ..Default::default() }
    }

    pub fn state(&mut self, state: StdState) -> &mut IssueListOptionsBuilder {
        self.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut IssueListOptionsBuilder {
        self.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut IssueListOptionsBuilder {
        self.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut IssueListOptionsBuilder
        where A: Into<String>
    {
        self.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut IssueListOptionsBuilder
        where C: Into<String>
    {
        self.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut IssueListOptionsBuilder
        where M: Into<String>
    {
        self.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut IssueListOptionsBuilder
        where L: Into<String>
    {
        self.params.insert("labels",
                           labels.into_iter().map(|l| l.into()).collect::<Vec<_>>().join(","));
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut IssueListOptionsBuilder
        where S: Into<String>
    {
        self.params.insert("since", since.into());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions { params: self.params.clone() }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(title: T,
                           body: Option<B>,
                           assignee: Option<A>,
                           milestone: Option<u64>,
                           labels: Vec<L>)
                           -> IssueOptions
        where T: Into<String>,
              B: Into<String>,
              A: Into<String>,
              L: Into<String>
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone: milestone,
            labels: labels.into_iter().map(|l| l.into()).collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: String,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

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

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (
                IssueListOptions::builder().build(),
                None
            ),
            (
                IssueListOptions::builder().state(StdState::Closed).build(),
                Some("state=closed".to_owned())
             ),
            (
                IssueListOptions::builder().labels(vec!["foo", "bar"]).build(),
                Some("labels=foo%2Cbar".to_owned())
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn filter_default() {
        let default: Filter = Default::default();
        assert_eq!(default, Filter::Assigned)
    }

    #[test]
    fn filter_display() {
        for (k, v) in vec![
            (Filter::Assigned, "assigned"),
            (Filter::Created, "created"),
            (Filter::Mentioned, "mentioned"),
            (Filter::Subscribed, "subscribed"),
            (Filter::All, "all"),
        ] {
            assert_eq!(k.to_string(), v)
        }
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![(Sort::Created, "created"),
                           (Sort::Updated, "updated"),
                           (Sort::Comments, "comments")] {
            assert_eq!(k.to_string(), v)
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write, ErrorKind};
use termion::event::Key;
use Editor;
use event::*;

pub trait KeyMap<'a, W: Write, T>: From<T> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
    fn editor(&self) -> &Editor<'a, W>;
    fn editor_mut(&mut self) -> &mut Editor<'a, W>;

    fn handle_key(&mut self, key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
        let mut done = false;

        handler(Event::new(self.editor_mut(), EventKind::BeforeKey(key)));

        let is_empty = self.editor().current_buffer().is_empty();

        match key {
            Key::Ctrl('c') => {
                try!(self.editor_mut().handle_newline());
                return Err(io::Error::new(ErrorKind::Interrupted, "ctrl-c"));
            }
            // if the current buffer is empty, treat ctrl-d as eof
            Key::Ctrl('d') if is_empty => {
                try!(self.editor_mut().handle_newline());
                return Err(io::Error::new(ErrorKind::UnexpectedEof, "ctrl-d"));
            }
            Key::Char('\t') => try!(self.editor_mut().complete(handler)),
            Key::Char('\n') => {
                done = try!(self.editor_mut().handle_newline());
            }
            Key::Ctrl('f') if self.editor().is_currently_showing_autosuggestion() => {
                try!(self.editor_mut().accept_autosuggestion());
            }
            Key::Right if self.editor().is_currently_showing_autosuggestion() &&
                          self.editor().cursor_is_at_end_of_line() => {
                try!(self.editor_mut().accept_autosuggestion());
            }
            _ => {
                try!(self.handle_key_core(key));
                self.editor_mut().skip_completions_hint();
            }
        };

        handler(Event::new(self.editor_mut(), EventKind::AfterKey(key)));

        try!(self.editor_mut().flush());

        Ok(done)
    }
}

pub mod vi;
pub use vi::Vi;

pub mod emacs;
pub use emacs::Emacs;

#[cfg(test)]
mod tests {
    use super::*;
    use termion::event::Key::*;
    use std::io::ErrorKind;
    use Context;

    struct TestKeyMap<'a, W: Write> {
        ed: Editor<'a, W>,
    }

    impl<'a, W: Write> TestKeyMap<'a, W> {
        pub fn new(ed: Editor<'a, W>) -> Self {
            TestKeyMap {
                ed: ed,
            }
        }
    }

    impl<'a, W: Write> KeyMap<'a, W, TestKeyMap<'a, W>> for TestKeyMap<'a, W> {
        fn handle_key_core(&mut self, _: Key) -> io::Result<()> {
            Ok(())
        }

        fn editor_mut(&mut self) ->  &mut Editor<'a, W> {
            &mut self.ed
        }

        fn editor(&self) ->  &Editor<'a, W> {
            &self.ed
        }
    }

    #[test]
    /// when the current buffer is empty, ctrl-d generates and eof error
    fn ctrl_d_empty() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);

        let res = map.handle_key(Ctrl('d'), &mut |_| {});
        assert_eq!(res.is_err(), true);
        assert_eq!(res.err().unwrap().kind(), ErrorKind::UnexpectedEof);
    }

    #[test]
    /// when the current buffer is not empty, ctrl-d should be ignored
    fn ctrl_d_non_empty() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);
        map.ed.insert_str_after_cursor("not empty").unwrap();

        let res = map.handle_key(Ctrl('d'), &mut |_| {});
        assert_eq!(res.is_ok(), true);
    }

    #[test]
    /// ctrl-c should generate an error
    fn ctrl_c() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);

        let res = map.handle_key(Ctrl('c'), &mut |_| {});
        assert_eq!(res.is_err(), true);
        assert_eq!(res.err().unwrap().kind(), ErrorKind::Interrupted);
    }
}
<commit_msg>map C-h to backspace<commit_after>use std::io::{self, Write, ErrorKind};
use termion::event::Key;
use Editor;
use event::*;

pub trait KeyMap<'a, W: Write, T>: From<T> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()>;
    fn editor(&self) -> &Editor<'a, W>;
    fn editor_mut(&mut self) -> &mut Editor<'a, W>;

    fn handle_key(&mut self, mut key: Key, handler: &mut EventHandler<W>) -> io::Result<bool> {
        let mut done = false;

        handler(Event::new(self.editor_mut(), EventKind::BeforeKey(key)));

        let is_empty = self.editor().current_buffer().is_empty();

        if key == Key::Ctrl('h') {
            // XXX: Might need to change this when remappable keybindings are added.
            key = Key::Backspace;
        }

        match key {
            Key::Ctrl('c') => {
                try!(self.editor_mut().handle_newline());
                return Err(io::Error::new(ErrorKind::Interrupted, "ctrl-c"));
            }
            // if the current buffer is empty, treat ctrl-d as eof
            Key::Ctrl('d') if is_empty => {
                try!(self.editor_mut().handle_newline());
                return Err(io::Error::new(ErrorKind::UnexpectedEof, "ctrl-d"));
            }
            Key::Char('\t') => try!(self.editor_mut().complete(handler)),
            Key::Char('\n') => {
                done = try!(self.editor_mut().handle_newline());
            }
            Key::Ctrl('f') if self.editor().is_currently_showing_autosuggestion() => {
                try!(self.editor_mut().accept_autosuggestion());
            }
            Key::Right if self.editor().is_currently_showing_autosuggestion() &&
                          self.editor().cursor_is_at_end_of_line() => {
                try!(self.editor_mut().accept_autosuggestion());
            }
            _ => {
                try!(self.handle_key_core(key));
                self.editor_mut().skip_completions_hint();
            }
        };

        handler(Event::new(self.editor_mut(), EventKind::AfterKey(key)));

        try!(self.editor_mut().flush());

        Ok(done)
    }
}

pub mod vi;
pub use vi::Vi;

pub mod emacs;
pub use emacs::Emacs;

#[cfg(test)]
mod tests {
    use super::*;
    use termion::event::Key::*;
    use std::io::ErrorKind;
    use Context;

    struct TestKeyMap<'a, W: Write> {
        ed: Editor<'a, W>,
    }

    impl<'a, W: Write> TestKeyMap<'a, W> {
        pub fn new(ed: Editor<'a, W>) -> Self {
            TestKeyMap {
                ed: ed,
            }
        }
    }

    impl<'a, W: Write> KeyMap<'a, W, TestKeyMap<'a, W>> for TestKeyMap<'a, W> {
        fn handle_key_core(&mut self, _: Key) -> io::Result<()> {
            Ok(())
        }

        fn editor_mut(&mut self) ->  &mut Editor<'a, W> {
            &mut self.ed
        }

        fn editor(&self) ->  &Editor<'a, W> {
            &self.ed
        }
    }

    #[test]
    /// when the current buffer is empty, ctrl-d generates and eof error
    fn ctrl_d_empty() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);

        let res = map.handle_key(Ctrl('d'), &mut |_| {});
        assert_eq!(res.is_err(), true);
        assert_eq!(res.err().unwrap().kind(), ErrorKind::UnexpectedEof);
    }

    #[test]
    /// when the current buffer is not empty, ctrl-d should be ignored
    fn ctrl_d_non_empty() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);
        map.ed.insert_str_after_cursor("not empty").unwrap();

        let res = map.handle_key(Ctrl('d'), &mut |_| {});
        assert_eq!(res.is_ok(), true);
    }

    #[test]
    /// ctrl-c should generate an error
    fn ctrl_c() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = TestKeyMap::new(ed);

        let res = map.handle_key(Ctrl('c'), &mut |_| {});
        assert_eq!(res.is_err(), true);
        assert_eq!(res.err().unwrap().kind(), ErrorKind::Interrupted);
    }
}
<|endoftext|>


<commit_before>//! Lang item required to make the normal `main` work in applications
//!
//! This is how the `start` lang item works:
//! When `rustc` compiles a binary crate, it creates a `main` function that looks
//! like this:
//!
//! ```
//! #[export_name = "main"]
//! pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//!     start(main, argc, argv)
//! }
//! ```
//!
//! Where `start` is this function and `main` is the binary crate's `main`
//! function.
//!
//! The final piece is that the entry point of our program, _start, has to call
//! `rustc_main`. That's covered by the `_start` function in the root of this
//! crate.

use crate::drivers;
use crate::leds::LedsDriver;
use crate::result::TockResult;
use crate::timer::Duration;
use crate::timer::ParallelSleepDriver;
use core::executor;
use core::panic::PanicInfo;

#[lang = "start"]
extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8)
where
    T: Termination,
{
    main();
}

#[lang = "termination"]
pub trait Termination {
    fn check_result(self);
}

impl Termination for () {
    fn check_result(self) {}
}

impl Termination for TockResult<()> {
    fn check_result(self) {
        self.ok().unwrap()
    }
}

#[panic_handler]
unsafe fn panic_handler(_info: &PanicInfo) -> ! {
    // Signal a panic using the LowLevelDebug capsule (if available).
    super::debug::low_level_status_code(1);

    // Flash all LEDs (if available).
    executor::block_on(async {
        let mut drivers = drivers::retrieve_drivers_unsafe();

        let leds_driver = drivers.leds.init_driver();
        let mut timer_driver = drivers.timer.create_timer_driver();
        let timer_driver = timer_driver.activate();

        if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) {
            let _ = blink_all_leds(&leds_driver, &timer_driver).await;
        }
        loop {}
    })
}

async fn blink_all_leds(
    leds_driver: &LedsDriver<'_>,
    timer_driver: &ParallelSleepDriver<'_>,
) -> TockResult<()> {
    loop {
        for led in leds_driver.leds() {
            led.on()?;
        }
        timer_driver.sleep(Duration::from_ms(100)).await?;
        for led in leds_driver.leds() {
            led.off()?;
        }
        timer_driver.sleep(Duration::from_ms(100)).await?;
    }
}
<commit_msg>Fix handling of panics<commit_after>//! Lang item required to make the normal `main` work in applications
//!
//! This is how the `start` lang item works:
//! When `rustc` compiles a binary crate, it creates a `main` function that looks
//! like this:
//!
//! ```
//! #[export_name = "main"]
//! pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//!     start(main, argc, argv)
//! }
//! ```
//!
//! Where `start` is this function and `main` is the binary crate's `main`
//! function.
//!
//! The final piece is that the entry point of our program, _start, has to call
//! `rustc_main`. That's covered by the `_start` function in the root of this
//! crate.

use crate::drivers;
use crate::leds::LedsDriver;
use crate::result::TockResult;
use crate::timer::Duration;
use crate::timer::ParallelSleepDriver;
use core::executor;
use core::panic::PanicInfo;

#[lang = "start"]
extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8)
where
    T: Termination,
{
    main().check_result();
}

#[lang = "termination"]
pub trait Termination {
    fn check_result(self);
}

impl Termination for () {
    fn check_result(self) {}
}

impl Termination for TockResult<()> {
    fn check_result(self) {
        if self.is_err() {
            unsafe { report_panic() };
        }
    }
}

#[panic_handler]
unsafe fn panic_handler(_info: &PanicInfo) -> ! {
    report_panic()
}

unsafe fn report_panic() -> ! {
    // Signal a panic using the LowLevelDebug capsule (if available).
    super::debug::low_level_status_code(1);

    // Flash all LEDs (if available).
    executor::block_on(async {
        let mut drivers = drivers::retrieve_drivers_unsafe();

        let leds_driver = drivers.leds.init_driver();
        let mut timer_driver = drivers.timer.create_timer_driver();
        let timer_driver = timer_driver.activate();

        if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) {
            let _ = blink_all_leds(&leds_driver, &timer_driver).await;
        }
        loop {}
    })
}

async fn blink_all_leds(
    leds_driver: &LedsDriver<'_>,
    timer_driver: &ParallelSleepDriver<'_>,
) -> TockResult<()> {
    loop {
        for led in leds_driver.leds() {
            led.on()?;
        }
        timer_driver.sleep(Duration::from_ms(100)).await?;
        for led in leds_driver.leds() {
            led.off()?;
        }
        timer_driver.sleep(Duration::from_ms(100)).await?;
    }
}
<|endoftext|>


<commit_before>use std::{ fs, io };
use std::path::Path;
use bytes::{ BytesMut, Bytes };
use once_cell::sync::OnceCell;
use ritsu::actions;

pub struct File {
    inner: ArcFile,
    buf: Option<BytesMut>,
    pos: u64,
    len: u64
}

impl File {
    pub async fn open(path: &Path) -> io::Result<File> {
        let handle = GLOBAL_HANDLE.get_or_init(init_ritsu_runtime);

        dbg!("open");

        let fd = actions::fs::open(handle, path).await?;

        dbg!("open ok");

        let len = fd.metadata()?.len();
        Ok(File {
            inner: ArcFile(Arc::new(fd)),
            buf: Some(BytesMut::with_capacity(1 << 64)),
            pos: 0,
            len
        })
    }

    pub async fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        fn add(x: u64, y: i64) -> u64 {
            if y >= 0 {
                x + (y as u64)
            } else {
                x - (-y as u64)
            }
        }

        match pos {
            io::SeekFrom::Start(offset) => self.pos = offset,
            io::SeekFrom::End(offset) => self.pos = add(self.len, offset),
            io::SeekFrom::Current(offset) => self.pos = add(self.pos, offset)
        }

        Ok(self.pos)
    }

    pub async fn next_chunk(&mut self) -> io::Result<Option<Bytes>> {
        let handle = GLOBAL_HANDLE.get_or_init(init_ritsu_runtime);

        dbg!("next chunk");

        let (_, mut buf) = actions::io::read_buf(
            handle,
            &mut Some(self.inner.clone()),
            self.buf.take().unwrap_or_else(|| BytesMut::with_capacity(1 << 16)),
            Some(self.pos as _)
        ).await?;

        dbg!("next chunk ok");

        Ok(if buf.is_empty() {
            None
        } else {
            self.pos += buf.len() as u64;
            let buf2 = buf.split();

            if buf.capacity() > 1024 {
                self.buf = Some(buf);
            }

            Some(buf2.freeze())
        })
    }
}

use std::thread;
use tokio::sync::mpsc::{ UnboundedSender, unbounded_channel };
use io_uring::squeue;
use ritsu::{ Proactor, Handle };

static GLOBAL_HANDLE: OnceCell<RemoteHandle> = OnceCell::new();

struct RemoteHandle(UnboundedSender<squeue::Entry>);

impl Handle for RemoteHandle {
    unsafe fn push(&self, entry: squeue::Entry) {
        let _ = self.0.send(entry);
    }
}

fn init_ritsu_runtime() -> RemoteHandle {
    let (tx, mut rx) = unbounded_channel();

    thread::spawn(move || {
        let mut proactor = Proactor::new().unwrap();
        let handle = proactor.handle();

        proactor.block_on(async move {
            while let Some(entry) = rx.recv().await {
                dbg!("process");

                unsafe {
                    handle.push(entry);
                }
            }
        }).unwrap();
    });

    RemoteHandle(tx)
}

use std::sync::Arc;
use std::os::unix::io::{ AsRawFd, RawFd };
use ritsu::actions::io::TrustedAsRawFd;

#[derive(Clone)]
struct ArcFile(Arc<fs::File>);

impl AsRawFd for ArcFile {
    #[inline]
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

unsafe impl TrustedAsRawFd for ArcFile {}
<commit_msg>Remove dbg!<commit_after>use std::{ fs, io };
use std::path::Path;
use bytes::{ BytesMut, Bytes };
use once_cell::sync::OnceCell;
use ritsu::actions;

pub struct File {
    inner: ArcFile,
    buf: Option<BytesMut>,
    pos: u64,
    len: u64
}

impl File {
    pub async fn open(path: &Path) -> io::Result<File> {
        let handle = GLOBAL_HANDLE.get_or_init(init_ritsu_runtime);

        let fd = actions::fs::open(handle, path).await?;

        let len = fd.metadata()?.len();
        Ok(File {
            inner: ArcFile(Arc::new(fd)),
            buf: Some(BytesMut::with_capacity(1 << 64)),
            pos: 0,
            len
        })
    }

    pub async fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        fn add(x: u64, y: i64) -> u64 {
            if y >= 0 {
                x + (y as u64)
            } else {
                x - (-y as u64)
            }
        }

        match pos {
            io::SeekFrom::Start(offset) => self.pos = offset,
            io::SeekFrom::End(offset) => self.pos = add(self.len, offset),
            io::SeekFrom::Current(offset) => self.pos = add(self.pos, offset)
        }

        Ok(self.pos)
    }

    pub async fn next_chunk(&mut self) -> io::Result<Option<Bytes>> {
        let handle = GLOBAL_HANDLE.get_or_init(init_ritsu_runtime);

        let (_, mut buf) = actions::io::read_buf(
            handle,
            &mut Some(self.inner.clone()),
            self.buf.take().unwrap_or_else(|| BytesMut::with_capacity(1 << 16)),
            Some(self.pos as _)
        ).await?;

        Ok(if buf.is_empty() {
            None
        } else {
            self.pos += buf.len() as u64;
            let buf2 = buf.split();

            if buf.capacity() > 64 {
                self.buf = Some(buf);
            }

            Some(buf2.freeze())
        })
    }
}

use std::thread;
use tokio::sync::mpsc::{ UnboundedSender, unbounded_channel };
use io_uring::squeue;
use ritsu::{ Proactor, Handle };

static GLOBAL_HANDLE: OnceCell<RemoteHandle> = OnceCell::new();

struct RemoteHandle(UnboundedSender<squeue::Entry>);

impl Handle for RemoteHandle {
    unsafe fn push(&self, entry: squeue::Entry) {
        let _ = self.0.send(entry);
    }
}

fn init_ritsu_runtime() -> RemoteHandle {
    let (tx, mut rx) = unbounded_channel();

    thread::spawn(move || {
        let mut proactor = Proactor::new().unwrap();
        let handle = proactor.handle();

        proactor.block_on(async move {
            while let Some(entry) = rx.recv().await {
                unsafe {
                    handle.push(entry);
                }
            }
        }).unwrap();
    });

    RemoteHandle(tx)
}

use std::sync::Arc;
use std::os::unix::io::{ AsRawFd, RawFd };
use ritsu::actions::io::TrustedAsRawFd;

#[derive(Clone)]
struct ArcFile(Arc<fs::File>);

impl AsRawFd for ArcFile {
    #[inline]
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

unsafe impl TrustedAsRawFd for ArcFile {}
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;
use parser::parse;
use reduction::{EVAL_ORDER, Order};

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(s().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(iota().app(iota())), i());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(b().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(c().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(w().app(zero()).app(one())),
///            beta_full(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(om().app(zero())), beta_full(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_once();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1)) // normal order
///
/// Y := λf.(λx.x x) (λx.(λy.(f (x x) y))) = λ (λ 1 1) (λ (λ (3 (2 2) 1))) // applicative order
///
/// # Example
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(y().app(zero())), beta_full(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    match EVAL_ORDER {
        Order::Normal => {
            abs(app(
                abs(Var(2).app(Var(1).app(Var(1)))),
                abs(Var(2).app(Var(1).app(Var(1))))
            ))
        }
        Order::Applicative => { /* WIP */
            parse(&"(λ11)(λ(λ(3(22)1)))").unwrap()
            //parse(&"λ(λ(2(λ(221))))(λ(2(λ(221))))").unwrap()
            //parse(&"λ(λ11)(λ(2(λ((22)1))))").unwrap()
        }
    }
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<commit_msg>initial applicative order handling for Y<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;
use reduction::{EVAL_ORDER, Order};

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(s().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(iota().app(iota())), i());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(beta_full(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(b().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(c().app(0.into()).app(1.into()).app(2.into())),
///            beta_full(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(w().app(zero()).app(one())),
///            beta_full(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(om().app(zero())), beta_full(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_once();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(y().app(zero())), beta_full(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    match EVAL_ORDER {
        Order::Normal => {
            abs(app(
                abs(Var(2).app(Var(1).app(Var(1)))),
                abs(Var(2).app(Var(1).app(Var(1))))
            ))
        }
        Order::Applicative => { /* should any variant work with applicative order? */
            panic!("Y combinator won't work with applicative order")
            //parse(&"(λλ212)(λλ2(121))").unwrap()
            //parse(&"(λλ(1(λ3321)))(λλ(1(λ3321)))").unwrap()
            //parse(&"(λ11)(λ(λ(3(22)1)))").unwrap()
            //parse(&"λ(λ(2(λ(221))))(λ(2(λ(221))))").unwrap()
            //parse(&"λ(λ11)(λ(2(λ((22)1))))").unwrap()
        }
    }
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<|endoftext|>