<commit_before>#![macro_escape]

pub trait StrParseExt {
    fn end_of_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<uint>;
    fn end_of_literal(&self, expected: &str) -> Option<uint>;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest(&self,
                         is_first: |char| -> bool,
                         is_rest: |char| -> bool)
                         -> Option<uint>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }

    fn end_of_literal(&self, expected: &str) -> Option<uint> {
        if self.starts_with(expected) {
            Some(expected.len())
        } else {
            None
        }
    }
}

pub struct BestFailure<'a, E> {
    pub failure: Option<Progress<'a, E>>
}

impl<'a, E> BestFailure<'a, E> {
    pub fn new() -> BestFailure<'a, E> {
        BestFailure {
            failure: None,
        }
    }

    pub fn with(failure: Progress<'a, E>) -> BestFailure<'a, E> {
        BestFailure {
            failure: Some(failure),
        }
    }

    pub fn push(&mut self, failure: Progress<'a, E>) {
        if let Some(ref old) = self.failure {
            if failure.point.offset <= old.point.offset {
                return;
            }
        }

        self.failure = Some(failure)
    }

    pub fn pop(self) -> Progress<'a, E> {
        self.failure.expect("No errors found")
    }
}

#[deriving(Show,Clone,PartialEq,Copy)]
pub struct Point<'a> {
    pub offset: uint,
    pub s: &'a str,
}

impl<'a> Point<'a> {
    pub fn to(&self, other: Point<'a>) -> &'a str {
        let len = other.offset - self.offset;
        self.s.slice_to(len)
    }

    pub fn slice_at(&self, position: uint) -> Progress<'a, &'a str> {
        Progress {
            data: self.s.slice_to(position),
            point: Point { offset: self.offset + position,
                           s: self.s.slice_from(position) }
        }
    }

    pub fn consume_to<E>(&self, l: Option<uint>) -> Result<'a, &'a str, E> {
        match l {
            None => Result::Failure(Progress{point: self.clone(), data: None}),
            Some(position) => Result::Success(self.slice_at(position)),
        }
    }

    pub fn consume_literal<E>(&self, literal: &str) -> Result<'a, &'a str, E> {
        self.consume_to(self.s.end_of_literal(literal))
    }
}

pub struct Progress<'a, T> {
    pub point: Point<'a>,
    pub data: T,
}

impl<'a, T> Progress<'a, T> {
    pub fn to_tuple(self) -> (T, Point<'a>) {
        (self.data, self.point)
    }

    pub fn map<F, B>(self, f: F) -> Progress<'a, B>
        where F: Fn(T) -> B
    {
        Progress { data: f(self.data), point: self.point }
    }
}

pub enum Result<'a, T, E> {
    Success(Progress<'a, T>),
    Partial{success: Progress<'a, T>, failure: Progress<'a, Option<E>>},
    Failure(Progress<'a, Option<E>>),
}

impl<'a, T, E> Result<'a, T, E> {
    pub fn success(data: T, point: Point<'a>) -> Result<'a, T, E> {
        Result::Success(Progress { data: data, point: point })
    }

    // Pattern: zero-or-one
    pub fn optional(self, point: Point<'a>) -> (Option<T>, Point<'a>) {
        match self {
            Result::Success(progress) |
            Result::Partial{ success: progress, .. } =>
                (Some(progress.data), progress.point),
            Result::Failure(_) =>
                (None, point),
        }
    }

    // Pattern: alternate
    pub fn or_else(self, f: || -> Result<'a, T, E>) -> Result<'a, T, E> {
        match self {
            Result::Success(..) => self,
            Result::Partial{ failure: fail, .. } |
            Result::Failure(fail) => {
                let next = f();
                match next {
                    Result::Success(..) => next,
                    Result::Partial{ failure: next_fail, .. } |
                    Result::Failure(next_fail) => {
                        let mut bf = BestFailure::with(fail);
                        bf.push(next_fail);
                        Result::Failure(bf.pop())
                    }
                }
            },
        }
    }

    pub fn map<F, B>(self, f: F) -> Result<'a, B, E>
        where F: Fn(T) -> B
    {
        match self {
            Result::Success(prog) =>
                Result::Success(prog.map(f)),
            Result::Partial{success: s, failure: ff} => {
                Result::Partial{ success: s.map(f), failure: ff}
            },
            Result::Failure(pf) =>
                Result::Failure(pf),
        }
    }
}

#[macro_export]
macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                progress.to_tuple(),
            ::document::peresil::Result::Partial{ failure: pf, .. } |
            ::document::peresil::Result::Failure(pf) =>
                return ::document::peresil::Result::Failure(pf),
        }
    })
);

#[macro_export]
macro_rules! try_partial_parse(
    ($e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                (progress.data, ::document::peresil::BestFailure::new(), progress.point),
            ::document::peresil::Result::Partial{ success: s, failure: pf } =>
                (s.data, ::document::peresil::BestFailure::with(pf), s.point),
            ::document::peresil::Result::Failure(pf) =>
                return ::document::peresil::Result::Failure(pf),
        }
    })
);

#[macro_export]
macro_rules! try_resume_after_partial_failure(
    ($partial:expr, $e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                progress.to_tuple(),
            ::document::peresil::Result::Partial{ failure: pf, .. } |
            ::document::peresil::Result::Failure(pf) => {
                let mut partial = $partial;
                partial.push(pf);
                return ::document::peresil::Result::Failure(partial.pop())
            },
        }
    });
);

// Pattern: zero-or-many
pub fn zero_or_more<'a, T, E, P>(point: Point<'a>, parser: P) -> Result<'a, Vec<T>, E>
    where P: FnMut(Point<'a>) -> Result<'a, T, E>
{
    let mut err;
    let mut data = Vec::new();
    let mut point = point;
    let mut parser = parser;

    loop {
        let (d, next_start) = match parser(point) {
            Result::Success(progress) =>
                progress.to_tuple(),
            Result::Partial{ failure: pf, .. } |
            Result::Failure(pf) => {
                err = Some(pf);
                break
            }
        };

        data.push(d);
        point = next_start;
    }

    Result::Partial {
        success: Progress { data: data, point: point },
        failure: err.unwrap()
    }
}
<commit_msg>Result `map` functions will only be called once<commit_after>#![macro_escape]

pub trait StrParseExt {
    fn end_of_start_rest(&self, is_first: |char| -> bool, is_rest: |char| -> bool) -> Option<uint>;
    fn end_of_literal(&self, expected: &str) -> Option<uint>;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest(&self,
                         is_first: |char| -> bool,
                         is_rest: |char| -> bool)
                         -> Option<uint>
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }

    fn end_of_literal(&self, expected: &str) -> Option<uint> {
        if self.starts_with(expected) {
            Some(expected.len())
        } else {
            None
        }
    }
}

pub struct BestFailure<'a, E> {
    pub failure: Option<Progress<'a, E>>
}

impl<'a, E> BestFailure<'a, E> {
    pub fn new() -> BestFailure<'a, E> {
        BestFailure {
            failure: None,
        }
    }

    pub fn with(failure: Progress<'a, E>) -> BestFailure<'a, E> {
        BestFailure {
            failure: Some(failure),
        }
    }

    pub fn push(&mut self, failure: Progress<'a, E>) {
        if let Some(ref old) = self.failure {
            if failure.point.offset <= old.point.offset {
                return;
            }
        }

        self.failure = Some(failure)
    }

    pub fn pop(self) -> Progress<'a, E> {
        self.failure.expect("No errors found")
    }
}

#[deriving(Show,Clone,PartialEq,Copy)]
pub struct Point<'a> {
    pub offset: uint,
    pub s: &'a str,
}

impl<'a> Point<'a> {
    pub fn to(&self, other: Point<'a>) -> &'a str {
        let len = other.offset - self.offset;
        self.s.slice_to(len)
    }

    pub fn slice_at(&self, position: uint) -> Progress<'a, &'a str> {
        Progress {
            data: self.s.slice_to(position),
            point: Point { offset: self.offset + position,
                           s: self.s.slice_from(position) }
        }
    }

    pub fn consume_to<E>(&self, l: Option<uint>) -> Result<'a, &'a str, E> {
        match l {
            None => Result::Failure(Progress{point: self.clone(), data: None}),
            Some(position) => Result::Success(self.slice_at(position)),
        }
    }

    pub fn consume_literal<E>(&self, literal: &str) -> Result<'a, &'a str, E> {
        self.consume_to(self.s.end_of_literal(literal))
    }
}

pub struct Progress<'a, T> {
    pub point: Point<'a>,
    pub data: T,
}

impl<'a, T> Progress<'a, T> {
    pub fn to_tuple(self) -> (T, Point<'a>) {
        (self.data, self.point)
    }

    pub fn map<F, B>(self, f: F) -> Progress<'a, B>
        where F: FnOnce(T) -> B
    {
        Progress { data: f(self.data), point: self.point }
    }
}

pub enum Result<'a, T, E> {
    Success(Progress<'a, T>),
    Partial{success: Progress<'a, T>, failure: Progress<'a, Option<E>>},
    Failure(Progress<'a, Option<E>>),
}

impl<'a, T, E> Result<'a, T, E> {
    pub fn success(data: T, point: Point<'a>) -> Result<'a, T, E> {
        Result::Success(Progress { data: data, point: point })
    }

    // Pattern: zero-or-one
    pub fn optional(self, point: Point<'a>) -> (Option<T>, Point<'a>) {
        match self {
            Result::Success(progress) |
            Result::Partial{ success: progress, .. } =>
                (Some(progress.data), progress.point),
            Result::Failure(_) =>
                (None, point),
        }
    }

    // Pattern: alternate
    pub fn or_else(self, f: || -> Result<'a, T, E>) -> Result<'a, T, E> {
        match self {
            Result::Success(..) => self,
            Result::Partial{ failure: fail, .. } |
            Result::Failure(fail) => {
                let next = f();
                match next {
                    Result::Success(..) => next,
                    Result::Partial{ failure: next_fail, .. } |
                    Result::Failure(next_fail) => {
                        let mut bf = BestFailure::with(fail);
                        bf.push(next_fail);
                        Result::Failure(bf.pop())
                    }
                }
            },
        }
    }

    pub fn map<F, B>(self, f: F) -> Result<'a, B, E>
        where F: FnOnce(T) -> B
    {
        match self {
            Result::Success(prog) =>
                Result::Success(prog.map(f)),
            Result::Partial{success: s, failure: ff} => {
                Result::Partial{ success: s.map(f), failure: ff}
            },
            Result::Failure(pf) =>
                Result::Failure(pf),
        }
    }
}

#[macro_export]
macro_rules! try_parse(
    ($e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                progress.to_tuple(),
            ::document::peresil::Result::Partial{ failure: pf, .. } |
            ::document::peresil::Result::Failure(pf) =>
                return ::document::peresil::Result::Failure(pf),
        }
    })
);

#[macro_export]
macro_rules! try_partial_parse(
    ($e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                (progress.data, ::document::peresil::BestFailure::new(), progress.point),
            ::document::peresil::Result::Partial{ success: s, failure: pf } =>
                (s.data, ::document::peresil::BestFailure::with(pf), s.point),
            ::document::peresil::Result::Failure(pf) =>
                return ::document::peresil::Result::Failure(pf),
        }
    })
);

#[macro_export]
macro_rules! try_resume_after_partial_failure(
    ($partial:expr, $e:expr) => ({
        match $e {
            ::document::peresil::Result::Success(progress) =>
                progress.to_tuple(),
            ::document::peresil::Result::Partial{ failure: pf, .. } |
            ::document::peresil::Result::Failure(pf) => {
                let mut partial = $partial;
                partial.push(pf);
                return ::document::peresil::Result::Failure(partial.pop())
            },
        }
    });
);

// Pattern: zero-or-many
pub fn zero_or_more<'a, T, E, P>(point: Point<'a>, parser: P) -> Result<'a, Vec<T>, E>
    where P: FnMut(Point<'a>) -> Result<'a, T, E>
{
    let mut err;
    let mut data = Vec::new();
    let mut point = point;
    let mut parser = parser;

    loop {
        let (d, next_start) = match parser(point) {
            Result::Success(progress) =>
                progress.to_tuple(),
            Result::Partial{ failure: pf, .. } |
            Result::Failure(pf) => {
                err = Some(pf);
                break
            }
        };

        data.push(d);
        point = next_start;
    }

    Result::Partial {
        success: Progress { data: data, point: point },
        failure: err.unwrap()
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

fn find_by<T, F>(list: &[T], start: Option<usize>, predicate: F) -> Option<usize>
where F: Fn(&T) -> bool {
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) { return Some(start + offset); }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {

            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                }
            }

            _ => {}
        }
    }
}
<commit_msg>Change find_by to accept a mut function<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where F: FnMut(&T) -> bool {
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) { return Some(start + offset); }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {

            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                }
            }

            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

use voodoo::color::ColorValue;
use voodoo::window::{Point, TermCell, Window};

pub struct Program {
    pub position: Point,
    tail: Vec<Point>,
    pub name: String,
    pub abilities: Vec<String>,
}

pub type ProgramRef = Rc<RefCell<Program>>;

impl Program {
    pub fn new(position: Point, name: &str) -> Program {
        Program {
            position: position,
            tail: vec![],
            name: name.to_owned(),
            abilities: vec![],
        }
    }

    pub fn move_to(&mut self, point: Point) {
        self.tail.push(self.position);
        self.position = point;
    }

    pub fn display_color(&self, color: ColorValue, window: &mut Window) {
        let mut tc: TermCell = '◘'.into();
        tc.bg = Some(color);
        window.put_at(self.position, tc);
        for point in self.tail.iter() {
            window.put_at(*point, tc);
        }
    }

    pub fn intersects(&self, point: Point) -> bool {
        for t in self.tail.iter() {
            if *t == point {
                return true;
            }
        }
        self.position == point
    }
}
<commit_msg>feat: limit size of tail<commit_after>use std::cell::RefCell;
use std::rc::Rc;

use voodoo::color::ColorValue;
use voodoo::window::{Point, TermCell, Window};

pub struct Program {
    pub position: Point,
    tail: Vec<Point>,
    pub name: String,
    pub abilities: Vec<String>,
    pub max_tail: usize,
}

pub type ProgramRef = Rc<RefCell<Program>>;

impl Program {
    pub fn new(position: Point, name: &str) -> Program {
        Program {
            position: position,
            tail: vec![],
            name: name.to_owned(),
            abilities: vec![],
            max_tail: 4,
        }
    }

    pub fn move_to(&mut self, point: Point) {
        self.tail.push(self.position);
        if self.tail.len() >= self.max_tail {
            self.tail.remove(0);
        }
        self.position = point;
    }

    pub fn display_color(&self, color: ColorValue, window: &mut Window) {
        let mut tc: TermCell = '◘'.into();
        tc.bg = Some(color);
        window.put_at(self.position, tc);
        for point in self.tail.iter() {
            window.put_at(*point, tc);
        }
    }

    pub fn intersects(&self, point: Point) -> bool {
        for t in self.tail.iter() {
            if *t == point {
                return true;
            }
        }
        self.position == point
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                if self.is_seeking {
                    let (new_index, still_seeking) = self.seek_forward(index);
                    self.is_seeking = still_seeking;
                    index = new_index;
                }
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.start_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        index = self.jump_backward(&vm, index);
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            let (index, still_seeking) = self.seek_forward(index);
            self.is_seeking = still_seeking;
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index + 1;
        }
    }
}
<commit_msg>Update start_jump_forward to use ProgramStatus enum<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                if self.is_seeking {
                    let (new_index, still_seeking) = self.seek_forward(index);
                    self.is_seeking = still_seeking;
                    index = new_index;
                }
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.start_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        index = self.jump_backward(&vm, index);
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.status = ProgramStatus::Seeking(self.current_depth);
                let (index, still_seeking) = self.seek_forward(index);
                self.status = if still_seeking { self.status } else { ProgramStatus::Normal };
                index
            },
            _ => {
                self.current_depth = self.current_depth + 1;
                index + 1
            }
        }
    }
}
<|endoftext|>


<commit_before>// Regression test for #88118. Used to ICE.
//
// check-pass

#![feature(capture_disjoint_fields)]

fn foo<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
    Box::new(move |value| {
        (|_| handler.clone()())(value);
        None
    }) as Box<dyn Fn(i32) -> Option<i32>>;
}

fn main() {}<commit_msg>add trailing newline<commit_after>// Regression test for #88118. Used to ICE.
//
// check-pass

#![feature(capture_disjoint_fields)]

fn foo<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
    Box::new(move |value| {
        (|_| handler.clone()())(value);
        None
    }) as Box<dyn Fn(i32) -> Option<i32>>;
}

fn main() {}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generic_associated_types)]

//FIXME(#44265): The lifetime shadowing and type parameter shadowing
// should cause an error. Now it compiles (errorneously) and this will be addressed
// by a future PR. Then remove the following:
// must-compile-successfully

trait Shadow<'a> {
    type Bar<'a>; // Error: shadowed lifetime
}

trait NoShadow<'a> {
    type Bar<'b>; // OK
}

impl<'a> NoShadow<'a> for &'a u32
{
    type Bar<'a> = i32; // Error: shadowed lifetime
}

trait ShadowT<T> {
    type Bar<T>; // Error: shadowed type parameter
}

trait NoShadowT<T> {
    type Bar<U>; // OK
}

impl<T> NoShadowT<T> for Option<T>
{
    type Bar<T> = i32; // Error: shadowed type parameter
}

fn main() {}
<commit_msg>Update tests to use compile-pass<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generic_associated_types)]

//FIXME(#44265): The lifetime shadowing and type parameter shadowing
// should cause an error. Now it compiles (errorneously) and this will be addressed
// by a future PR. Then remove the following:
// compile-pass

trait Shadow<'a> {
    type Bar<'a>; // Error: shadowed lifetime
}

trait NoShadow<'a> {
    type Bar<'b>; // OK
}

impl<'a> NoShadow<'a> for &'a u32
{
    type Bar<'a> = i32; // Error: shadowed lifetime
}

trait ShadowT<T> {
    type Bar<T>; // Error: shadowed type parameter
}

trait NoShadowT<T> {
    type Bar<U>; // OK
}

impl<T> NoShadowT<T> for Option<T>
{
    type Bar<T> = i32; // Error: shadowed type parameter
}

fn main() {}
<|endoftext|>


<commit_before>#[macro_use]
extern crate enum_primitive_derive;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate itertools;
extern crate num_traits;

pub use self::interval::{Interval, Intervals};
use self::note::Accidental;
pub use self::note::Note;
use failure::Error;
use std::str::FromStr;

pub mod interval {
    use itertools::Itertools;
    use std::fmt;
    use std::ops::Deref;
    use std::str::FromStr;

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Fail)]
    pub enum ParseErr {
        #[fail(display = "invalid interval")]
        InvalidInterval,
        #[fail(display = "wrong number of semitones")]
        WrongNumberOfSemitones,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Interval {
        HalfStep = 1,
        WholeStep = 2,
        AugmentedFirst = 3,
    }

    impl fmt::Display for Interval {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            use self::Interval::*;
            write!(
                f,
                "{}",
                match self {
                    HalfStep => "m",
                    WholeStep => "M",
                    AugmentedFirst => "A",
                }
            )
        }
    }

    impl FromStr for Interval {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            use self::Interval::*;
            match s {
                "m" => Ok(HalfStep),
                "M" => Ok(WholeStep),
                "A" => Ok(AugmentedFirst),
                _ => Err(ParseErr::InvalidInterval),
            }
        }
    }

    #[derive(Debug, Clone, PartialEq, Eq)]
    pub struct Intervals(Vec<Interval>);

    impl fmt::Display for Intervals {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.0.iter().join(""))
        }
    }

    impl FromStr for Intervals {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let mut semitones = Vec::with_capacity(s.len());

            for (i, c) in s.char_indices() {
                semitones.push(Interval::from_str(&s[i..i + c.len_utf8()])?);
            }

            if semitones.iter().take(12).map(|&i| i as u8).sum::<u8>() == 12 {
                Ok(Intervals(semitones))
            } else {
                Err(ParseErr::WrongNumberOfSemitones)
            }
        }
    }

    impl Deref for Intervals {
        type Target = Vec<Interval>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

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

        #[test]
        fn test_parse_chromatic() {
            assert!("mmmmmmmmmmmm".parse::<Intervals>().is_ok());
        }

        #[test]
        fn test_parse_major() {
            assert!("MMmMMMm".parse::<Intervals>().is_ok());
        }

        #[test]
        fn test_parse_minor() {
            assert!("MmMMmMM".parse::<Intervals>().is_ok());
        }
    }
}

pub mod note {
    use interval::Interval;
    use num_traits::{FromPrimitive, ToPrimitive};
    use std::fmt;
    use std::ops::AddAssign;
    use std::str::FromStr;

    pub const SEMITONES: i8 = 12;

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Semitone {
        A = 0,
        ASharp = 1,
        B = 2,
        C = 3,
        CSharp = 4,
        D = 5,
        DSharp = 6,
        E = 7,
        F = 8,
        FSharp = 9,
        G = 10,
        GSharp = 11,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Root {
        A = 0,
        B = 2,
        C = 3,
        D = 5,
        E = 7,
        F = 8,
        G = 10,
    }

    impl fmt::Display for Root {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{:?}", self)
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum Accidental {
        Sharp,
        Flat,
    }

    impl Accidental {
        fn to_i8(&self) -> i8 {
            match *self {
                Accidental::Sharp => 1,
                Accidental::Flat => -1,
            }
        }

        pub fn from_tonic(tonic: &str) -> Accidental {
            match tonic {
                "C" | "a" | "G" | "D" | "A" | "E" | "B" | "F#" | "e" | "b" | "f#" | "c#" | "g#"
                | "d#" => Accidental::Sharp,
                _ => Accidental::Flat,
            }
        }
    }

    impl fmt::Display for Accidental {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(
                f,
                "{}",
                match &self {
                    Accidental::Sharp => '#',
                    Accidental::Flat => 'b',
                }
            )
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Note {
        tonic: Root,
        accidental: Option<Accidental>,
    }

    impl Note {
        pub fn canonicalize(&self, lean: Accidental) -> Note {
            let mut n: Note = Semitone::from(*self).into();
            if let Some(accidental) = n.accidental {
                if accidental != lean {
                    if lean == Accidental::Flat {
                        n += Interval::HalfStep;
                        n.accidental = Some(Accidental::Flat);
                    }
                }
            }
            n
        }
    }

    impl fmt::Display for Note {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(
                f,
                "{}{}",
                self.tonic,
                self.accidental.map_or(String::new(), |a| a.to_string()),
            )
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Fail)]
    pub enum ParseErr {
        #[fail(display = "invalid length")]
        InvalidLength,
        #[fail(display = "invalid tonic")]
        InvalidTonic,
        #[fail(display = "invalid accidental")]
        InvalidAccidental,
    }

    impl FromStr for Note {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let lc = s.to_lowercase();
            let mut iter = lc.chars();

            let mut note = match iter.next() {
                Some(c) if 'a' <= c && 'g' >= c => Note {
                    tonic: match c {
                        'a' => Root::A,
                        'b' => Root::B,
                        'c' => Root::C,
                        'd' => Root::D,
                        'e' => Root::E,
                        'f' => Root::F,
                        'g' => Root::G,
                        _ => return Err(ParseErr::InvalidTonic),
                    },
                    accidental: None,
                },
                Some(_) => return Err(ParseErr::InvalidTonic),
                None => return Err(ParseErr::InvalidLength),
            };

            match iter.next() {
                Some('b') => note.accidental = Some(Accidental::Flat),
                Some('#') => note.accidental = Some(Accidental::Sharp),
                Some(_) => return Err(ParseErr::InvalidAccidental),
                None => {}
            }

            if iter.next().is_some() {
                return Err(ParseErr::InvalidLength);
            }

            Ok(note)
        }
    }

    impl From<Semitone> for Note {
        fn from(s: Semitone) -> Self {
            Note {
                tonic: match s {
                    Semitone::A | Semitone::ASharp => Root::A,
                    Semitone::B => Root::B,
                    Semitone::C | Semitone::CSharp => Root::C,
                    Semitone::D | Semitone::DSharp => Root::D,
                    Semitone::E => Root::E,
                    Semitone::F | Semitone::FSharp => Root::F,
                    Semitone::G | Semitone::GSharp => Root::G,
                },
                accidental: match s {
                    Semitone::ASharp
                    | Semitone::CSharp
                    | Semitone::DSharp
                    | Semitone::FSharp
                    | Semitone::GSharp => Some(Accidental::Sharp),
                    _ => None,
                },
            }
        }
    }

    impl From<Note> for Semitone {
        fn from(n: Note) -> Self {
            Semitone::from_i8(
                (SEMITONES + n.tonic.to_i8().unwrap() + n.accidental.map_or(0, |a| a.to_i8()))
                    % SEMITONES,
            ).expect("must have valid semitone")
        }
    }

    impl AddAssign<Interval> for Note {
        fn add_assign(&mut self, rhs: Interval) {
            *self = Semitone::from_i8(
                (SEMITONES + Semitone::from(*self).to_i8().unwrap() + rhs.to_i8().unwrap())
                    % SEMITONES,
            ).unwrap()
                .into();
        }
    }

}

#[derive(Debug)]
pub struct Scale {
    tonic: Note,
    lean: Accidental,
    intervals: Intervals,
}

impl Scale {
    pub fn new(tonic: &str, intervals: &str) -> Result<Scale, Error> {
        Ok(Scale {
            tonic: Note::from_str(tonic)?,
            lean: Accidental::from_tonic(tonic),
            intervals: Intervals::from_str(intervals)?,
        })
    }

    pub fn chromatic(tonic: &str) -> Result<Scale, Error> {
        Scale::new(tonic, "mmmmmmmmmmmm")
    }

    pub fn enumerate(&self) -> Vec<String> {
        let mut out = Vec::with_capacity(self.intervals.len());

        let mut note = self.tonic;
        for &interval in self.intervals.iter() {
            out.push(note.canonicalize(self.lean).to_string());
            note += interval;
        }

        out
    }
}
<commit_msg>scale-generator: Combine two adjacent `if` conditions into one<commit_after>#[macro_use]
extern crate enum_primitive_derive;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate itertools;
extern crate num_traits;

pub use self::interval::{Interval, Intervals};
use self::note::Accidental;
pub use self::note::Note;
use failure::Error;
use std::str::FromStr;

pub mod interval {
    use itertools::Itertools;
    use std::fmt;
    use std::ops::Deref;
    use std::str::FromStr;

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Fail)]
    pub enum ParseErr {
        #[fail(display = "invalid interval")]
        InvalidInterval,
        #[fail(display = "wrong number of semitones")]
        WrongNumberOfSemitones,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Interval {
        HalfStep = 1,
        WholeStep = 2,
        AugmentedFirst = 3,
    }

    impl fmt::Display for Interval {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            use self::Interval::*;
            write!(
                f,
                "{}",
                match self {
                    HalfStep => "m",
                    WholeStep => "M",
                    AugmentedFirst => "A",
                }
            )
        }
    }

    impl FromStr for Interval {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            use self::Interval::*;
            match s {
                "m" => Ok(HalfStep),
                "M" => Ok(WholeStep),
                "A" => Ok(AugmentedFirst),
                _ => Err(ParseErr::InvalidInterval),
            }
        }
    }

    #[derive(Debug, Clone, PartialEq, Eq)]
    pub struct Intervals(Vec<Interval>);

    impl fmt::Display for Intervals {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.0.iter().join(""))
        }
    }

    impl FromStr for Intervals {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let mut semitones = Vec::with_capacity(s.len());

            for (i, c) in s.char_indices() {
                semitones.push(Interval::from_str(&s[i..i + c.len_utf8()])?);
            }

            if semitones.iter().take(12).map(|&i| i as u8).sum::<u8>() == 12 {
                Ok(Intervals(semitones))
            } else {
                Err(ParseErr::WrongNumberOfSemitones)
            }
        }
    }

    impl Deref for Intervals {
        type Target = Vec<Interval>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

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

        #[test]
        fn test_parse_chromatic() {
            assert!("mmmmmmmmmmmm".parse::<Intervals>().is_ok());
        }

        #[test]
        fn test_parse_major() {
            assert!("MMmMMMm".parse::<Intervals>().is_ok());
        }

        #[test]
        fn test_parse_minor() {
            assert!("MmMMmMM".parse::<Intervals>().is_ok());
        }
    }
}

pub mod note {
    use interval::Interval;
    use num_traits::{FromPrimitive, ToPrimitive};
    use std::fmt;
    use std::ops::AddAssign;
    use std::str::FromStr;

    pub const SEMITONES: i8 = 12;

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Semitone {
        A = 0,
        ASharp = 1,
        B = 2,
        C = 3,
        CSharp = 4,
        D = 5,
        DSharp = 6,
        E = 7,
        F = 8,
        FSharp = 9,
        G = 10,
        GSharp = 11,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Primitive)]
    pub enum Root {
        A = 0,
        B = 2,
        C = 3,
        D = 5,
        E = 7,
        F = 8,
        G = 10,
    }

    impl fmt::Display for Root {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{:?}", self)
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum Accidental {
        Sharp,
        Flat,
    }

    impl Accidental {
        fn to_i8(&self) -> i8 {
            match *self {
                Accidental::Sharp => 1,
                Accidental::Flat => -1,
            }
        }

        pub fn from_tonic(tonic: &str) -> Accidental {
            match tonic {
                "C" | "a" | "G" | "D" | "A" | "E" | "B" | "F#" | "e" | "b" | "f#" | "c#" | "g#"
                | "d#" => Accidental::Sharp,
                _ => Accidental::Flat,
            }
        }
    }

    impl fmt::Display for Accidental {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(
                f,
                "{}",
                match &self {
                    Accidental::Sharp => '#',
                    Accidental::Flat => 'b',
                }
            )
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Note {
        tonic: Root,
        accidental: Option<Accidental>,
    }

    impl Note {
        pub fn canonicalize(&self, lean: Accidental) -> Note {
            let mut n: Note = Semitone::from(*self).into();
            if let Some(accidental) = n.accidental {
                if accidental != lean && lean == Accidental::Flat {
                    n += Interval::HalfStep;
                    n.accidental = Some(Accidental::Flat);
                }
            }
            n
        }
    }

    impl fmt::Display for Note {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(
                f,
                "{}{}",
                self.tonic,
                self.accidental.map_or(String::new(), |a| a.to_string()),
            )
        }
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Fail)]
    pub enum ParseErr {
        #[fail(display = "invalid length")]
        InvalidLength,
        #[fail(display = "invalid tonic")]
        InvalidTonic,
        #[fail(display = "invalid accidental")]
        InvalidAccidental,
    }

    impl FromStr for Note {
        type Err = ParseErr;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let lc = s.to_lowercase();
            let mut iter = lc.chars();

            let mut note = match iter.next() {
                Some(c) if 'a' <= c && 'g' >= c => Note {
                    tonic: match c {
                        'a' => Root::A,
                        'b' => Root::B,
                        'c' => Root::C,
                        'd' => Root::D,
                        'e' => Root::E,
                        'f' => Root::F,
                        'g' => Root::G,
                        _ => return Err(ParseErr::InvalidTonic),
                    },
                    accidental: None,
                },
                Some(_) => return Err(ParseErr::InvalidTonic),
                None => return Err(ParseErr::InvalidLength),
            };

            match iter.next() {
                Some('b') => note.accidental = Some(Accidental::Flat),
                Some('#') => note.accidental = Some(Accidental::Sharp),
                Some(_) => return Err(ParseErr::InvalidAccidental),
                None => {}
            }

            if iter.next().is_some() {
                return Err(ParseErr::InvalidLength);
            }

            Ok(note)
        }
    }

    impl From<Semitone> for Note {
        fn from(s: Semitone) -> Self {
            Note {
                tonic: match s {
                    Semitone::A | Semitone::ASharp => Root::A,
                    Semitone::B => Root::B,
                    Semitone::C | Semitone::CSharp => Root::C,
                    Semitone::D | Semitone::DSharp => Root::D,
                    Semitone::E => Root::E,
                    Semitone::F | Semitone::FSharp => Root::F,
                    Semitone::G | Semitone::GSharp => Root::G,
                },
                accidental: match s {
                    Semitone::ASharp
                    | Semitone::CSharp
                    | Semitone::DSharp
                    | Semitone::FSharp
                    | Semitone::GSharp => Some(Accidental::Sharp),
                    _ => None,
                },
            }
        }
    }

    impl From<Note> for Semitone {
        fn from(n: Note) -> Self {
            Semitone::from_i8(
                (SEMITONES + n.tonic.to_i8().unwrap() + n.accidental.map_or(0, |a| a.to_i8()))
                    % SEMITONES,
            ).expect("must have valid semitone")
        }
    }

    impl AddAssign<Interval> for Note {
        fn add_assign(&mut self, rhs: Interval) {
            *self = Semitone::from_i8(
                (SEMITONES + Semitone::from(*self).to_i8().unwrap() + rhs.to_i8().unwrap())
                    % SEMITONES,
            ).unwrap()
                .into();
        }
    }

}

#[derive(Debug)]
pub struct Scale {
    tonic: Note,
    lean: Accidental,
    intervals: Intervals,
}

impl Scale {
    pub fn new(tonic: &str, intervals: &str) -> Result<Scale, Error> {
        Ok(Scale {
            tonic: Note::from_str(tonic)?,
            lean: Accidental::from_tonic(tonic),
            intervals: Intervals::from_str(intervals)?,
        })
    }

    pub fn chromatic(tonic: &str) -> Result<Scale, Error> {
        Scale::new(tonic, "mmmmmmmmmmmm")
    }

    pub fn enumerate(&self) -> Vec<String> {
        let mut out = Vec::with_capacity(self.intervals.len());

        let mut note = self.tonic;
        for &interval in self.intervals.iter() {
            out.push(note.canonicalize(self.lean).to_string());
            note += interval;
        }

        out
    }
}
<|endoftext|>


<commit_before><commit_msg>Add QueryMatch::nodes_for_capture_index<commit_after><|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! *Disclaimer*: This is not an official Google product.
//!
//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! [Documentation](https://docs.rs/crate/tarpc/)
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no context switching between different languages.
//!
//! Some other features of tarpc:
//! - Pluggable transport: any type impling `Stream<Item = Request> + Sink<Response>` can be
//!   used as a transport to connect the client and server.
//! - `Send + 'static` optional: if the transport doesn't require it, neither does tarpc!
//! - Cascading cancellation: dropping a request will send a cancellation message to the server.
//!   The server will cease any unfinished work on the request, subsequently cancelling any of its
//!   own requests, repeating for the entire chain of transitive dependencies.
//! - Configurable deadlines and deadline propagation: request deadlines default to 10s if
//!   unspecified. The server will automatically cease work when the deadline has passed. Any
//!   requests sent by the server that use the request context will propagate the request deadline.
//!   For example, if a server is handling a request with a 10s deadline, does 2s of work, then
//!   sends a request to another server, that server will see an 8s deadline.
//! - Serde serialization: enabling the `serde1` Cargo feature will make service requests and
//!   responses `Serialize + Deserialize`. It's entirely optional, though: in-memory transports can
//!   be used, as well, so the price of serialization doesn't have to be paid when it's not needed.
//!
//! ## Usage
//! Add to your `Cargo.toml` dependencies:
//!
//! ```toml
//! tarpc = "0.23.0"
//! ```
//!
//! The `tarpc::service` attribute expands to a collection of items that form an rpc service.
//! These generated types make it easy and ergonomic to write servers with less boilerplate.
//! Simply implement the generated service trait, and you're off to the races!
//!
//! ## Example
//!
//! This example uses [tokio](https://tokio.rs), so add the following dependencies to
//! your `Cargo.toml`:
//!
//! ```toml
//! futures = "0.3"
//! tarpc = { version = "0.23.0", features = ["tokio1"] }
//! tokio = "0.3"
//! ```
//!
//! In the following example, we use an in-process channel for communication between
//! client and server. In real code, you will likely communicate over the network.
//! For a more real-world example, see [example-service](example-service).
//!
//! First, let's set up the dependencies and service definition.
//!
//! ```rust
//! # extern crate futures;
//!
//! use futures::{
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! #[tarpc::service]
//! trait World {
//!     /// Returns a greeting for name.
//!     async fn hello(name: String) -> String;
//! }
//! ```
//!
//! This service definition generates a trait called `World`. Next we need to
//! implement it for our Server struct.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! // This is the type that implements the generated World trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl World for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//! ```
//!
//! Lastly let's write our `main` that will start the server. While this example uses an
//! [in-process channel](rpc::transport::channel), tarpc also ships a generic [`serde_transport`]
//! behind the `serde-transport` feature, with additional [TCP](serde_transport::tcp) functionality
//! available behind the `tcp` feature.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! # // This is the type that implements the generated World trait. It is the business logic
//! # // and is used to start the server.
//! # #[derive(Clone)]
//! # struct HelloServer;
//! # impl World for HelloServer {
//! #     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//! #     // an associated type representing the future output by the fn.
//! #     type HelloFut = Ready<String>;
//! #     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//! #         future::ready(format!("Hello, {}!", name))
//! #     }
//! # }
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let (client_transport, server_transport) = tarpc::transport::channel::unbounded();
//!
//!     let server = server::new(server::Config::default())
//!         // incoming() takes a stream of transports such as would be returned by
//!         // TcpListener::incoming (but a stream instead of an iterator).
//!         .incoming(stream::once(future::ready(server_transport)))
//!         .respond_with(HelloServer.serve());
//!
//!     tokio::spawn(server);
//!
//!     // WorldClient is generated by the macro. It has a constructor `new` that takes a config and
//!     // any Transport as input
//!     let mut client = WorldClient::new(client::Config::default(), client_transport).spawn()?;
//!
//!     // The client has an RPC method for each RPC defined in the annotated trait. It takes the same
//!     // args as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = client.hello(context::current(), "Stim".to_string()).await?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Service Documentation
//!
//! Use `cargo doc` as you normally would to see the documentation created for all
//! items expanded by a `service!` invocation.
#![deny(missing_docs)]
#![allow(clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod rpc;
pub use rpc::*;

#[cfg(feature = "serde-transport")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde-transport")))]
pub mod serde_transport;

pub mod trace;

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// #[tarpc::service]
/// trait Service {
/// /// Say hello
/// async fn hello(name: String) -> String;
/// }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated service traits'
/// corresponding `fn`s, as well as to the client stubs' RPCs.
///
/// The following items are expanded in the enclosing module:
///
/// * `trait Service` -- defines the RPC service.
///   * `fn serve` -- turns a service impl into a request handler.
/// * `Client` -- a client stub with a fn for each RPC.
///   * `fn new_stub` -- creates a new Client stub.
pub use tarpc_plugins::service;

/// A utility macro that can be used for RPC server implementations.
///
/// Syntactic sugar to make using async functions in the server implementation
/// easier. It does this by rewriting code like this, which would normally not
/// compile because async functions are disallowed in trait implementations:
///
/// ```rust
/// # use tarpc::context;
/// # use std::net::SocketAddr;
/// #[tarpc::service]
/// trait World {
///     async fn hello(name: String) -> String;
/// }
///
/// #[derive(Clone)]
/// struct HelloServer(SocketAddr);
///
/// #[tarpc::server]
/// impl World for HelloServer {
///     async fn hello(self, _: context::Context, name: String) -> String {
///         format!("Hello, {}! You are connected from {:?}.", name, self.0)
///     }
/// }
/// ```
///
/// Into code like this, which matches the service trait definition:
///
/// ```rust
/// # use tarpc::context;
/// # use std::pin::Pin;
/// # use futures::Future;
/// # use std::net::SocketAddr;
/// #[derive(Clone)]
/// struct HelloServer(SocketAddr);
///
/// #[tarpc::service]
/// trait World {
///     async fn hello(name: String) -> String;
/// }
///
/// impl World for HelloServer {
///     type HelloFut = Pin<Box<dyn Future<Output = String> + Send>>;
///
///     fn hello(self, _: context::Context, name: String) -> Pin<Box<dyn Future<Output = String>
///     + Send>> {
///         Box::pin(async move {
///             format!("Hello, {}! You are connected from {:?}.", name, self.0)
///         })
///     }
/// }
/// ```
///
/// Note that this won't touch functions unless they have been annotated with
/// `async`, meaning that this should not break existing code.
pub use tarpc_plugins::server;
<commit_msg>Add tokio's macros feature to readme example's dependencies<commit_after>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! *Disclaimer*: This is not an official Google product.
//!
//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! [Documentation](https://docs.rs/crate/tarpc/)
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no context switching between different languages.
//!
//! Some other features of tarpc:
//! - Pluggable transport: any type impling `Stream<Item = Request> + Sink<Response>` can be
//!   used as a transport to connect the client and server.
//! - `Send + 'static` optional: if the transport doesn't require it, neither does tarpc!
//! - Cascading cancellation: dropping a request will send a cancellation message to the server.
//!   The server will cease any unfinished work on the request, subsequently cancelling any of its
//!   own requests, repeating for the entire chain of transitive dependencies.
//! - Configurable deadlines and deadline propagation: request deadlines default to 10s if
//!   unspecified. The server will automatically cease work when the deadline has passed. Any
//!   requests sent by the server that use the request context will propagate the request deadline.
//!   For example, if a server is handling a request with a 10s deadline, does 2s of work, then
//!   sends a request to another server, that server will see an 8s deadline.
//! - Serde serialization: enabling the `serde1` Cargo feature will make service requests and
//!   responses `Serialize + Deserialize`. It's entirely optional, though: in-memory transports can
//!   be used, as well, so the price of serialization doesn't have to be paid when it's not needed.
//!
//! ## Usage
//! Add to your `Cargo.toml` dependencies:
//!
//! ```toml
//! tarpc = "0.23.0"
//! ```
//!
//! The `tarpc::service` attribute expands to a collection of items that form an rpc service.
//! These generated types make it easy and ergonomic to write servers with less boilerplate.
//! Simply implement the generated service trait, and you're off to the races!
//!
//! ## Example
//!
//! This example uses [tokio](https://tokio.rs), so add the following dependencies to
//! your `Cargo.toml`:
//!
//! ```toml
//! futures = "0.3"
//! tarpc = { version = "0.23.0", features = ["tokio1"] }
//! tokio = { version = "0.3", features = ["macros"] }
//! ```
//!
//! In the following example, we use an in-process channel for communication between
//! client and server. In real code, you will likely communicate over the network.
//! For a more real-world example, see [example-service](example-service).
//!
//! First, let's set up the dependencies and service definition.
//!
//! ```rust
//! # extern crate futures;
//!
//! use futures::{
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! #[tarpc::service]
//! trait World {
//!     /// Returns a greeting for name.
//!     async fn hello(name: String) -> String;
//! }
//! ```
//!
//! This service definition generates a trait called `World`. Next we need to
//! implement it for our Server struct.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! // This is the type that implements the generated World trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl World for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//! ```
//!
//! Lastly let's write our `main` that will start the server. While this example uses an
//! [in-process channel](rpc::transport::channel), tarpc also ships a generic [`serde_transport`]
//! behind the `serde-transport` feature, with additional [TCP](serde_transport::tcp) functionality
//! available behind the `tcp` feature.
//!
//! ```rust
//! # extern crate futures;
//! # use futures::{
//! #     future::{self, Ready},
//! #     prelude::*,
//! # };
//! # use tarpc::{
//! #     client, context,
//! #     server::{self, Handler},
//! # };
//! # use std::io;
//! # // This is the service definition. It looks a lot like a trait definition.
//! # // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! # #[tarpc::service]
//! # trait World {
//! #     /// Returns a greeting for name.
//! #     async fn hello(name: String) -> String;
//! # }
//! # // This is the type that implements the generated World trait. It is the business logic
//! # // and is used to start the server.
//! # #[derive(Clone)]
//! # struct HelloServer;
//! # impl World for HelloServer {
//! #     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//! #     // an associated type representing the future output by the fn.
//! #     type HelloFut = Ready<String>;
//! #     fn hello(self, _: context::Context, name: String) -> Self::HelloFut {
//! #         future::ready(format!("Hello, {}!", name))
//! #     }
//! # }
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let (client_transport, server_transport) = tarpc::transport::channel::unbounded();
//!
//!     let server = server::new(server::Config::default())
//!         // incoming() takes a stream of transports such as would be returned by
//!         // TcpListener::incoming (but a stream instead of an iterator).
//!         .incoming(stream::once(future::ready(server_transport)))
//!         .respond_with(HelloServer.serve());
//!
//!     tokio::spawn(server);
//!
//!     // WorldClient is generated by the macro. It has a constructor `new` that takes a config and
//!     // any Transport as input
//!     let mut client = WorldClient::new(client::Config::default(), client_transport).spawn()?;
//!
//!     // The client has an RPC method for each RPC defined in the annotated trait. It takes the same
//!     // args as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = client.hello(context::current(), "Stim".to_string()).await?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//! ```
//!
//! ## Service Documentation
//!
//! Use `cargo doc` as you normally would to see the documentation created for all
//! items expanded by a `service!` invocation.
#![deny(missing_docs)]
#![allow(clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod rpc;
pub use rpc::*;

#[cfg(feature = "serde-transport")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde-transport")))]
pub mod serde_transport;

pub mod trace;

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// #[tarpc::service]
/// trait Service {
/// /// Say hello
/// async fn hello(name: String) -> String;
/// }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated service traits'
/// corresponding `fn`s, as well as to the client stubs' RPCs.
///
/// The following items are expanded in the enclosing module:
///
/// * `trait Service` -- defines the RPC service.
///   * `fn serve` -- turns a service impl into a request handler.
/// * `Client` -- a client stub with a fn for each RPC.
///   * `fn new_stub` -- creates a new Client stub.
pub use tarpc_plugins::service;

/// A utility macro that can be used for RPC server implementations.
///
/// Syntactic sugar to make using async functions in the server implementation
/// easier. It does this by rewriting code like this, which would normally not
/// compile because async functions are disallowed in trait implementations:
///
/// ```rust
/// # use tarpc::context;
/// # use std::net::SocketAddr;
/// #[tarpc::service]
/// trait World {
///     async fn hello(name: String) -> String;
/// }
///
/// #[derive(Clone)]
/// struct HelloServer(SocketAddr);
///
/// #[tarpc::server]
/// impl World for HelloServer {
///     async fn hello(self, _: context::Context, name: String) -> String {
///         format!("Hello, {}! You are connected from {:?}.", name, self.0)
///     }
/// }
/// ```
///
/// Into code like this, which matches the service trait definition:
///
/// ```rust
/// # use tarpc::context;
/// # use std::pin::Pin;
/// # use futures::Future;
/// # use std::net::SocketAddr;
/// #[derive(Clone)]
/// struct HelloServer(SocketAddr);
///
/// #[tarpc::service]
/// trait World {
///     async fn hello(name: String) -> String;
/// }
///
/// impl World for HelloServer {
///     type HelloFut = Pin<Box<dyn Future<Output = String> + Send>>;
///
///     fn hello(self, _: context::Context, name: String) -> Pin<Box<dyn Future<Output = String>
///     + Send>> {
///         Box::pin(async move {
///             format!("Hello, {}! You are connected from {:?}.", name, self.0)
///         })
///     }
/// }
/// ```
///
/// Note that this won't touch functions unless they have been annotated with
/// `async`, meaning that this should not break existing code.
pub use tarpc_plugins::server;
<|endoftext|>


<commit_before>//
extern crate termion;

//
use self::termion::screen::AlternateScreen;
use self::termion::event::{Event, Key, MouseEvent};
use self::termion::input::{TermRead, MouseTerminal};
use self::termion::raw::IntoRawMode;
use self::termion::terminal_size;

use std::io::{self, Write, stdin, Stdout};

//
use core::view::View;
use core::screen::Screen;
use core::codepointinfo::CodepointInfo;

use core::editor::Editor;

//
struct UiState {
    keys: Vec<Event>,
    quit: bool,
    status: String,
    display_status: bool,
    display_view: bool,
    vid: u64,
    nb_view: usize,
}

impl UiState {
    fn new() -> UiState {
        UiState {
            keys: Vec::new(),
            quit: false,
            status: String::new(),
            display_status: true,
            display_view: true,
            vid: 0,
            nb_view: 0,
        }
    }
}

pub fn main_loop(mut editor: &mut Editor) {

    let mut ui_state = UiState::new();

    let (width, height) = terminal_size().unwrap();

    setup_views(editor, width as usize, height as usize);

    //
    let stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap());
    let mut stdout = AlternateScreen::from(stdout);

    write!(stdout, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();
    stdout.flush().unwrap();

    while !ui_state.quit {

        ui_state.nb_view = editor.view_map.len();
        let mut view = editor.view_map.get_mut(&ui_state.vid);

        let status_line_y = height;

        if ui_state.display_view == true {
            draw_view(&mut view.as_mut().unwrap(), &mut stdout);
        }

        if ui_state.display_status == true {
            display_status_line(&mut view.as_mut().unwrap(),
                                &ui_state.status,
                                status_line_y,
                                width,
                                &mut stdout);
        }

        process_input_events(&mut ui_state, &mut view.as_mut().unwrap());
    }

    // quit
    // clear, restore cursor
    write!(stdout, "{}{}", termion::clear::All, termion::cursor::Show).unwrap();
    stdout.flush().unwrap();
}

fn setup_views(editor: &mut Editor, width: usize, height: usize) {

    let mut views = Vec::new();

    let mut vid = 0;

    for (_, b) in &editor.document_map {

        let view = View::new(vid,
                             0 as u64,
                             width as usize,
                             height as usize,
                             Some(b.clone()));
        views.push(view);
        vid += 1;
    }

    for view in views {
        &editor.view_map.insert(view.id, Box::new(view));
    }
}

fn fill_screen(view: &mut View) {

    match view.document {

        Some(ref buf) => {

            view.screen.clear();

            let mut offset = view.start_offset;

            let data = &buf.borrow().buffer.data;
            for c in data {

                let mut displayed_cp: char = *c as char;
                if *c as char == '\n' as char {
                    displayed_cp = ' ';
                }

                let cpi = CodepointInfo {
                    cp: *c as char,
                    displayed_cp: displayed_cp,
                    offset: offset,
                    is_selected: false,
                };

                let (ok, _) = view.screen.push(cpi);
                offset += 1;
                if ok == false {
                    break;
                }
            }
            view.end_offset = offset;

            // brute force for now
            let mut screen = &mut view.screen;

            for m in &buf.borrow().moving_marks {

                // TODO: screen.find_line_by_offset(m.offset) -> Option<&mut Line>
                if m.offset >= view.start_offset && m.offset <= view.end_offset {
                    for l in 0..screen.height {
                        let line = screen.get_mut_line(l).unwrap();
                        for c in 0..line.used {
                            let mut cpi = line.get_mut_cpi(c).unwrap();
                            if cpi.offset == m.offset {
                                cpi.is_selected = true;
                            }
                        }
                    }
                }
            }
        }
        None => {}
    }
}

fn draw_screen(screen: &mut Screen, mut stdout: &mut Stdout) {

    write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap();

    for l in 0..screen.height {

        terminal_cursor_to(&mut stdout, 1, (l + 1) as u16);

        let line = screen.get_line(l).unwrap();

        for c in 0..line.used {

            let cpi = line.get_cpi(c).unwrap();

            if cpi.is_selected == true {
                write!(stdout, "{}", termion::style::Invert).unwrap();
            }

            write!(stdout, "{}", cpi.displayed_cp).unwrap();
            write!(stdout, "{}", termion::style::Reset).unwrap();
        }

        for _ in line.used..line.width {
            write!(stdout, " ").unwrap();
        }
    }

    stdout.flush().unwrap();
}

/*
    TODO:
    1 : be explicit
    2 : create editor internal result type Result<>
    3 : use idomatic    func()? style
*/
fn draw_view(mut view: &mut View, mut stdout: &mut Stdout) {

    fill_screen(&mut view);
    draw_screen(&mut view.screen, &mut stdout);
}

fn terminal_clear_current_line(mut stdout: &mut Stdout, line_width: u16) {
    for _ in 0..line_width {
        write!(stdout, " ").unwrap();
    }
}

fn terminal_cursor_to(mut stdout: &mut Stdout, x: u16, y: u16) {
    write!(stdout, "{}", termion::cursor::Goto(x, y)).unwrap();
}

fn process_input_events(ui_state: &mut UiState, view: &mut View) {
    for evt in stdin().events() {

        ui_state.keys.push(evt.unwrap());
        let evt = ui_state.keys[ui_state.keys.len() - 1].clone();

        // Print recieved Events...
        match evt {

            Event::Key(k) => {
                match k {
                    // Exit.
                    Key::Ctrl('r') => {
                        ui_state.keys.clear();
                    }

                    Key::Ctrl('c') => {
                        if ui_state.keys.len() > 1 {
                            if let Event::Key(prev_event) = ui_state.keys[ui_state.keys.len() - 2] {
                                if let Key::Ctrl(prev_char) = prev_event {
                                    if prev_char == 'x' {
                                        ui_state.quit = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    Key::Char(c) => {
                        if c == '\n' {
                            ui_state.status = format!("'{}'", "<newline>");
                        } else {
                            ui_state.status = format!("'{}'", c);
                        }
                    }
                    Key::Alt(c) => ui_state.status = format!("Alt-{}", c),
                    Key::Ctrl(c) => ui_state.status = format!("Ctrl-{}", c),

                    Key::F(1) => {
                        if ui_state.vid > 0 {
                            ui_state.vid -= 1;
                        }
                        break;
                    }

                    Key::F(2) => {
                        ui_state.vid = ::std::cmp::min(ui_state.vid + 1,
                                                       (ui_state.nb_view - 1) as u64);
                        break;
                    }

                    Key::F(f) => ui_state.status = format!("F{:?}", f),
                    Key::Left => {
                        ui_state.status = {
                            let mut doc = view.document.as_mut().unwrap().borrow_mut();
                            for m in &mut doc.moving_marks {
                                if m.offset > 0 {
                                    m.offset -= 1;
                                }
                            }
                            format!("<left>")
                        }
                    }
                    Key::Right => {
                        ui_state.status = {
                            let mut doc = view.document.as_mut().unwrap().borrow_mut();
                            let buffer_size = doc.buffer.size as u64;

                            for m in &mut doc.moving_marks {
                                m.offset += 1;
                                if m.offset > buffer_size {
                                    m.offset = buffer_size
                                }
                            }

                            format!("<right>")
                        }
                    }
                    Key::Up => ui_state.status = format!("<up>"),
                    Key::Down => ui_state.status = format!("<down>"),
                    Key::Backspace => ui_state.status = format!("<backspace>"),
                    Key::Home => ui_state.status = format!("<Home>"),
                    Key::End => ui_state.status = format!("<End>"),
                    Key::PageUp => ui_state.status = format!("<PageUp>"),
                    Key::PageDown => ui_state.status = format!("<PageDown>"),
                    Key::Delete => ui_state.status = format!("<Delete>"),
                    Key::Insert => ui_state.status = format!("<Insert>"),
                    Key::Esc => ui_state.status = format!("<Esc>"),
                    _ => ui_state.status = format!("Other"),
                }
            }

            Event::Mouse(m) => {
                match m {
                    MouseEvent::Press(mb, x, y) => {
                        ui_state.status =
                            format!("MouseEvent::Press => MouseButton {:?} @ ({}, {})", mb, x, y);
                    }

                    MouseEvent::Release(x, y) => {
                        ui_state.status = format!("MouseEvent::Release => @ ({}, {})", x, y);
                    }

                    MouseEvent::Hold(x, y) => {
                        ui_state.status = format!("MouseEvent::Hold => @ ({}, {})", x, y);
                    }
                };
            }

            Event::Unsupported(e) => {
                ui_state.status = format!("Event::Unsupported {:?}", e);
            }
        }

        break;
    }
}

fn display_status_line(view: &View, status: &str, line: u16, width: u16, mut stdout: &mut Stdout) {

    let doc = match view.document {
        Some(ref d) => d.borrow(),
        None => return,
    };

    let name = doc.name.as_str();
    let file_name = doc.buffer.file_name.as_str();

    // select/clear last line
    terminal_cursor_to(&mut stdout, 1, line);
    terminal_clear_current_line(&mut stdout, width);
    terminal_cursor_to(&mut stdout, 1, line);

    let status_str = format!("line {} document_name '{}', file: '{}', event '{}'",
                             line,
                             name,
                             file_name,
                             status);

    print!("{}", status_str);
    stdout.flush().unwrap();
}
<commit_msg>add end-of-file rendering<commit_after>//
extern crate termion;

//
use self::termion::screen::AlternateScreen;
use self::termion::event::{Event, Key, MouseEvent};
use self::termion::input::{TermRead, MouseTerminal};
use self::termion::raw::IntoRawMode;
use self::termion::terminal_size;

use std::io::{self, Write, stdin, Stdout};

//
use core::view::View;
use core::screen::Screen;
use core::codepointinfo::CodepointInfo;

use core::editor::Editor;

//
struct UiState {
    keys: Vec<Event>,
    quit: bool,
    status: String,
    display_status: bool,
    display_view: bool,
    vid: u64,
    nb_view: usize,
}

impl UiState {
    fn new() -> UiState {
        UiState {
            keys: Vec::new(),
            quit: false,
            status: String::new(),
            display_status: true,
            display_view: true,
            vid: 0,
            nb_view: 0,
        }
    }
}

pub fn main_loop(mut editor: &mut Editor) {

    let mut ui_state = UiState::new();

    let (width, height) = terminal_size().unwrap();

    setup_views(editor, width as usize, height as usize);

    //
    let stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap());
    let mut stdout = AlternateScreen::from(stdout);

    write!(stdout, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();
    stdout.flush().unwrap();

    while !ui_state.quit {

        ui_state.nb_view = editor.view_map.len();
        let mut view = editor.view_map.get_mut(&ui_state.vid);

        let status_line_y = height;

        if ui_state.display_view == true {
            draw_view(&mut view.as_mut().unwrap(), &mut stdout);
        }

        if ui_state.display_status == true {
            display_status_line(&mut view.as_mut().unwrap(),
                                &ui_state.status,
                                status_line_y,
                                width,
                                &mut stdout);
        }

        process_input_events(&mut ui_state, &mut view.as_mut().unwrap());
    }

    // quit
    // clear, restore cursor
    write!(stdout, "{}{}", termion::clear::All, termion::cursor::Show).unwrap();
    stdout.flush().unwrap();
}

fn setup_views(editor: &mut Editor, width: usize, height: usize) {

    let mut views = Vec::new();

    let mut vid = 0;

    for (_, b) in &editor.document_map {

        let view = View::new(vid,
                             0 as u64,
                             width as usize,
                             height as usize,
                             Some(b.clone()));
        views.push(view);
        vid += 1;
    }

    for view in views {
        &editor.view_map.insert(view.id, Box::new(view));
    }
}

fn fill_screen(view: &mut View) {

    match view.document {

        Some(ref buf) => {

            view.screen.clear();

            let mut offset = view.start_offset;

            let data = &buf.borrow().buffer.data;
            for c in data {

                let mut displayed_cp: char = *c as char;
                if *c as char == '\n' as char {
                    displayed_cp = ' ';
                }

                let cpi = CodepointInfo {
                    cp: *c as char,
                    displayed_cp: displayed_cp,
                    offset: offset,
                    is_selected: false,
                };

                let (ok, _) = view.screen.push(cpi);
                offset += 1;
                if ok == false {
                    break;
                }
            }
            view.end_offset = offset;

            if view.end_offset == buf.borrow().buffer.size as u64 {
                view.screen
                    .push(CodepointInfo {
                              cp: ' ',
                              displayed_cp: ' ',
                              offset: offset,
                              is_selected: false,
                          });
            }

            // brute force for now
            let mut screen = &mut view.screen;

            for m in &buf.borrow().moving_marks {

                // TODO: screen.find_line_by_offset(m.offset) -> Option<&mut Line>
                if m.offset >= view.start_offset && m.offset <= view.end_offset {
                    for l in 0..screen.height {
                        let line = screen.get_mut_line(l).unwrap();
                        for c in 0..line.used {
                            let mut cpi = line.get_mut_cpi(c).unwrap();
                            if cpi.offset == m.offset {
                                cpi.is_selected = true;
                            }
                        }
                    }
                }
            }
        }
        None => {}
    }
}

fn draw_screen(screen: &mut Screen, mut stdout: &mut Stdout) {

    write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap();

    for l in 0..screen.height {

        terminal_cursor_to(&mut stdout, 1, (l + 1) as u16);

        let line = screen.get_line(l).unwrap();

        for c in 0..line.used {

            let cpi = line.get_cpi(c).unwrap();

            if cpi.is_selected == true {
                write!(stdout, "{}", termion::style::Invert).unwrap();
            }

            write!(stdout, "{}", cpi.displayed_cp).unwrap();
            write!(stdout, "{}", termion::style::Reset).unwrap();
        }

        for _ in line.used..line.width {
            write!(stdout, " ").unwrap();
        }
    }

    stdout.flush().unwrap();
}

/*
    TODO:
    1 : be explicit
    2 : create editor internal result type Result<>
    3 : use idomatic    func()? style
*/
fn draw_view(mut view: &mut View, mut stdout: &mut Stdout) {

    fill_screen(&mut view);
    draw_screen(&mut view.screen, &mut stdout);
}

fn terminal_clear_current_line(mut stdout: &mut Stdout, line_width: u16) {
    for _ in 0..line_width {
        write!(stdout, " ").unwrap();
    }
}

fn terminal_cursor_to(mut stdout: &mut Stdout, x: u16, y: u16) {
    write!(stdout, "{}", termion::cursor::Goto(x, y)).unwrap();
}

fn process_input_events(ui_state: &mut UiState, view: &mut View) {
    for evt in stdin().events() {

        ui_state.keys.push(evt.unwrap());
        let evt = ui_state.keys[ui_state.keys.len() - 1].clone();

        // Print recieved Events...
        match evt {

            Event::Key(k) => {
                match k {
                    // Exit.
                    Key::Ctrl('r') => {
                        ui_state.keys.clear();
                    }

                    Key::Ctrl('c') => {
                        if ui_state.keys.len() > 1 {
                            if let Event::Key(prev_event) = ui_state.keys[ui_state.keys.len() - 2] {
                                if let Key::Ctrl(prev_char) = prev_event {
                                    if prev_char == 'x' {
                                        ui_state.quit = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    Key::Char(c) => {
                        if c == '\n' {
                            ui_state.status = format!("'{}'", "<newline>");
                        } else {
                            ui_state.status = format!("'{}'", c);
                        }
                    }
                    Key::Alt(c) => ui_state.status = format!("Alt-{}", c),
                    Key::Ctrl(c) => ui_state.status = format!("Ctrl-{}", c),

                    Key::F(1) => {
                        if ui_state.vid > 0 {
                            ui_state.vid -= 1;
                        }
                        break;
                    }

                    Key::F(2) => {
                        ui_state.vid = ::std::cmp::min(ui_state.vid + 1,
                                                       (ui_state.nb_view - 1) as u64);
                        break;
                    }

                    Key::F(f) => ui_state.status = format!("F{:?}", f),
                    Key::Left => {
                        ui_state.status = {
                            let mut doc = view.document.as_mut().unwrap().borrow_mut();
                            for m in &mut doc.moving_marks {
                                if m.offset > 0 {
                                    m.offset -= 1;
                                }
                            }
                            format!("<left>")
                        }
                    }
                    Key::Right => {
                        ui_state.status = {
                            let mut doc = view.document.as_mut().unwrap().borrow_mut();
                            let buffer_size = doc.buffer.size as u64;

                            for m in &mut doc.moving_marks {
                                m.offset += 1;
                                if m.offset > buffer_size {
                                    m.offset = buffer_size
                                }
                            }

                            format!("<right>")
                        }
                    }
                    Key::Up => ui_state.status = format!("<up>"),
                    Key::Down => ui_state.status = format!("<down>"),
                    Key::Backspace => ui_state.status = format!("<backspace>"),
                    Key::Home => ui_state.status = format!("<Home>"),
                    Key::End => ui_state.status = format!("<End>"),
                    Key::PageUp => ui_state.status = format!("<PageUp>"),
                    Key::PageDown => ui_state.status = format!("<PageDown>"),
                    Key::Delete => ui_state.status = format!("<Delete>"),
                    Key::Insert => ui_state.status = format!("<Insert>"),
                    Key::Esc => ui_state.status = format!("<Esc>"),
                    _ => ui_state.status = format!("Other"),
                }
            }

            Event::Mouse(m) => {
                match m {
                    MouseEvent::Press(mb, x, y) => {
                        ui_state.status =
                            format!("MouseEvent::Press => MouseButton {:?} @ ({}, {})", mb, x, y);
                    }

                    MouseEvent::Release(x, y) => {
                        ui_state.status = format!("MouseEvent::Release => @ ({}, {})", x, y);
                    }

                    MouseEvent::Hold(x, y) => {
                        ui_state.status = format!("MouseEvent::Hold => @ ({}, {})", x, y);
                    }
                };
            }

            Event::Unsupported(e) => {
                ui_state.status = format!("Event::Unsupported {:?}", e);
            }
        }

        break;
    }
}

fn display_status_line(view: &View, status: &str, line: u16, width: u16, mut stdout: &mut Stdout) {

    let doc = match view.document {
        Some(ref d) => d.borrow(),
        None => return,
    };

    let name = doc.name.as_str();
    let file_name = doc.buffer.file_name.as_str();

    // select/clear last line
    terminal_cursor_to(&mut stdout, 1, line);
    terminal_clear_current_line(&mut stdout, width);
    terminal_cursor_to(&mut stdout, 1, line);

    let status_str = format!("line {} document_name '{}', file: '{}', event '{}'",
                             line,
                             name,
                             file_name,
                             status);

    print!("{}", status_str);
    stdout.flush().unwrap();
}
<|endoftext|>