<commit_before>//! Procedural macro implementing `#[derive(Enum)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

use std::iter;

use syn::{Data, DataEnum, DeriveInput, Fields, Ident, Variant};

fn generate_enum_code(name: Ident, data_enum: DataEnum) -> proc_macro2::TokenStream {
    let enum_count = data_enum.variants.len();
    let mut has_discriminants = false;

    for &Variant {
        ref fields,
        ref discriminant,
        ..
    } in &data_enum.variants
    {
        match *fields {
            Fields::Unit => (),
            _ => return quote!(compile_error! {"#[derive(Enum)] requires C style style enum"}),
        }

        if discriminant.is_some() {
            has_discriminants = true;
        }
    }

    let variants_names_a = data_enum.variants.iter().map(|variant| &variant.ident);
    let variants_names_b = data_enum.variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(&name);
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..enum_count;

    let to_usize = if enum_count == 0 || has_discriminants {
        let variants_names = data_enum.variants.iter().map(|variant| &variant.ident);
        let repeat_name = repeat_name_a.clone();
        let counter = counter.clone();

        quote! {
            match self {
                #(
                    #repeat_name::#variants_names => #counter,
                )*
            }
        }
    } else {
        quote! { self as usize }
    };

    quote! {
        #[automatically_derived]
        impl<V> ::enum_map::Enum<V> for #name {
            type Array = [V; #enum_count];
            const POSSIBLE_VALUES: usize = #enum_count;

            #[inline]
            fn slice(array: &Self::Array) -> &[V] {
                array
            }

            #[inline]
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }

            #[inline]
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variants_names_a,
                    )*
                    _ => unreachable!()
                }
            }

            #[inline]
            fn to_usize(self) -> usize {
                #to_usize
            }

            #[inline]
            fn from_function<F: FnMut(Self) -> V>(mut _f: F) -> Self::Array {
                [#(
                    _f(#repeat_name_b::#variants_names_b),
                )*]
            }
        }
    }
}

/// Procedural derive generating `enum_map::Enum` implementation.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::Enum;
///
/// #[derive(Enum)]
/// enum A {
///     B,
///     C,
///     D,
/// }
///
/// assert_eq!(Enum::<()>::to_usize(A::C), 1);
/// ```
#[proc_macro_derive(Enum)]
pub fn derive_enum_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input: DeriveInput = syn::parse(input).unwrap();

    let result = match input.data {
        Data::Enum(data_enum) => generate_enum_code(input.ident, data_enum),
        _ => quote!(compile_error! {"#[derive(Enum)] is only defined for enums"}),
    };

    result.into()
}
<commit_msg>Improve C style enum error message<commit_after>//! Procedural macro implementing `#[derive(Enum)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;
extern crate syn;

use std::iter;

use syn::spanned::Spanned;
use syn::{Data, DataEnum, DeriveInput, Fields, Ident, Variant};

fn generate_enum_code(name: Ident, data_enum: DataEnum) -> proc_macro2::TokenStream {
    let enum_count = data_enum.variants.len();
    let mut has_discriminants = false;

    for variant in &data_enum.variants {
        let Variant {
            fields,
            discriminant,
            ..
        } = variant;
        match fields {
            Fields::Unit => (),
            _ => {
                return syn::Error::new(
                    fields.span(),
                    "#[derive(Enum)] requires C style style enum",
                )
                .to_compile_error();
            }
        }

        if discriminant.is_some() {
            has_discriminants = true;
        }
    }

    let variants_names_a = data_enum.variants.iter().map(|variant| &variant.ident);
    let variants_names_b = data_enum.variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(&name);
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..enum_count;

    let to_usize = if enum_count == 0 || has_discriminants {
        let variants_names = data_enum.variants.iter().map(|variant| &variant.ident);
        let repeat_name = repeat_name_a.clone();
        let counter = counter.clone();

        quote! {
            match self {
                #(
                    #repeat_name::#variants_names => #counter,
                )*
            }
        }
    } else {
        quote! { self as usize }
    };

    quote! {
        #[automatically_derived]
        impl<V> ::enum_map::Enum<V> for #name {
            type Array = [V; #enum_count];
            const POSSIBLE_VALUES: usize = #enum_count;

            #[inline]
            fn slice(array: &Self::Array) -> &[V] {
                array
            }

            #[inline]
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }

            #[inline]
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variants_names_a,
                    )*
                    _ => unreachable!()
                }
            }

            #[inline]
            fn to_usize(self) -> usize {
                #to_usize
            }

            #[inline]
            fn from_function<F: FnMut(Self) -> V>(mut _f: F) -> Self::Array {
                [#(
                    _f(#repeat_name_b::#variants_names_b),
                )*]
            }
        }
    }
}

/// Procedural derive generating `enum_map::Enum` implementation.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::Enum;
///
/// #[derive(Enum)]
/// enum A {
///     B,
///     C,
///     D,
/// }
///
/// assert_eq!(Enum::<()>::to_usize(A::C), 1);
/// ```
#[proc_macro_derive(Enum)]
pub fn derive_enum_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input: DeriveInput = syn::parse(input).unwrap();

    let result = match input.data {
        Data::Enum(data_enum) => generate_enum_code(input.ident, data_enum),
        _ => quote!(compile_error! {"#[derive(Enum)] is only defined for enums"}),
    };

    result.into()
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};

use crate::complete_hint_line;
use crate::config::Config;
use crate::edit::State;
use crate::error;
use crate::history::SearchDirection;
use crate::keymap::{Anchor, At, Cmd, Movement, Word};
use crate::keymap::{InputState, Refresher};
use crate::kill_ring::{KillRing, Mode};
use crate::line_buffer::WordAction;
use crate::{Helper, Result};

pub enum Status {
    Proceed,
    Submit,
}

pub fn execute<H: Helper>(
    cmd: Cmd,
    s: &mut State<'_, '_, H>,
    input_state: &InputState,
    kill_ring: &Arc<Mutex<KillRing>>,
    config: &Config,
) -> Result<Status> {
    use Status::{Proceed, Submit};

    match cmd {
        Cmd::CompleteHint => {
            complete_hint_line(s)?;
        }
        Cmd::SelfInsert(n, c) => {
            s.edit_insert(c, n)?;
        }
        Cmd::Insert(n, text) => {
            s.edit_yank(input_state, &text, Anchor::Before, n)?;
        }
        Cmd::Move(Movement::BeginningOfLine) => {
            // Move to the beginning of line.
            s.edit_move_home()?;
        }
        Cmd::Move(Movement::ViFirstPrint) => {
            s.edit_move_home()?;
            s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
        }
        Cmd::Move(Movement::BackwardChar(n)) => {
            // Move back a character.
            s.edit_move_backward(n)?;
        }
        Cmd::ReplaceChar(n, c) => s.edit_replace_char(c, n)?,
        Cmd::Replace(mvt, text) => {
            s.edit_kill(&mvt)?;
            if let Some(text) = text {
                s.edit_insert_text(&text)?;
            }
        }
        Cmd::Overwrite(c) => {
            s.edit_overwrite_char(c)?;
        }
        Cmd::EndOfFile => {
            if s.has_hint() || !s.is_default_prompt() {
                // Force a refresh without hints to leave the previous
                // line as the user typed it after a newline.
                s.refresh_line_with_msg(None)?;
            }
            if s.line.is_empty() {
                return Err(error::ReadlineError::Eof);
            } else if !input_state.is_emacs_mode() {
                return Ok(Submit);
            }
        }
        Cmd::Move(Movement::EndOfLine) => {
            // Move to the end of line.
            s.edit_move_end()?;
        }
        Cmd::Move(Movement::ForwardChar(n)) => {
            // Move forward a character.
            s.edit_move_forward(n)?;
        }
        Cmd::ClearScreen => {
            // Clear the screen leaving the current line at the top of the screen.
            s.clear_screen()?;
            s.refresh_line()?;
        }
        Cmd::NextHistory => {
            // Fetch the next command from the history list.
            s.edit_history_next(false)?;
        }
        Cmd::PreviousHistory => {
            // Fetch the previous command from the history list.
            s.edit_history_next(true)?;
        }
        Cmd::LineUpOrPreviousHistory(n) => {
            if !s.edit_move_line_up(n)? {
                s.edit_history_next(true)?;
            }
        }
        Cmd::LineDownOrNextHistory(n) => {
            if !s.edit_move_line_down(n)? {
                s.edit_history_next(false)?;
            }
        }
        Cmd::HistorySearchBackward => s.edit_history_search(SearchDirection::Reverse)?,
        Cmd::HistorySearchForward => s.edit_history_search(SearchDirection::Forward)?,
        Cmd::TransposeChars => {
            // Exchange the char before cursor with the character at cursor.
            s.edit_transpose_chars()?;
        }
        Cmd::Yank(n, anchor) => {
            // retrieve (yank) last item killed
            let mut kill_ring = kill_ring.lock().unwrap();
            if let Some(text) = kill_ring.yank() {
                s.edit_yank(input_state, text, anchor, n)?;
            }
        }
        Cmd::ViYankTo(ref mvt) => {
            if let Some(text) = s.line.copy(mvt) {
                let mut kill_ring = kill_ring.lock().unwrap();
                kill_ring.kill(&text, Mode::Append);
            }
        }
        Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } | Cmd::Newline => {
            if s.has_hint() || !s.is_default_prompt() {
                // Force a refresh without hints to leave the previous
                // line as the user typed it after a newline.
                s.refresh_line_with_msg(None)?;
            }
            let validation_result = s.validate()?;
            let valid = validation_result.is_valid();
            let end = s.line.is_end_of_input();
            match (cmd, valid, end) {
                (Cmd::AcceptLine, ..)
                | (Cmd::AcceptOrInsertLine { .. }, true, true)
                | (
                    Cmd::AcceptOrInsertLine {
                        accept_in_the_middle: true,
                    },
                    true,
                    _,
                ) => {
                    return Ok(Submit);
                }
                (Cmd::AcceptOrInsertLine { .. }, false, _)
                | (Cmd::AcceptOrInsertLine { .. }, true, false) => {
                    if valid || !validation_result.has_message() {
                        s.edit_insert('\n', 1)?;
                    }
                }
                (Cmd::Newline, ..) => {
                    s.edit_insert('\n', 1)?;
                }
                _ => unreachable!(),
            }
        }
        Cmd::BeginningOfHistory => {
            // move to first entry in history
            s.edit_history(true)?;
        }
        Cmd::EndOfHistory => {
            // move to last entry in history
            s.edit_history(false)?;
        }
        Cmd::Move(Movement::BackwardWord(n, word_def)) => {
            // move backwards one word
            s.edit_move_to_prev_word(word_def, n)?;
        }
        Cmd::CapitalizeWord => {
            // capitalize word after point
            s.edit_word(WordAction::Capitalize)?;
        }
        Cmd::Kill(ref mvt) => {
            s.edit_kill(mvt)?;
        }
        Cmd::Move(Movement::ForwardWord(n, at, word_def)) => {
            // move forwards one word
            s.edit_move_to_next_word(at, word_def, n)?;
        }
        Cmd::Move(Movement::LineUp(n)) => {
            s.edit_move_line_up(n)?;
        }
        Cmd::Move(Movement::LineDown(n)) => {
            s.edit_move_line_down(n)?;
        }
        Cmd::Move(Movement::BeginningOfBuffer) => {
            // Move to the start of the buffer.
            s.edit_move_buffer_start()?;
        }
        Cmd::Move(Movement::EndOfBuffer) => {
            // Move to the end of the buffer.
            s.edit_move_buffer_end()?;
        }
        Cmd::DowncaseWord => {
            // lowercase word after point
            s.edit_word(WordAction::Lowercase)?;
        }
        Cmd::TransposeWords(n) => {
            // transpose words
            s.edit_transpose_words(n)?;
        }
        Cmd::UpcaseWord => {
            // uppercase word after point
            s.edit_word(WordAction::Uppercase)?;
        }
        Cmd::YankPop => {
            // yank-pop
            let mut kill_ring = kill_ring.lock().unwrap();
            if let Some((yank_size, text)) = kill_ring.yank_pop() {
                s.edit_yank_pop(yank_size, text)?;
            }
        }
        Cmd::Move(Movement::ViCharSearch(n, cs)) => s.edit_move_to(cs, n)?,
        Cmd::Undo(n) => {
            if s.changes.borrow_mut().undo(&mut s.line, n) {
                s.refresh_line()?;
            }
        }
        Cmd::Dedent(mvt) => {
            s.edit_indent(&mvt, config.indent_size(), true)?;
        }
        Cmd::Indent(mvt) => {
            s.edit_indent(&mvt, config.indent_size(), false)?;
        }
        Cmd::Interrupt => {
            // Move to end, in case cursor was in the middle of the
            // line, so that next thing application prints goes after
            // the input
            s.move_cursor_to_end()?;
            return Err(error::ReadlineError::Interrupted);
        }
        _ => {
            // Ignore the character typed.
        }
    }
    Ok(Proceed)
}
<commit_msg>apply gwenn suggestions<commit_after>use std::sync::{Arc, Mutex};

use crate::complete_hint_line;
use crate::config::Config;
use crate::edit::State;
use crate::error;
use crate::history::SearchDirection;
use crate::keymap::{Anchor, At, Cmd, Movement, Word};
use crate::keymap::{InputState, Refresher};
use crate::kill_ring::{KillRing, Mode};
use crate::line_buffer::WordAction;
use crate::{Helper, Result};

pub enum Status {
    Proceed,
    Submit,
}

pub fn execute<H: Helper>(
    cmd: Cmd,
    s: &mut State<'_, '_, H>,
    input_state: &InputState,
    kill_ring: &Arc<Mutex<KillRing>>,
    config: &Config,
) -> Result<Status> {
    use Status::{Proceed, Submit};

    match cmd {
        Cmd::EndOfFile | Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } | Cmd::Newline => {
            if s.has_hint() || !s.is_default_prompt() {
                // Force a refresh without hints to leave the previous
                // line as the user typed it after a newline.
                s.refresh_line_with_msg(None)?;
            }
        }
        _ => {}
    };
    match cmd {
        Cmd::CompleteHint => {
            complete_hint_line(s)?;
        }
        Cmd::SelfInsert(n, c) => {
            s.edit_insert(c, n)?;
        }
        Cmd::Insert(n, text) => {
            s.edit_yank(input_state, &text, Anchor::Before, n)?;
        }
        Cmd::Move(Movement::BeginningOfLine) => {
            // Move to the beginning of line.
            s.edit_move_home()?;
        }
        Cmd::Move(Movement::ViFirstPrint) => {
            s.edit_move_home()?;
            s.edit_move_to_next_word(At::Start, Word::Big, 1)?;
        }
        Cmd::Move(Movement::BackwardChar(n)) => {
            // Move back a character.
            s.edit_move_backward(n)?;
        }
        Cmd::ReplaceChar(n, c) => s.edit_replace_char(c, n)?,
        Cmd::Replace(mvt, text) => {
            s.edit_kill(&mvt)?;
            if let Some(text) = text {
                s.edit_insert_text(&text)?;
            }
        }
        Cmd::Overwrite(c) => {
            s.edit_overwrite_char(c)?;
        }
        Cmd::EndOfFile => {
            if s.line.is_empty() {
                return Err(error::ReadlineError::Eof);
            } else if !input_state.is_emacs_mode() {
                return Ok(Submit);
            }
        }
        Cmd::Move(Movement::EndOfLine) => {
            // Move to the end of line.
            s.edit_move_end()?;
        }
        Cmd::Move(Movement::ForwardChar(n)) => {
            // Move forward a character.
            s.edit_move_forward(n)?;
        }
        Cmd::ClearScreen => {
            // Clear the screen leaving the current line at the top of the screen.
            s.clear_screen()?;
            s.refresh_line()?;
        }
        Cmd::NextHistory => {
            // Fetch the next command from the history list.
            s.edit_history_next(false)?;
        }
        Cmd::PreviousHistory => {
            // Fetch the previous command from the history list.
            s.edit_history_next(true)?;
        }
        Cmd::LineUpOrPreviousHistory(n) => {
            if !s.edit_move_line_up(n)? {
                s.edit_history_next(true)?;
            }
        }
        Cmd::LineDownOrNextHistory(n) => {
            if !s.edit_move_line_down(n)? {
                s.edit_history_next(false)?;
            }
        }
        Cmd::HistorySearchBackward => s.edit_history_search(SearchDirection::Reverse)?,
        Cmd::HistorySearchForward => s.edit_history_search(SearchDirection::Forward)?,
        Cmd::TransposeChars => {
            // Exchange the char before cursor with the character at cursor.
            s.edit_transpose_chars()?;
        }
        Cmd::Yank(n, anchor) => {
            // retrieve (yank) last item killed
            let mut kill_ring = kill_ring.lock().unwrap();
            if let Some(text) = kill_ring.yank() {
                s.edit_yank(input_state, text, anchor, n)?;
            }
        }
        Cmd::ViYankTo(ref mvt) => {
            if let Some(text) = s.line.copy(mvt) {
                let mut kill_ring = kill_ring.lock().unwrap();
                kill_ring.kill(&text, Mode::Append);
            }
        }
        Cmd::Newline => {
            s.edit_insert('\n', 1)?;
        }
        Cmd::AcceptLine | Cmd::AcceptOrInsertLine { .. } => {
            let validation_result = s.validate()?;
            let valid = validation_result.is_valid();
            let end = s.line.is_end_of_input();
            match (cmd, valid, end) {
                (Cmd::AcceptLine, ..)
                | (Cmd::AcceptOrInsertLine { .. }, true, true)
                | (
                    Cmd::AcceptOrInsertLine {
                        accept_in_the_middle: true,
                    },
                    true,
                    _,
                ) => {
                    return Ok(Submit);
                }
                (Cmd::AcceptOrInsertLine { .. }, false, _)
                | (Cmd::AcceptOrInsertLine { .. }, true, false) => {
                    if valid || !validation_result.has_message() {
                        s.edit_insert('\n', 1)?;
                    }
                }
                _ => unreachable!(),
            }
        }
        Cmd::BeginningOfHistory => {
            // move to first entry in history
            s.edit_history(true)?;
        }
        Cmd::EndOfHistory => {
            // move to last entry in history
            s.edit_history(false)?;
        }
        Cmd::Move(Movement::BackwardWord(n, word_def)) => {
            // move backwards one word
            s.edit_move_to_prev_word(word_def, n)?;
        }
        Cmd::CapitalizeWord => {
            // capitalize word after point
            s.edit_word(WordAction::Capitalize)?;
        }
        Cmd::Kill(ref mvt) => {
            s.edit_kill(mvt)?;
        }
        Cmd::Move(Movement::ForwardWord(n, at, word_def)) => {
            // move forwards one word
            s.edit_move_to_next_word(at, word_def, n)?;
        }
        Cmd::Move(Movement::LineUp(n)) => {
            s.edit_move_line_up(n)?;
        }
        Cmd::Move(Movement::LineDown(n)) => {
            s.edit_move_line_down(n)?;
        }
        Cmd::Move(Movement::BeginningOfBuffer) => {
            // Move to the start of the buffer.
            s.edit_move_buffer_start()?;
        }
        Cmd::Move(Movement::EndOfBuffer) => {
            // Move to the end of the buffer.
            s.edit_move_buffer_end()?;
        }
        Cmd::DowncaseWord => {
            // lowercase word after point
            s.edit_word(WordAction::Lowercase)?;
        }
        Cmd::TransposeWords(n) => {
            // transpose words
            s.edit_transpose_words(n)?;
        }
        Cmd::UpcaseWord => {
            // uppercase word after point
            s.edit_word(WordAction::Uppercase)?;
        }
        Cmd::YankPop => {
            // yank-pop
            let mut kill_ring = kill_ring.lock().unwrap();
            if let Some((yank_size, text)) = kill_ring.yank_pop() {
                s.edit_yank_pop(yank_size, text)?;
            }
        }
        Cmd::Move(Movement::ViCharSearch(n, cs)) => s.edit_move_to(cs, n)?,
        Cmd::Undo(n) => {
            if s.changes.borrow_mut().undo(&mut s.line, n) {
                s.refresh_line()?;
            }
        }
        Cmd::Dedent(mvt) => {
            s.edit_indent(&mvt, config.indent_size(), true)?;
        }
        Cmd::Indent(mvt) => {
            s.edit_indent(&mvt, config.indent_size(), false)?;
        }
        Cmd::Interrupt => {
            // Move to end, in case cursor was in the middle of the
            // line, so that next thing application prints goes after
            // the input
            s.move_cursor_to_end()?;
            return Err(error::ReadlineError::Interrupted);
        }
        _ => {
            // Ignore the character typed.
        }
    }
    Ok(Proceed)
}
<|endoftext|>


<commit_before>use std;
use std::os::raw::c_char;

use raw::*;
use pushable::Pushable;

pub struct Context {
    pthx: PerlContext,
    stack: OuroborosStack,
}

macro_rules! simple_wrapper {
    ($meth:ident, $func:ident, $( $arg:ident: $ty:ty ),*) => {
        pub fn $meth(&mut self, $( $arg: $ty ),*) {
            unsafe { $func(self.pthx, &mut self.stack, $( $arg ),*) }
        }
    }
}

impl Context {
    pub fn new(pthx: PerlContext) -> Context {
        unsafe {
            let mut ctx = Context {
                pthx: pthx,
                stack: std::mem::uninitialized(),
            };
            ouroboros_stack_init(ctx.pthx, &mut ctx.stack);
            ctx
        }
    }

    pub fn new_xs(&mut self, name: &str, func: XSUBADDR_t) {
        let cname = std::ffi::CString::new(name).unwrap();
        unsafe {
            Perl_newXS(self.pthx, cname.as_ptr(), func, b"\0" as *const _ as *const c_char);
        }
    }

    simple_wrapper! { prepush, ouroboros_stack_prepush, }
    simple_wrapper! { putback, ouroboros_stack_putback, }

    pub fn push<T>(&mut self, value: T) where T: Pushable {
        value.push_extend(self.pthx, &mut self.stack);
    }

    pub unsafe fn push_unsafe<T>(&mut self, value: T) where T: Pushable {
        value.push_unsafe(self.pthx, &mut self.stack);
    }

    pub fn extend(&mut self, len: Size_t) {
        unsafe {
            ouroboros_stack_extend(self.pthx, &mut self.stack, len);
        }
    }
}
<commit_msg>Make wrapper macro more flexible.<commit_after>use std;
use std::os::raw::c_char;

use raw::*;
use pushable::Pushable;

pub struct Context {
    pthx: PerlContext,
    stack: OuroborosStack,
}

macro_rules! wrapper {
    ($name:ident : $func:ident $( -$flag:ident )* ($( $arg:ident : $ty:ty ),*))
        => (wrapper! { $name : $func $( -$flag )* ( $( $arg : $ty ),* ) -> () });

    ($name:ident : $func:ident ($( $arg:ident : $ty:ty ),*) -> $rt:ty)
        => (wrapper! { $name : $func ( $( $arg: $ty ),* ) self (self.pthx) -> $rt });

    ($name:ident : $func:ident -stack ( $( $arg:ident: $ty:ty ),*) -> $rt:ty)
        => (wrapper! { $name : $func ( $( $arg: $ty ),* ) self (self.pthx, &mut self.stack) -> $rt });

    ($name:ident : $func:ident ( $( $arg:ident: $ty:ty ),* ) $slf:ident ( $( $def:expr ),* ) -> $rt:ty)
        => (pub fn $name(&mut $slf, $( $arg: $ty ),*) -> $rt { unsafe { $func($( $def ),*, $( $arg ),*) } });
}

impl Context {
    pub fn new(pthx: PerlContext) -> Context {
        unsafe {
            let mut ctx = Context {
                pthx: pthx,
                stack: std::mem::uninitialized(),
            };
            ouroboros_stack_init(ctx.pthx, &mut ctx.stack);
            ctx
        }
    }

    pub fn new_xs(&mut self, name: &str, func: XSUBADDR_t) {
        let cname = std::ffi::CString::new(name).unwrap();
        unsafe {
            Perl_newXS(self.pthx, cname.as_ptr(), func, b"\0" as *const _ as *const c_char);
        }
    }

    wrapper! { prepush: ouroboros_stack_prepush -stack () }
    wrapper! { putback: ouroboros_stack_putback -stack () }

    pub fn push<T>(&mut self, value: T) where T: Pushable {
        value.push_extend(self.pthx, &mut self.stack);
    }

    pub unsafe fn push_unsafe<T>(&mut self, value: T) where T: Pushable {
        value.push_unsafe(self.pthx, &mut self.stack);
    }

    pub fn extend(&mut self, len: Size_t) {
        unsafe {
            ouroboros_stack_extend(self.pthx, &mut self.stack, len);
        }
    }
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::io::fs;
#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::random_name;

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", root::homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<commit_msg>Test a project file is actually created.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::io::fs;
#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::random_name;

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", root::homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write, Error ,ErrorKind};
use std::fs::File;
use cursor::Cursor;

/// The Backend is responsible opening files and editing text.
/// It does this by managing a Vec of Buffers that actually edit the text.
/// By making the Backend handle the Buffers, the rest of the editor doesn't have to
/// worry about using the right buffer.
pub struct Backend {
    /// The Buffers being edited
    buffers: Vec<Buffer>,
    /// The index of the current Buffer
    current: usize,
}

impl Backend {
    /// Constructs and returns a new Backend from the command line arguments
    pub fn new() -> Backend {
        Backend {
            buffers: vec![Buffer::from_file(
                // TODO: Replace with real argument parsing. In editor.rs, maybe?
                ::std::env::args().nth(1).unwrap_or(String::from("test.txt"))
            ).unwrap()],
            current: 0,
        }
    }
    /// Returns the lines of text from the buffer that is being edited
    // TODO: Make this higher level so that it is easier to change
    // the buffer representation? Maybe as an iterator?
    pub fn current_lines(&mut self) -> &Vec<String> {
        &self.current_buffer().lines
    }
    /// Returns the number of lines in the current buffer.
    pub fn number_of_lines(&mut self) -> usize {
        self.current_buffer().lines.len()
    }
    /// Returns the length of the line in the current buffer
    pub fn length_of_line(&mut self, line: usize) -> usize {
        self.current_buffer().lines[line].len()
    }
    /// Inserts a newline at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_newline_at(&mut self, cursor: &mut Cursor) {
        // TODO
        let line_len = self.length_of_line(cursor.line);
        let mut buf = self.current_buffer();
        buf.split_line_into_two_at(cursor.line, cursor.column);
        cursor.line += 1;
        cursor.column = 0;

    }
    /// Inserts a backspace at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_backspace_at(&mut self, cursor: &mut Cursor) {
        // TODO
    }
    /// Inserts a character at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_char_at(&mut self, c: char, cursor: &mut Cursor) {
        // BUG: Doesn't work for most non-ascii utf8 text. :(
        self.current_buffer().insert_char_at(c, cursor.line as usize, cursor.column as usize);
        cursor.column += 1;
    }
    /// Returns the current buffer
    // TODO: Does this need to be public?
    pub fn current_buffer(&mut self) -> &mut Buffer {
        &mut self.buffers[self.current]
    }
}

/// A Buffer contains the text being edited and applies the edits to it.
/// It is also responsible for opening and saving files.
pub struct Buffer {
    /// The filename that the Buffer gets saved to.
    pub filename: Option<String>,
    /// The lines of text.
    lines: Vec<String>,
    /// The saved state of the buffer. If dirty is true then there are
    /// unsaved modifications to the Buffer that haven't saved.
    pub dirty: bool,
}
impl Buffer {
    /// Constructs a new, empty buffer that doesn't have a filename to save to.
    pub fn new() -> Buffer {
        Buffer {
            filename: None,
            lines: vec![String::new()],
            dirty: false,
        }
    }
    /// Contructs a new buffer from the contents of a file.
    pub fn from_file(filename: String) -> io::Result<Buffer> {
        let mut file = File::open(&filename)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let mut lines = Vec::new();
        for line in contents.lines() {
            lines.push(String::from(line))
        }
        Ok(Buffer {
            filename: Some(filename),
            lines: lines,
            dirty: false
        })
    }
    /// Saves the contents of the buffer to the file
    pub fn save(&mut self) -> io::Result<()> {
        if let Some(ref filename) = self.filename {
            let mut file = File::create(filename)?;
            for line in &self.lines {
                writeln!(&mut file, "{}", line)?;
            }
        } else {
            return Err(Error::new(ErrorKind::Other, "No file to write to"));
        }
        self.dirty = false;
        Ok(())
    }
    /// Inserts a newline
    pub fn insert_newline_at(&mut self, index: usize, content: String) {
        if index == self.lines.len() {
            self.push_newline(content);
        } else {
            self.lines.insert(index, content);
        }
    }
    /// Adds a new line at the end of the text
    pub fn push_newline(&mut self, content: String) {
        self.lines.push(content);
    }
    /// Returns a line of text as a String
    pub fn get_line(&self, index: usize) -> &String {
        &self.lines[index]
    }
    /// Splits the line at `line` into two lines at column.
    pub fn split_line_into_two_at(&mut self, line: usize, column: usize) {
        let (start, rest) = self.split_line_at(line, column);
        self.lines[line] = start;
        self.insert_newline_at(line + 1, rest);
    }
    /// Splits a line into two Strings
    pub fn split_line_at(&self, line: usize, column: usize) -> (String, String) {
        let (a, b) = self.lines[line].split_at(column);
        (String::from(a), String::from(b))
    }
    /// Inserts a char at a specific line, column
    pub fn insert_char_at(&mut self, c: char, line: usize, column: usize) {
        // TODO fix for unicode
        self.lines[line].insert(column, c);
    }
}
<commit_msg>You can now delete characters and lines! 😄<commit_after>use std::io;
use std::io::{Read, Write, Error ,ErrorKind};
use std::fs::File;
use cursor::Cursor;

/// The Backend is responsible opening files and editing text.
/// It does this by managing a Vec of Buffers that actually edit the text.
/// By making the Backend handle the Buffers, the rest of the editor doesn't have to
/// worry about using the right buffer.
pub struct Backend {
    /// The Buffers being edited
    buffers: Vec<Buffer>,
    /// The index of the current Buffer
    current: usize,
}

impl Backend {
    /// Constructs and returns a new Backend from the command line arguments
    pub fn new() -> Backend {
        Backend {
            buffers: vec![Buffer::from_file(
                // TODO: Replace with real argument parsing. In editor.rs, maybe?
                ::std::env::args().nth(1).unwrap_or(String::from("test.txt"))
            ).unwrap()],
            current: 0,
        }
    }
    /// Returns the lines of text from the buffer that is being edited
    // TODO: Make this higher level so that it is easier to change
    // the buffer representation? Maybe as an iterator?
    pub fn current_lines(&mut self) -> &Vec<String> {
        &self.current_buffer().lines
    }
    /// Returns the number of lines in the current buffer.
    pub fn number_of_lines(&mut self) -> usize {
        self.current_buffer().lines.len()
    }
    /// Returns the length of the line in the current buffer
    pub fn length_of_line(&mut self, line: usize) -> usize {
        self.current_buffer().lines[line].len()
    }
    /// Inserts a newline at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_newline_at(&mut self, cursor: &mut Cursor) {
        let line_len = self.length_of_line(cursor.line);
        let mut buf = self.current_buffer();
        buf.split_line_into_two_at(cursor.line, cursor.column);
        cursor.line += 1;
        cursor.column = 0;

    }
    /// Inserts a backspace at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_backspace_at(&mut self, cursor: &mut Cursor) {
        // TODO
        if cursor.column == 0 && cursor.line == 0 {
            // We are at the top left corner and there is nothing to delete.
            return;
        }
        let mut buf = self.current_buffer();
        if cursor.column == 0 {
            cursor.column = buf.lines[cursor.line - 1].len();
            buf.join_lines_at(cursor.line);
            cursor.line -= 1;
        } else {
            // We remove the char at the column before the cursor because
            // when you use backspace you are trying to delete what
            // comes before.
            buf.delete_char_at(cursor.line, cursor.column - 1);
            cursor.column -= 1;
        }
    }
    /// Inserts a character at the position given by the Cursor and updates
    /// the Cursor to reflect the new position
    pub fn insert_char_at(&mut self, c: char, cursor: &mut Cursor) {
        // BUG: Doesn't work for most non-ascii utf8 text. :(
        self.current_buffer().insert_char_at(c, cursor.line as usize, cursor.column as usize);
        cursor.column += 1;
    }
    /// Returns the current buffer
    // TODO: Does this need to be public?
    pub fn current_buffer(&mut self) -> &mut Buffer {
        &mut self.buffers[self.current]
    }
}

/// A Buffer contains the text being edited and applies the edits to it.
/// It is also responsible for opening and saving files.
pub struct Buffer {
    /// The filename that the Buffer gets saved to.
    pub filename: Option<String>,
    /// The lines of text.
    lines: Vec<String>,
    /// The saved state of the buffer. If dirty is true then there are
    /// unsaved modifications to the Buffer that haven't saved.
    pub dirty: bool,
}
impl Buffer {
    /// Constructs a new, empty buffer that doesn't have a filename to save to.
    pub fn new() -> Buffer {
        Buffer {
            filename: None,
            lines: vec![String::new()],
            dirty: false,
        }
    }
    /// Contructs a new buffer from the contents of a file.
    pub fn from_file(filename: String) -> io::Result<Buffer> {
        let mut file = File::open(&filename)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let mut lines = Vec::new();
        for line in contents.lines() {
            lines.push(String::from(line))
        }
        Ok(Buffer {
            filename: Some(filename),
            lines: lines,
            dirty: false
        })
    }
    /// Saves the contents of the buffer to the file
    pub fn save(&mut self) -> io::Result<()> {
        if let Some(ref filename) = self.filename {
            let mut file = File::create(filename)?;
            for line in &self.lines {
                writeln!(&mut file, "{}", line)?;
            }
        } else {
            return Err(Error::new(ErrorKind::Other, "No file to write to"));
        }
        self.dirty = false;
        Ok(())
    }
    /// Inserts a newline
    pub fn insert_newline_at(&mut self, index: usize, content: String) {
        if index == self.lines.len() {
            self.push_newline(content);
        } else {
            self.lines.insert(index, content);
        }
    }
    /// Adds a new line at the end of the text
    pub fn push_newline(&mut self, content: String) {
        self.lines.push(content);
    }
    /// Returns a line of text as a String
    pub fn get_line(&self, index: usize) -> &String {
        &self.lines[index]
    }
    /// Splits the line at `line` into two lines at column.
    pub fn split_line_into_two_at(&mut self, line: usize, column: usize) {
        let (start, rest) = self.split_line_at(line, column);
        self.lines[line] = start;
        self.insert_newline_at(line + 1, rest);
    }
    /// Splits a line into two Strings
    pub fn split_line_at(&self, line: usize, column: usize) -> (String, String) {
        let (a, b) = self.lines[line].split_at(column);
        (String::from(a), String::from(b))
    }
    /// Inserts a char at a specific line, column
    pub fn insert_char_at(&mut self, c: char, line: usize, column: usize) {
        // TODO fix for unicode
        self.lines[line].insert(column, c);
    }
    /// Moves the line at `line` into the line before it and removes it.
    pub fn join_lines_at(&mut self, line: usize) {
        assert!(line >= 1, "Tried to move first line to the -1 line!");
        let s = self.lines.remove(line);
        self.lines[line - 1].push_str(&s);
    }
    /// Deletes the character at `line`, `column`.
    pub fn delete_char_at(&mut self, line: usize, column: usize) {
        self.lines[line].remove(column);
    }
}
<|endoftext|>


<commit_before>/// mush graph backend and abstraction to swap out with custom backend

use uuid::Uuid;
use std::collections::{HashMap,HashSet,VecDeque};

/// unidirectional edge, use two edges for bidirectional/undirected graph
/*
struct GraphEdge {
    to: Uuid,
    maybe_weight: Option<f64>,
}
impl GraphEdge {
    // this should be private, this should be called by a graph method
    fn new (uuid: Uuid, weight: Option<f64>) -> GraphEdge {
        GraphEdge { to: uuid,
                    maybe_weight:weight }
    }
    pub fn get_directed (&self) -> &Uuid {
        &self.to
    }
    pub fn get_weight (&self) -> Option<f64> {
        self.maybe_weight
    }
}*/

#[derive(Debug)]
struct GraphNode {
    uuid: Uuid,
    edges: HashMap<Uuid,Option<f64>>, //to,weight
}
impl GraphNode {
    fn new (uuid: Uuid) -> GraphNode {
        GraphNode { uuid: uuid,
                    edges: HashMap::new() }
    }
    /// direct the node towards another node
    // todo: rename me! sounds too similar to unidirectional
    fn direct (&mut self, to:&Uuid, weight: Option<f64>) -> bool {
        self.edges.insert(*to,weight).is_some()
    }
    fn undirect (&mut self, to:&Uuid) -> bool {
        self.edges.remove(to).is_some()
    }
}

//----

pub struct Graph {
    nodes: HashMap<Uuid,GraphNode>,

    // todo: as traits
    is_weighted: bool,
    is_directed: bool,
}
impl Graph {
    pub fn default() -> Graph {
        Graph { nodes: HashMap::new(),
                is_weighted: false,
                is_directed: true, }
    }

    /// manual accessors
    fn get_mut(&mut self, uuid: &Uuid) -> Option<&mut GraphNode> {
        self.nodes.get_mut(uuid)
    }
    fn get(&self, uuid: &Uuid) -> Option<&GraphNode> {
        self.nodes.get(uuid)
    }

    pub fn add (&mut self) -> Uuid { //todo: maybe_edges fn arg
        let uuid = Uuid::new_v4();
        let n = GraphNode::new(uuid);
        self.nodes.insert(uuid,n);
        uuid
    }
    pub fn remove(&mut self, node: &Uuid) { //-> Option<GraphNode> {
        self.nodes.remove(node);
    }

    pub fn direct(&mut self, from: &Uuid, to: &Uuid) -> bool {
        let mut r = false;
        if let Some(f) = self.nodes.get_mut(from) {
            r = f.direct(to,None);
        }

        if self.is_directed { return r }
        else if r {
            if let Some(t) = self.nodes.get_mut(to) {
                r = t.direct(from,None);
            }
        }

        return r
    }
    pub fn undirect(&mut self, from: &Uuid, to: &Uuid) -> bool {
        let mut r = false;
        if let Some(f) = self.nodes.get_mut(from) {
            r = f.undirect(to);
        }

        if self.is_directed { return r }
        else if r {
            if let Some(t) = self.nodes.get_mut(to) {
                r = t.undirect(from);
            }
        }

        return r
    }

    // search functions
    // todo: consider weights between nodes to direct search, cycle-detection
    pub fn get_path(&self, s: GraphSearch) -> Option<Vec<Uuid>> {
        let mut visited: HashSet<Uuid> = HashSet::new();
        let mut result = vec!();

        match s {
            GraphSearch::Depth(from,to) => {
                let mut stack = vec!();

                stack.push(from);
                visited.insert(from);
                result.push(from);

                let mut cursor = Some(from);

                while cursor.is_some() {
                    if let Some(ref node) = self.get(&cursor.unwrap()) {
                        //get first unvisited node
                        let not_visited = node.edges.iter().find(|&(&n,v)| !visited.contains(&n));

                        if let Some((&n,w)) = not_visited {
                            stack.push(n);
                            visited.insert(n);
                            result.push(n);

                            if let Some(to_node) = to {
                                if n == to_node { break; }
                            }

                            cursor = Some(n);
                        }
                        else { cursor = stack.pop(); }
                    }
                    else { cursor = stack.pop(); }
                }

                if let Some(to_node) = to {
                    if result.contains(&to_node) {
                        return Some(result)
                    }
                }

                return None
            },
            GraphSearch::Breadth(from,to) => { // breadth first search, uses a queue
                let mut queue = VecDeque::new();

                queue.push_back(from);
                visited.insert(from);
                result.push(from);

                let mut cursor = Some(from);

                while cursor.is_some() {
                    if let Some(ref node) = self.get(&cursor.unwrap()) {
                        //get unvisted nodes to queue up
                        let not_visited: Vec<Option<(Uuid,Option<f64>)>> = node.edges.iter().map(|(&n,&v)| {
                            if !visited.contains(&n) {
                                Some((n,v))
                            }
                            else { None }
                        }).collect();

                        for maybe_node in not_visited {
                            if let Some((n,w)) = maybe_node {
                                queue.push_back(n);
                                visited.insert(n);
                                result.push(n);

                                if let Some(to_node) = to {
                                    if n == to_node { break; }
                                }

                                cursor = Some(n);
                            }
                        }

                        cursor = queue.pop_front();
                    }
                    else { cursor = queue.pop_front(); }
                }

                if let Some(to_node) = to {
                    if result.contains(&to_node) {
                        return Some(result)
                    }
                }

                return None
            },
            _ => None, // todo: djk algo
        }

    }

    //this is virtually the same as get_path dfs, should abstract dfs somehow to use it for this
    pub fn get_cycle(&self, from: Uuid, to: Option<Uuid>) -> Option<Uuid> { //Option<Vec<Uuid>> {
        let mut stack = vec!();
        let mut visited: HashSet<Uuid> = HashSet::new();

        stack.push(from);
        visited.insert(from);

        let mut cursor = Some(from);

        while cursor.is_some() {
            if let Some(ref node) = self.get(&cursor.unwrap()) {
                //get first unvisited node
                let not_visited = node.edges.iter().find(|&(&n,v)| !visited.contains(&n));

                if let Some(cycle) = node.edges.iter().find(|&(&n,v)| stack.contains(&n)) {
                    return Some(*cycle.0);
                    // should consider returning stack
                }

                if let Some((&n,w)) = not_visited {
                    stack.push(n);
                    visited.insert(n);

                    if let Some(to_node) = to {
                        if n == to_node { break; }
                    }

                    cursor = Some(n);
                }
                else { cursor = stack.pop(); }
            }
            else { cursor = stack.pop(); }
        }

        return None
    }

    /// get immediate next node from list of connected nodes for the current node
    pub fn get_next(&self, from: &Uuid) -> Option<Uuid> {
        if let Some(n) = self.nodes.get(from) {
            if let Some(next_id) = n.edges.iter().next() {
                return Some(*next_id.0) // grab uuid key
            }
        }

        return None

    }

    fn is_connected() -> bool { false }
    fn is_complete() -> bool { false }

    fn get_path_shortest(&self) -> bool {
        if !self.is_weighted { false } //must be weighted
        else { false } //todo: use bfs
    }
}

// todo: impl as trait instead?
pub enum GraphSearch {
    Depth(Uuid,Option<Uuid>), // used on part of graph for reachability, and all of graph for cycle-detection
    Breadth(Uuid,Option<Uuid>), // used on part of graph for reachability, and (unweighted) for shortest path
    Dijkstra(Uuid,Uuid), // used on part of graph (weighted) for shortest path
}

pub struct GraphBuilder(Graph);

impl GraphBuilder {
    pub fn new() -> GraphBuilder {
        GraphBuilder(Graph::default())
    }

    pub fn directed(mut self, d: bool) -> GraphBuilder {
        self.0.is_directed = d;
        self
    }
    pub fn weighted(mut self, w: bool) -> GraphBuilder {
        self.0.is_weighted = w;
        self
    }
    pub fn build(mut self) -> Graph {
        self.0
    }
}

// ----
// tests
// ----
#[cfg(test)]
mod tests {
    extern crate test;

    use ::{Graph,GraphSearch};

    #[test]
    fn test_basic() {
        let mut graph = Graph::default();
        let mut nodes = vec!();
        for i in 0..5 {
            nodes.push(graph.add());
        }

        graph.direct(&nodes[0],&nodes[1]);

        graph.direct(&nodes[3],&nodes[0]);
        graph.direct(&nodes[4],&nodes[3]);

        let r = graph.get_path(GraphSearch::Depth(nodes[0],Some(nodes[4])));
        assert!(!r.is_some());

        let r = graph.get_path(GraphSearch::Depth(nodes[4],Some(nodes[0])));
        assert!(r.is_some());

        {let r = graph.get_cycle(nodes[4],Some(nodes[1]));
         assert!(!r.is_some());}

        let n2 = graph.add();
        graph.direct(&n2,&nodes[3]);
        graph.direct(&nodes[0],&n2);

        let r = graph.get_cycle(nodes[4],Some(nodes[1]));
        assert!(r.is_some());
    }

}
<commit_msg>fixed get_cycle, bug, need to fix path<commit_after>/// mush graph backend and abstraction to swap out with custom backend

use uuid::Uuid;
use std::collections::{HashMap,HashSet,VecDeque};

/// unidirectional edge, use two edges for bidirectional/undirected graph
//#[derive(Hash, Eq, PartialEq, Debug)]
#[derive(Debug)]
struct GraphEdge<K> {
    to: Uuid,
    maybe_weight: Option<f64>,
    maybe_custom: Option<K>,
}
impl<K> GraphEdge<K> {
    // this should be private, this should be called by a graph method
    fn new (uuid: Uuid, weight: Option<f64>, custom: Option<K>) -> GraphEdge<K> {
        GraphEdge { to: uuid,
                    maybe_weight:weight,
                    maybe_custom: custom }
    }
    pub fn get_directed (&self) -> &Uuid {
        &self.to
    }

    pub fn get_weight (&self) -> Option<&f64> {
        if let Some(ref w) = self.maybe_weight { Some(w) }
        else { None }
    }
    pub fn get_weight_mut (&mut self) -> Option<&mut f64> {
        if let Some(ref mut w) = self.maybe_weight { Some(w) }
        else { None }
    }

    pub fn get_custom (&self) -> Option<&K> {
        if let Some(ref k) = self.maybe_custom { Some(k) }
        else { None }
    }
    pub fn get_custom_mut (&mut self) -> Option<&mut K> {
        if let Some(ref mut k) = self.maybe_custom { Some(k) }
        else { None }
    }
}

//--

#[derive(Debug)]
struct GraphNode {
    uuid: Uuid,
    edges_to: HashMap<Uuid,Option<f64>>, //to,weight //todo: turn to hashset if using graphedge struct
    edges_from: HashMap<Uuid,Option<f64>>,
}
impl GraphNode {
    fn new (uuid: Uuid) -> GraphNode {
        GraphNode { uuid: uuid,
                    edges_to: HashMap::new(),
                    edges_from: HashMap::new(), }
    }
    /// direct the node towards another node
    // todo: rename me! sounds too similar to unidirectional
    fn direct (&mut self, to:&Uuid, weight: Option<f64>) {
        self.edges_to.insert(*to,weight);
    }
    fn undirect (&mut self, to:&Uuid) {
        self.edges_to.remove(to);
    }
}

//----
#[derive(Debug)]
pub struct Graph {
    nodes: HashMap<Uuid,GraphNode>,

    // todo: as traits
    is_weighted: bool,
    is_directed: bool,
    is_tracking: bool,  // tracking from-edges
}

//todo: turn many of these methods into a trait
impl Graph {
    pub fn default() -> Graph {
        Graph { nodes: HashMap::new(),
                is_weighted: false,
                is_directed: true,
                is_tracking: false, }
    }

    /// manual accessors
    fn get_node_mut(&mut self, uuid: &Uuid) -> Option<&mut GraphNode> {
        self.nodes.get_mut(uuid)
    }
    fn get_node(&self, uuid: &Uuid) -> Option<&GraphNode> {
        self.nodes.get(uuid)
    }

    pub fn add (&mut self) -> Uuid { //todo: maybe_edges fn arg
        let uuid = Uuid::new_v4();
        let n = GraphNode::new(uuid);
        self.nodes.insert(uuid,n);
        uuid
    }
    pub fn remove(&mut self, node: &Uuid) -> bool { //Option<GraphNode> {
        self.nodes.remove(node).is_some()
    }

    pub fn direct(&mut self, from: &Uuid, to: &Uuid) -> bool {
        let mut r = true;

        if !self.get_node(to).is_some() { return false } // todo: expand on this, and impl for undirect?

        if let Some(f) = self.nodes.get_mut(from) {
            f.direct(to,None);
        }
        else { r = false; }

        if self.is_directed { return r }
        else if r {
            if let Some(t) = self.nodes.get_mut(to) {
                t.direct(from,None);
            }
            else { r = false; }
        }

        return r
    }
    pub fn undirect(&mut self, from: &Uuid, to: &Uuid) -> bool {
        let mut r = true;
        if let Some(f) = self.nodes.get_mut(from) {
            f.undirect(to);
        }
        else { r = false; }

        if self.is_directed { return r }
        else if r {
            if let Some(t) = self.nodes.get_mut(to) {
                t.undirect(from);
            }
            else { r = false; }
        }

        return r
    }

    // search functions
    // todo: consider weights between nodes to direct search, cycle-detection
    pub fn get_path(&self, s: GraphSearch) -> Option<Vec<Uuid>> {
        let mut visited: HashSet<Uuid> = HashSet::new();
        let mut result = vec!();

        match s {
            GraphSearch::Depth(from,to) => {
                let mut stack = vec!();

                stack.push(from);
                visited.insert(from);
                result.push(from);

                let mut cursor = Some(from);

                while cursor.is_some() {
                    if let Some(ref node) = self.get_node(&cursor.unwrap()) {
                        //get first unvisited node
                        let not_visited = node.edges_to.iter().find(|&(&n,v)| !visited.contains(&n));

                        if let Some((&n,w)) = not_visited {
                            if !self.is_tracking || self.nodes.contains_key(&n) { //node exists?
                                stack.push(n);
                                visited.insert(n);
                                result.push(n);

                                if let Some(to_node) = to {
                                    if n == to_node { break; }
                                }

                                cursor = Some(n);
                            }
                        }
                        else { cursor = stack.pop(); }
                    }
                    else { cursor = stack.pop(); }
                }

                if let Some(to_node) = to {
                    if result.contains(&to_node) {
                        return Some(result)
                    }
                }

                return None
            },
            GraphSearch::Breadth(from,to) => { // breadth first search, uses a queue
                let mut queue = VecDeque::new();

                queue.push_back(from);
                visited.insert(from);
                result.push(from);

                let mut cursor = Some(from);

                while cursor.is_some() {
                    if let Some(ref node) = self.get_node(&cursor.unwrap()) {
                        //get unvisted nodes to queue up
                        let not_visited: Vec<Option<(Uuid,Option<f64>)>> = node.edges_to.iter().map(|(&n,&v)| {
                            if !visited.contains(&n) {
                                Some((n,v))
                            }
                            else { None }
                        }).collect();

                        for maybe_node in not_visited {
                            if let Some((n,w)) = maybe_node {
                                if !self.is_tracking || self.nodes.contains_key(&n) { //node exists?
                                    queue.push_back(n);
                                    visited.insert(n);
                                    result.push(n);

                                    if let Some(to_node) = to {
                                        if n == to_node { break; }
                                    }

                                    cursor = Some(n);
                                }
                            }
                        }

                        cursor = queue.pop_front();
                    }
                    else { cursor = queue.pop_front(); }
                }

                if let Some(to_node) = to {
                    if result.contains(&to_node) {
                        return Some(result)
                    }
                }

                return None
            },
            _ => None, // todo: djk algo
        }

    }

    //this is virtually the same as get_path dfs, should abstract dfs somehow to use it for this
    pub fn get_cycle(&self, from: Uuid) -> HashSet<(Uuid,Uuid)> {
        let mut stack = vec!();
        let mut visited: HashSet<Uuid> = HashSet::new();
        let mut r = HashSet::new(); //Vec::new();

        stack.push(from);

        while stack.len() > 0 {
            let cursor = *stack.last().unwrap();
            visited.insert(cursor);

            if let Some(ref node) = self.get_node(&cursor) {

                //does the cursor point to a node on stack
                for (n,_) in node.edges_to.iter() {
                    if stack.contains(&n) {
                        r.insert((*n,cursor));
                    }
                }

                //get first unvisited node
                let not_visited = node.edges_to.iter().find(|&(n,_)| !visited.contains(n));

                if let Some((&n,_)) = not_visited {
                    if !stack.contains(&n) {
                        stack.push(n); //add node to check
                    }
                }
                else { stack.pop(); } //nothing left, pop off and head back a node
            }
            else { stack.pop(); } //invalid node?
        }

        return r
    }

    /// get immediate next node from list of connected nodes for the current node
    pub fn get_next(&self, from: &Uuid) -> Option<Uuid> {
        if let Some(n) = self.nodes.get(from) {
            if let Some(next_id) = n.edges_to.iter().next() {
                return Some(*next_id.0) // grab uuid key
            }
        }

        return None

    }

    fn is_connected() -> bool { false }
    fn is_complete() -> bool { false }

    fn get_path_shortest(&self) -> bool {
        if !self.is_weighted { false } //must be weighted
        else { false } //todo: use bfs
    }
}

// todo: impl as trait instead?
pub enum GraphSearch {
    Depth(Uuid,Option<Uuid>), // used on part of graph for reachability, and all of graph for cycle-detection
    Breadth(Uuid,Option<Uuid>), // used on part of graph for reachability, and (unweighted) for shortest path
    Dijkstra(Uuid,Uuid), // used on part of graph (weighted) for shortest path
}

pub struct GraphBuilder(Graph);

impl GraphBuilder {
    pub fn new() -> GraphBuilder {
        GraphBuilder(Graph::default())
    }

    pub fn directed(mut self, d: bool) -> GraphBuilder {
        self.0.is_directed = d;
        self
    }
    pub fn weighted(mut self, w: bool) -> GraphBuilder {
        self.0.is_weighted = w;
        self
    }
    pub fn track_from_nodes(mut self, t: bool) -> GraphBuilder {
        self.0.is_tracking = t;
        self
    }
    pub fn build(mut self) -> Graph {
        self.0
    }
}

// ----
// tests
// ----
#[cfg(test)]
mod tests {
    extern crate test;

    use ::{Graph,GraphSearch};

    use uuid::Uuid;
    use std::collections::{HashMap};

    #[test]
    fn test_basic_direct() {
        let mut graph = Graph::default();
        let mut nodes = vec!();
        for _ in 0..5 {
            nodes.push(graph.add());
        }

        assert!(graph.direct(&nodes[0],&nodes[1]));

        assert!(graph.direct(&nodes[3],&nodes[0]));
        assert!(graph.direct(&nodes[4],&nodes[3]));

        graph.remove(&nodes[2]);
        assert!(!graph.direct(&nodes[4],&nodes[2]));

        let n6 = graph.add();
        assert!(graph.direct(&n6,&nodes[3]));
        assert!(graph.direct(&nodes[0],&n6));
    }

    #[test]
    fn test_basic_paths() {
        let mut graph = Graph::default();
        let mut nodes = vec!();
        for _ in 0..5 {
            nodes.push(graph.add());
        }

        graph.direct(&nodes[0],&nodes[1]);

        graph.direct(&nodes[3],&nodes[0]);
        graph.direct(&nodes[4],&nodes[3]);

        graph.remove(&nodes[2]);

        let r = graph.get_path(GraphSearch::Depth(nodes[0],Some(nodes[4])));
        assert!(!r.is_some());

        let r = graph.get_path(GraphSearch::Depth(nodes[4],Some(nodes[0])));
        assert!(r.is_some());

        let r = graph.get_path(GraphSearch::Breadth(nodes[4],Some(nodes[0])));
        assert!(r.is_some());
    }

    #[test]
    fn test_basic_cycle() {
        let mut graph = Graph::default();
        let mut nodes = vec!();
        for _ in 0..5 {
            nodes.push(graph.add());
        }

        graph.direct(&nodes[0],&nodes[1]);

        graph.direct(&nodes[3],&nodes[0]);
        graph.direct(&nodes[4],&nodes[3]);

        graph.remove(&nodes[2]);

        let r = graph.get_cycle(nodes[4]);
        assert_eq!(r.len(),0);

        let n6 = graph.add();
        graph.direct(&n6,&nodes[3]);
        graph.direct(&nodes[0],&n6);

        let n7 = graph.add();
        graph.direct(&n7,&nodes[3]);
        graph.direct(&nodes[0],&n7);

        let r = graph.get_cycle(nodes[4]);
        println!("{:?}",r);
        assert_eq!(r.len(),2);
    }
}
<|endoftext|>


<commit_before>//! A TCP socket implementation of Hamelin.
#![feature(env, io)]
extern crate hamelin;
extern crate mio;

use std::collections::HashMap;
use std::env::args;
use std::old_io::IoErrorKind::TimedOut;
use hamelin::{BufferedAsyncStream, Hamelin, HamelinGuard};
use mio::{EventLoop, Handler, IoAcceptor, NonBlock, Token};
use mio::event::{Interest, PollOpt, ReadHint};
use mio::net::{SockAddr};
use mio::net::tcp::{TcpSocket, TcpAcceptor};

const SERVER: Token = Token(0);

struct Client {
    stream: BufferedAsyncStream<TcpSocket>,
    guard: HamelinGuard,
}

impl Client {
    fn new(sock: TcpSocket, guard: HamelinGuard) -> Client {
        Client {
            stream: BufferedAsyncStream::new(sock),
            guard: guard
        }
    }

    fn wait(&mut self) -> Result<(), ()> {
        self.guard.wait().map_err(|_| ())
    }

    fn read(&mut self) -> Result<(), ()> {
        match self.stream.read_line() {
            Ok(line) => match self.guard.write_line(&line) {
                Ok(_) => Ok(()),
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }

    fn write(&mut self) -> Result<(), ()> {
        match self.guard.read_line() {
            Ok(line) => match self.stream.write_line(&line) {
                Ok(_) => {
                    println!("Wrote: {}", line);
                    Ok(())
                },
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }
}

struct HamelinHandler {
    server: TcpAcceptor,
    hamelin: Hamelin,
    token_index: usize,
    clients: HashMap<usize, Client>,
}

impl HamelinHandler {
    fn new(server: TcpAcceptor, hamelin: Hamelin) -> HamelinHandler {
        HamelinHandler {
            server: server,
            hamelin: hamelin,
            token_index: 1,
            clients: HashMap::new(),
        }
    }

    fn accept(&mut self, eloop: &mut EventLoop<(), ()>) {
        if let NonBlock::Ready(client) = self.server.accept().unwrap() {
            let token = mio::Token(self.token_index);
            self.token_index += 1;
            eloop.register_opt(&client, token, Interest::all(), PollOpt::level())
                 .ok().expect("Failed to accept new client.");
            self.clients.insert(
                token.as_usize(), Client::new(client, self.hamelin.spawn().unwrap())
            );
            println!("Client connected.");
        }
    }

    fn read(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.read();
        res
    }

    fn write(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.write();
        res
    }
}

impl Handler<(), ()> for HamelinHandler {
    fn readable(&mut self, eloop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
        match token {
            SERVER => self.accept(eloop),
            Token(x) => {
                if let Err(_) = self.read(x) {
                    eloop.deregister(&self.clients[x].stream.stream).unwrap();
                    let _ = self.clients[x].wait();
                    self.clients.remove(&x);
                }
            },
        }
    }

    fn writable(&mut self, _: &mut EventLoop<(), ()>, token: Token) {
        match token {
            SERVER => (),
            Token(x) => {
                let _ = self.write(x);
            }
        }
    }
}

fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let addr = SockAddr::parse(&format!("{}:{}", if args[0] == "localhost" { "127.0.0.1" } else
                                        { &args[0][] }, args[1])).unwrap();
    let server = TcpSocket::v4().unwrap()
                    .bind(&addr).unwrap()
                    .listen(256).unwrap();
    println!("Server bound on {:?}.", addr);
    let mut eloop = EventLoop::<(), ()>::new().unwrap();
    eloop.register(&server, SERVER).unwrap();
    eloop.run(HamelinHandler::new(server, hamelin)).ok().expect("Failed to execute event loop.");
}
<commit_msg>Removed debugging println.<commit_after>//! A TCP socket implementation of Hamelin.
#![feature(env, io)]
extern crate hamelin;
extern crate mio;

use std::collections::HashMap;
use std::env::args;
use std::old_io::IoErrorKind::TimedOut;
use hamelin::{BufferedAsyncStream, Hamelin, HamelinGuard};
use mio::{EventLoop, Handler, IoAcceptor, NonBlock, Token};
use mio::event::{Interest, PollOpt, ReadHint};
use mio::net::{SockAddr};
use mio::net::tcp::{TcpSocket, TcpAcceptor};

const SERVER: Token = Token(0);

struct Client {
    stream: BufferedAsyncStream<TcpSocket>,
    guard: HamelinGuard,
}

impl Client {
    fn new(sock: TcpSocket, guard: HamelinGuard) -> Client {
        Client {
            stream: BufferedAsyncStream::new(sock),
            guard: guard
        }
    }

    fn wait(&mut self) -> Result<(), ()> {
        self.guard.wait().map_err(|_| ())
    }

    fn read(&mut self) -> Result<(), ()> {
        match self.stream.read_line() {
            Ok(line) => match self.guard.write_line(&line) {
                Ok(_) => Ok(()),
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }

    fn write(&mut self) -> Result<(), ()> {
        match self.guard.read_line() {
            Ok(line) => match self.stream.write_line(&line) {
                Ok(_) => {
                    Ok(())
                },
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }
}

struct HamelinHandler {
    server: TcpAcceptor,
    hamelin: Hamelin,
    token_index: usize,
    clients: HashMap<usize, Client>,
}

impl HamelinHandler {
    fn new(server: TcpAcceptor, hamelin: Hamelin) -> HamelinHandler {
        HamelinHandler {
            server: server,
            hamelin: hamelin,
            token_index: 1,
            clients: HashMap::new(),
        }
    }

    fn accept(&mut self, eloop: &mut EventLoop<(), ()>) {
        if let NonBlock::Ready(client) = self.server.accept().unwrap() {
            let token = mio::Token(self.token_index);
            self.token_index += 1;
            eloop.register_opt(&client, token, Interest::all(), PollOpt::level())
                 .ok().expect("Failed to accept new client.");
            self.clients.insert(
                token.as_usize(), Client::new(client, self.hamelin.spawn().unwrap())
            );
            println!("Client connected.");
        }
    }

    fn read(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.read();
        res
    }

    fn write(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.write();
        res
    }
}

impl Handler<(), ()> for HamelinHandler {
    fn readable(&mut self, eloop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
        match token {
            SERVER => self.accept(eloop),
            Token(x) => {
                if let Err(_) = self.read(x) {
                    eloop.deregister(&self.clients[x].stream.stream).unwrap();
                    let _ = self.clients[x].wait();
                    self.clients.remove(&x);
                }
            },
        }
    }

    fn writable(&mut self, _: &mut EventLoop<(), ()>, token: Token) {
        match token {
            SERVER => (),
            Token(x) => {
                let _ = self.write(x);
            }
        }
    }
}

fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let addr = SockAddr::parse(&format!("{}:{}", if args[0] == "localhost" { "127.0.0.1" } else
                                        { &args[0][] }, args[1])).unwrap();
    let server = TcpSocket::v4().unwrap()
                    .bind(&addr).unwrap()
                    .listen(256).unwrap();
    println!("Server bound on {:?}.", addr);
    let mut eloop = EventLoop::<(), ()>::new().unwrap();
    eloop.register(&server, SERVER).unwrap();
    eloop.run(HamelinHandler::new(server, hamelin)).ok().expect("Failed to execute event loop.");
}
<|endoftext|>


<commit_before>// Copyright 2013 The color-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Color channel conversions and utility methods

use std;

fn cast<T: std::num::NumCast, U: std::num::NumCast>(n: T) -> U {
    std::num::cast(n).unwrap()
}

pub trait Channel: Copy + Primitive {
    fn from<T:Channel>(chan: T) -> Self;
    fn to_channel<T:Channel>(self) -> T { Channel::from(self) }
    fn to_channel_u8(self)  -> u8;
    fn to_channel_u16(self) -> u16;
    fn to_channel_f32(self) -> f32;
    fn to_channel_f64(self) -> f64;

    fn invert_channel(self) -> Self;

    fn clamp(self, lo: Self, hi: Self) -> Self {
        if self < lo {
            lo
        } else if self > hi {
            hi
        } else {
            self
        }
    }
    fn max(self, other: Self) -> Self {
        self.max(other)
    }
    fn min(self, other: Self) -> Self {
        self.min(other)
    }
}

impl Channel for u8 {
    #[inline] fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inline] fn to_channel_u8(self)  -> u8  { self }
    #[inline] fn to_channel_u16(self) -> u16 { (self as u16 << 8) | self as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { (self as f32) / (0xFF as f32) }
    #[inline] fn to_channel_f64(self) -> f64 { (self as f64) / (0xFF as f64) }

    #[inline] fn invert_channel(self) -> u8 { !self }
}

impl Channel for u16 {
    #[inline] fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self >> 8) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { self }
    #[inline] fn to_channel_f32(self) -> f32 { (self / 0xFFFF) as f32 }
    #[inline] fn to_channel_f64(self) -> f64 { (self / 0xFFFF) as f64 }

    #[inline] fn invert_channel(self) -> u16 { !self }
}

impl Channel for f32 {
    #[inline] fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self * (0xFF as f32)) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF as f32)) as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { self }
    #[inline] fn to_channel_f64(self) -> f64 { self as f64 }

    #[inline] fn invert_channel(self) -> f32 { 1.0 - self }
}

impl Channel for f64 {
    #[inline] fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self * (0xFF as f64)) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF as f64)) as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { self as f32 }
    #[inline] fn to_channel_f64(self) -> f64 { self }

    #[inline] fn invert_channel(self) -> f64 { 1.0 - self }
}

pub trait FloatChannel: Float + Channel {
    #[inline]
    fn normalize_channel(self) -> Self {
        self.clamp(cast(0.0), cast(1.0))
    }

    #[inline]
    fn normalize_degrees(self) -> Self {
        if (self) < cast(0.0) {
            (self + cast(360.0)) % cast(360.0)
        } else {
            self % cast(360.0)
        }
    }

    #[inline]
    fn invert_degrees(self) -> Self {
        (self + cast(180.0)).normalize_degrees()
    }
}

impl FloatChannel for f32 {}
impl FloatChannel for f64 {}

#[cfg(test)]
mod tests {
    use super::{Channel, FloatChannel};

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<commit_msg>channel: fix infinite recursion<commit_after>// Copyright 2013 The color-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Color channel conversions and utility methods

use std;

fn cast<T: std::num::NumCast, U: std::num::NumCast>(n: T) -> U {
    std::num::cast(n).unwrap()
}

// these are WRONG in general but fine for the primitives

fn max<T: PartialOrd>(a: T, b: T) -> T {
    if a.lt(&b) {
        b
    } else {
        a
    }
}

fn min<T: PartialOrd>(a: T, b: T) -> T {
    if a.lt(&b) {
        a
    } else {
        b
    }
}

pub trait Channel: Copy + Primitive {
    fn from<T:Channel>(chan: T) -> Self;
    fn to_channel<T:Channel>(self) -> T { Channel::from(self) }
    fn to_channel_u8(self)  -> u8;
    fn to_channel_u16(self) -> u16;
    fn to_channel_f32(self) -> f32;
    fn to_channel_f64(self) -> f64;

    fn invert_channel(self) -> Self;

    fn clamp(self, lo: Self, hi: Self) -> Self {
        if self < lo {
            lo
        } else if self > hi {
            hi
        } else {
            self
        }
    }
    fn max(self, other: Self) -> Self {
        max(self, other)
    }
    fn min(self, other: Self) -> Self {
        min(self, other)
    }
}

impl Channel for u8 {
    #[inline] fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inline] fn to_channel_u8(self)  -> u8  { self }
    #[inline] fn to_channel_u16(self) -> u16 { (self as u16 << 8) | self as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { (self as f32) / (0xFF as f32) }
    #[inline] fn to_channel_f64(self) -> f64 { (self as f64) / (0xFF as f64) }

    #[inline] fn invert_channel(self) -> u8 { !self }
}

impl Channel for u16 {
    #[inline] fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self >> 8) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { self }
    #[inline] fn to_channel_f32(self) -> f32 { (self / 0xFFFF) as f32 }
    #[inline] fn to_channel_f64(self) -> f64 { (self / 0xFFFF) as f64 }

    #[inline] fn invert_channel(self) -> u16 { !self }
}

impl Channel for f32 {
    #[inline] fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self * (0xFF as f32)) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF as f32)) as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { self }
    #[inline] fn to_channel_f64(self) -> f64 { self as f64 }

    #[inline] fn invert_channel(self) -> f32 { 1.0 - self }
}

impl Channel for f64 {
    #[inline] fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inline] fn to_channel_u8(self)  -> u8  { (self * (0xFF as f64)) as u8 }
    #[inline] fn to_channel_u16(self) -> u16 { (self * (0xFFFF as f64)) as u16 }
    #[inline] fn to_channel_f32(self) -> f32 { self as f32 }
    #[inline] fn to_channel_f64(self) -> f64 { self }

    #[inline] fn invert_channel(self) -> f64 { 1.0 - self }
}

pub trait FloatChannel: Float + Channel {
    #[inline]
    fn normalize_channel(self) -> Self {
        self.clamp(cast(0.0), cast(1.0))
    }

    #[inline]
    fn normalize_degrees(self) -> Self {
        if (self) < cast(0.0) {
            (self + cast(360.0)) % cast(360.0)
        } else {
            self % cast(360.0)
        }
    }

    #[inline]
    fn invert_degrees(self) -> Self {
        (self + cast(180.0)).normalize_degrees()
    }
}

impl FloatChannel for f32 {}
impl FloatChannel for f64 {}

#[cfg(test)]
mod tests {
    use super::{Channel, FloatChannel};

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<|endoftext|>