<commit_before>macro_rules! callback(
    (
        mod $mod_name:ident {
            $extfun:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun:ty ( $($args:expr),+ )
        }
    ) => (
        mod $mod_name {
            /**
             * A key for setting and retrieving the callback from
             * task-local storage
             */
            fn tls_key(_: @ $cbfun) {}
            _setter!(tls_key, $cbfun, $extfun)
            _extern_wrapper!(
                tls_key, ($($extarg_id : $extarg_ty),+) => $cbfun ($($args),+)
            )
        }
    );

    // Invoked there is a return type and fallback value supplied
    //
    // `$ext_ret_type`: The return type of the external callback wrapper
    // `$ret_val_if_none`: A fallback value to return if the external callback
    //                     wrapper function returned `None`
    (
        mod $mod_name:ident {
            $extfun:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun:ty ( $($args:expr),+ )
                    -> (Some: $ext_ret_type:ty | None: $ret_val_if_none:expr)
        }
    ) => (
        mod $mod_name {
            /**
             * A key for setting and retrieving the callback from
             * task-local storage
             */
            fn tls_key(_: @ $cbfun) {}
            _setter!(tls_key, $cbfun, $extfun)
            _extern_wrapper!(
                tls_key, ($($extarg_id : $extarg_ty),+) => $cbfun ($($args),+)
                        -> (Some: $ext_ret_type | None: $ret_val_if_none)
            )
        }
    )
)

// Generates a function that stores a callback in task local storage
macro_rules! _setter(
    ($tls_key:ident, $cbfun:ty, $extfun:ty) => (
        pub fn set(cbfun: $cbfun, f: &fn($extfun) ) {
            /*!
            Stores `cbfun` in task-local storage. `f` is called after storing
            `cbfun` has been stored. Eg.

            ~~~
            do callbacks::errorfun::set(cbfun) |ext| {
                unsafe { api::glfwSetErrorCallback(ext); }
            }
            ~~~
            */
            unsafe {
                task::local_data::local_data_set($tls_key, @cbfun);
                f(ext);
            }
        }
    )
)

// Generates an external function that fetches and calls a function from
// task local storage.
macro_rules! _extern_wrapper(
    (
        $tls_key:ident, ( $($extarg_id:ident : $extarg_ty:ty),+ )
            => $cbfun:ty ( $($args:expr),+ )
    ) => (
        extern fn ext( $( $extarg_id : $extarg_ty ),+ ) {
            unsafe {
                do task::local_data::local_data_get($tls_key).map |&f| {
                    (*f)( $($args),+ );
                }
            };
        }
    );

    // Invoked there is a return type and fallback value supplied
    //
    // `$ext_ret_type`: The return type of the external callback wrapper
    // `$ret_val_if_none`: A fallback value to return if the external callback
    //                     wrapper function returned `None`
    (
        $tls_key:ident, ( $($extarg_id:ident : $extarg_ty:ty),+ )
            => $cbfun:ty ( $($args:expr),+ )
                -> (Some: $ext_ret_type:ty | None: $ret_val_if_none:expr)
    ) => (
        extern fn ext( $( $extarg_id : $extarg_ty ),+ ) -> $ext_ret_type {
            unsafe {
                do task::local_data::local_data_get($tls_key)
                    .map_default($ret_val_if_none) |&f| {
                    (*f)( $($args),+ ) as $ext_ret_type
                }
            }
        }
    );
)

// Error Callback
pub callback!(
    mod errorfun {
        ::api::GLFWerrorfun(err: libc::c_int,
                            format: *libc::c_char)
            => ::ErrorFun(err, str::raw::from_c_str(format))
    }
)

// Monitor Callback
pub callback!(
    mod monitorfun {
        ::api::GLFWmonitorfun(monitor: *::api::GLFWmonitor,
                              event: libc::c_int)
            => ::MonitorFun(&::Monitor(monitor), event)
    }
)

// Window Position Callback
pub callback!(
    mod windowposfun {
        ::api::GLFWwindowposfun(window: *::api::GLFWwindow,
                                x: libc::c_int,
                                y: libc::c_int)
            => ::WindowPosFun(&::Window(window),
                               x as int, y as int)
    }
)

// Window Size Callback
pub callback!(
    mod windowsizefun {
        ::api::GLFWwindowsizefun(window: *::api::GLFWwindow,
                                 width: libc::c_int,
                                 height: libc::c_int)
            => ::WindowSizeFun(&::Window(window),
                               width as int, height as int)
    }
)

// Window Close Callback
pub callback!(
    mod windowclosefun {
        ::api::GLFWwindowclosefun(window: *::api::GLFWwindow)
            => ::WindowCloseFun(&::Window(window))
                -> (Some: libc::c_int | None: ::FALSE)
    }
)

// Window Refresh Callback
pub callback!(
    mod windowrefreshfun {
        ::api::GLFWwindowrefreshfun(window: *::api::GLFWwindow)
            => ::WindowRefreshFun(&::Window(window))
    }
)

// Window Focus Callback
pub callback!(
    mod windowfocusfun {
        ::api::GLFWwindowfocusfun(window: *::api::GLFWwindow,
                                  activated: libc::c_int)
            => ::WindowFocusFun(&::Window(window), activated as bool)
    }
)

// Window Iconify Callback
pub callback!(
    mod windowiconifyfun {
        ::api::GLFWwindowiconifyfun(window: *::api::GLFWwindow,
                                    iconified: libc::c_int)
            => ::WindowIconifyFun(&::Window(window), iconified as bool)
    }
)

// Key Callback
pub callback!(
    mod keyfun {
        ::api::GLFWkeyfun(window: *::api::GLFWwindow,
                          key: libc::c_int,
                          action: libc::c_int)
            => ::KeyFun(&::Window(window), key, action)
    }
)

// Character Callback
pub callback!(
    mod charfun {
        ::api::GLFWcharfun(window: *::api::GLFWwindow,
                           character: libc::c_uint)
            => ::CharFun(&::Window(window),
                         // TODO: tempory fix for the lack of a bounds check
                         // on X11 and Win32 in GLFW
                         if character == -1 { '0' }
                         else { character as char })
    }
)

// Mouse Button Callback
pub callback!(
    mod mousebuttonfun {
        ::api::GLFWmousebuttonfun(window: *::api::GLFWwindow,
                                  button: libc::c_int,
                                  action: libc::c_int)
            => ::MouseButtonFun(&::Window(window), button, action)
    }
)

// Cursor Position Callback
pub callback!(
    mod cursorposfun {
        ::api::GLFWcursorposfun(window: *::api::GLFWwindow,
                                x: libc::c_int, y: libc::c_int)
            => ::CursorPosFun(&::Window(window), x as int, y as int)
    }
)

// Cursor Enter Callback
pub callback!(
    mod cursorenterfun {
        ::api::GLFWcursorenterfun(window: *::api::GLFWwindow,
                                  entered: libc::c_int)
            => ::CursorEnterFun(&::Window(window), entered as bool)
    }
)

// Scroll Callback
pub callback!(
    mod scrollfun {
        ::api::GLFWscrollfun(window: *::api::GLFWwindow,
                             x: libc::c_double, y: libc::c_double)
            => ::ScrollFun(&::Window(window), x as f64, y as f64)
    }
)
<commit_msg>Refactor macros a little to make them easier to understand<commit_after>macro_rules! callback(
    (
        mod $mod_name:ident {
            $extfun_ty:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun_ty:ty ( $($args:expr),+ )
        }
    ) => (
        mod $mod_name {
            tls_key !(cbkey, $cbfun_ty)
            setter  !(cbkey, $cbfun_ty, $extfun_ty)
            extfun  !(cbkey, ($($extarg_id : $extarg_ty),+)
                => $cbfun_ty ($($args),+))
        }
    );

    // `$ext_ret_type`: The return type of the external callback wrapper
    // `$ret_val_if_none`: A fallback value to return if the external callback
    //                     wrapper function returned `None`
    (
        mod $mod_name:ident {
            $extfun_ty:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun_ty:ty ( $($args:expr),+ )
                    -> (Some: $ext_ret_type:ty | None: $ret_val_if_none:expr)
        }
    ) => (
        mod $mod_name {
            tls_key !(cbkey, $cbfun_ty)
            setter  !(cbkey, $cbfun_ty, $extfun_ty)
            extfun  !(cbkey, ($($extarg_id : $extarg_ty),+)
                => $cbfun_ty ($($args),+)
                    -> (Some: $ext_ret_type | None: $ret_val_if_none))
        }
    )
)

// Generates a key for setting and retrieving a value from task-local storage
macro_rules! tls_key(
    ($key:ident, $key_type:ty) => (
        fn $key(_: @$key_type) {}
    )
)

// Generates a function that stores a callback in task local storage
macro_rules! setter(
    ($cbkey:ident, $cbfun_ty:ty, $extfun_ty:ty) => (
        pub fn set(cbfun: $cbfun_ty, f: &fn($extfun_ty) ) {
            /*!
            Stores `cbfun` in task-local storage and then calls `f` with
            with an external callback wrapper as an argument. Eg.

            ~~~
            do callbacks::errorfun::set(cbfun) |ext| {
                unsafe { api::glfwSetErrorCallback(ext); }
            }
            ~~~
            */
            unsafe {
                task::local_data::local_data_set($cbkey, @cbfun);
                f(extfun);
            }
        }
    )
)

// Generates an external function that fetches and calls a function from
// task local storage.
macro_rules! extfun(
    (
        $cbkey:ident, ( $($extarg_id:ident : $extarg_ty:ty),+ )
            => $cbfun_ty:ty ( $($args:expr),+ )
    ) => (
        extern fn extfun( $( $extarg_id : $extarg_ty ),+ ) {
            unsafe {
                do task::local_data::local_data_get($cbkey).map |&f| {
                    (*f)( $($args),+ );
                }
            };
        }
    );

    // `$ext_ret_type`: The return type of the external callback wrapper
    // `$ret_val_if_none`: A fallback value to return if the external callback
    //                     wrapper function returned `None`
    (
        $cbkey:ident, ( $($extarg_id:ident : $extarg_ty:ty),+ )
            => $cbfun_ty:ty ( $($args:expr),+ )
                -> (Some: $ext_ret_type:ty | None: $ret_val_if_none:expr)
    ) => (
        extern fn extfun( $( $extarg_id : $extarg_ty ),+ ) -> $ext_ret_type {
            unsafe {
                do task::local_data::local_data_get($cbkey)
                    .map_default($ret_val_if_none) |&f| {
                    (*f)( $($args),+ ) as $ext_ret_type
                }
            }
        }
    );
)

// Error Callback
pub callback!(
    mod errorfun {
        ::api::GLFWerrorfun(err: libc::c_int,
                            format: *libc::c_char)
            => ::ErrorFun(err, str::raw::from_c_str(format))
    }
)

// Monitor Callback
pub callback!(
    mod monitorfun {
        ::api::GLFWmonitorfun(monitor: *::api::GLFWmonitor,
                              event: libc::c_int)
            => ::MonitorFun(&::Monitor(monitor), event)
    }
)

// Window Position Callback
pub callback!(
    mod windowposfun {
        ::api::GLFWwindowposfun(window: *::api::GLFWwindow,
                                x: libc::c_int,
                                y: libc::c_int)
            => ::WindowPosFun(&::Window(window),
                               x as int, y as int)
    }
)

// Window Size Callback
pub callback!(
    mod windowsizefun {
        ::api::GLFWwindowsizefun(window: *::api::GLFWwindow,
                                 width: libc::c_int,
                                 height: libc::c_int)
            => ::WindowSizeFun(&::Window(window),
                               width as int, height as int)
    }
)

// Window Close Callback
pub callback!(
    mod windowclosefun {
        ::api::GLFWwindowclosefun(window: *::api::GLFWwindow)
            => ::WindowCloseFun(&::Window(window))
                -> (Some: libc::c_int | None: ::FALSE)
    }
)

// Window Refresh Callback
pub callback!(
    mod windowrefreshfun {
        ::api::GLFWwindowrefreshfun(window: *::api::GLFWwindow)
            => ::WindowRefreshFun(&::Window(window))
    }
)

// Window Focus Callback
pub callback!(
    mod windowfocusfun {
        ::api::GLFWwindowfocusfun(window: *::api::GLFWwindow,
                                  activated: libc::c_int)
            => ::WindowFocusFun(&::Window(window), activated as bool)
    }
)

// Window Iconify Callback
pub callback!(
    mod windowiconifyfun {
        ::api::GLFWwindowiconifyfun(window: *::api::GLFWwindow,
                                    iconified: libc::c_int)
            => ::WindowIconifyFun(&::Window(window), iconified as bool)
    }
)

// Key Callback
pub callback!(
    mod keyfun {
        ::api::GLFWkeyfun(window: *::api::GLFWwindow,
                          key: libc::c_int,
                          action: libc::c_int)
            => ::KeyFun(&::Window(window), key, action)
    }
)

// Character Callback
pub callback!(
    mod charfun {
        ::api::GLFWcharfun(window: *::api::GLFWwindow,
                           character: libc::c_uint)
            => ::CharFun(&::Window(window),
                         // TODO: tempory fix for the lack of a bounds check
                         // on X11 and Win32 in GLFW
                         if character == -1 { '0' }
                         else { character as char })
    }
)

// Mouse Button Callback
pub callback!(
    mod mousebuttonfun {
        ::api::GLFWmousebuttonfun(window: *::api::GLFWwindow,
                                  button: libc::c_int,
                                  action: libc::c_int)
            => ::MouseButtonFun(&::Window(window), button, action)
    }
)

// Cursor Position Callback
pub callback!(
    mod cursorposfun {
        ::api::GLFWcursorposfun(window: *::api::GLFWwindow,
                                x: libc::c_int, y: libc::c_int)
            => ::CursorPosFun(&::Window(window), x as int, y as int)
    }
)

// Cursor Enter Callback
pub callback!(
    mod cursorenterfun {
        ::api::GLFWcursorenterfun(window: *::api::GLFWwindow,
                                  entered: libc::c_int)
            => ::CursorEnterFun(&::Window(window), entered as bool)
    }
)

// Scroll Callback
pub callback!(
    mod scrollfun {
        ::api::GLFWscrollfun(window: *::api::GLFWwindow,
                             x: libc::c_double, y: libc::c_double)
            => ::ScrollFun(&::Window(window), x as f64, y as f64)
    }
)
<|endoftext|>


<commit_before>mod card;
mod deck;
mod hand;

pub use self::deck::Deck;<commit_msg>Clean card mods of public use of Deck.<commit_after>mod card;
mod deck;
mod hand;<|endoftext|>


<commit_before>
use focus_char::FocusChar;
use fragments::Fragment;
use location::Location;
use location::Direction::{Bottom, BottomLeft, BottomRight, Left, Right, Top, TopLeft, TopRight};
use block::Block::{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y};
use point_block::PointBlock;
use fragments::{self, line, arc, open_circle, arrow_line, dashed_line};

pub trait EnhanceCircle {
    fn enhance_circle(&self) -> (Vec<Fragment>, Vec<Location>);
}

impl<'g> EnhanceCircle for FocusChar<'g> {

    fn enhance_circle(&self) -> (Vec<Fragment>, Vec<Location>) {
        let mut elm = vec![];
        let mut consumed = vec![];
        let a = &PointBlock::block(A);
        let _b = &PointBlock::block(B);
        let c = &PointBlock::block(C);
        let _d = &PointBlock::block(D);
        let e = &PointBlock::block(E);
        let _f = &PointBlock::block(F);
        let _g = &PointBlock::block(G);
        let _h = &PointBlock::block(H);
        let _i = &PointBlock::block(I);
        let _j = &PointBlock::block(J);
        let k = &PointBlock::block(K);
        let l = &PointBlock::block(L);
        let m = &PointBlock::block(M);
        let n = &PointBlock::block(N);
        let o = &PointBlock::block(O);
        let _p = &PointBlock::block(P);
        let _q = &PointBlock::block(Q);
        let _r = &PointBlock::block(R);
        let _s = &PointBlock::block(S);
        let _t = &PointBlock::block(T);
        let u = &PointBlock::block(U);
        let _v = &PointBlock::block(V);
        let w = &PointBlock::block(W);
        let _x = &PointBlock::block(X);
        let y = &PointBlock::block(Y);

        let this = || Location::this();
        let top = || Location::go(Top);
        let bottom = || Location::go(Bottom);
        let left = || Location::go(Left);
        let right = || Location::go(Right);
        let top_left = || Location::go(TopLeft);
        let top_right = || Location::go(TopRight);
        let bottom_left = || Location::go(BottomLeft);
        let bottom_right = || Location::go(BottomRight);

        let top2 = || Location::jump(Top,2);
        let bottom2 = || Location::jump(Bottom,2);
        let left2 = || Location::jump(Left,2);
        let right2 = || Location::jump(Right,2);
        let top_right2 = || top().go_right(2);
        let top_left2 = || top().go_left(2);
        let bottom_right2 = || bottom().go_right(2);
        let bottom_left2 = || bottom().go_left(2);

        let top3 = || Location::jump(Top,3);
        let bottom3 = || Location::jump(Bottom,3);
        let left3 = || Location::jump(Left,3);
        let right3 = || Location::jump(Right,3);
        let top_right3 = || top().go_right(3);
        let top_left3 = || top().go_left(3);
        let bottom_right3 = || bottom().go_right(3);
        let bottom_left3 = || bottom().go_left(3);

        //  circle 4
        //   _
        //  (_)
        //
        if self.is('_')
            && self.left().is('(') && self.right().is(')')
            && self.top().is('_'){
            elm.push(open_circle(m, 4));
            consumed.extend(vec![this(), left(), right(),top()]);
        }

        //  circle 6
        //   __
        //  (__)
        //
        if self.is('_')
            && self.left().is('(') && self.in_right(2).is(')')
            && self.top().is('_') && self.top_right().is('_')
            && self.right().is('_'){
            elm.push(open_circle(m, 6));
            consumed.extend(vec![this(), left(), right2(), top(), top_right(), right()]);
        }

        // circle 8
        //       .-.
        //      ( + )
        //       '-'
        if self.in_left(2).is('(')
            && self.in_right(2).is(')')
            && self.top().is('-')
            && self.bottom().is('-')
            && self.bottom_left().any("`'")
            && self.bottom_right().is('\'')
            && self.top_left().any(".,")
            && self.top_right().is('.'){
            elm.push(open_circle(m,8));
            consumed.extend(vec![left2(), right2(), top(), bottom(),
                bottom_left(), bottom_right(), top_left(), top_right()]);
        }
        // circle 10
        //      .--.
        //     ( +  )
        //      `--'
        if self.in_left(2).is('(')
            && self.in_right(3).is(')')
            && self.top_left().any(".,")
            && self.top().is('-')
            && self.top_right().is('-')
            && self.top_right().right().is('.')
            && self.bottom_left().any("`'")
            && self.bottom().is('-')
            && self.bottom_right().is('-')
            && self.bottom_right().right().is('\''){
            elm.push(open_circle(&this().o(),10));
            consumed.extend(vec![left2(), right3(), top_left(), top(), top_right(),
                top_right2(), bottom_left(), bottom(), bottom_right(), bottom_right2(),
            ]);
        }

        // Circle 12
        //        _
        //      .' '.
        //     (  +  )
        //      `._.'
        if self.in_left(3).is('(')
            && self.in_right(3).is(')')
            && self.in_top(2).is('_')
            && self.bottom().is('_')
            && self.top().in_left(2).any(",.")
            && self.top_left().is('\'')
            && self.top_right().any("`'")
            && self.top().in_right(2).is('.')
            && self.bottom().in_left(2).any("`'")
            && self.bottom_left().is('.')
            && self.bottom_right().any(".,")
            && self.bottom().in_right(2).is('\''){
                elm.push(open_circle(m, 12));
                consumed.extend(vec![
                        left3(), right3(), top2(), bottom(), top_left2(), top_left(), top_right(), top_right2(),
                        bottom_left2(), bottom_left(), bottom_right(), bottom_right2()
                ]);
        }
        //
        //        __
        //      ,'  `.
        //     (  +   )  14
        //      `.__,'
        //
        //        ___
        //      ,'   `.
        //     /   +   \  16
        //     \       /
        //      `.___,'
        //
        //        ____
        //      ,'    `.
        //     /   +    \  18
        //     \        /
        //      `.____,'
        //
        //        ____
        //      ,'    `.
        //     /        \
        //    (    +     )  20
        //     \        /
        //      `.____,'
        //
        //
        //        _____
        //      ,'     `.
        //     /         \
        //    (     +     )  22
        //     \         /
        //      `._____,'
        //
        //
        //        ______
        //      ,'      `.
        //     /          \
        //    |     +      | 24
        //    |            |
        //     \          /
        //      `.______,'
        //
        (elm, consumed)
    }
}

<commit_msg>Support for parts that are not only dash, but for generic characters that can connect K and O<commit_after>
use focus_char::FocusChar;
use fragments::Fragment;
use location::Location;
use location::Direction::{Bottom, BottomLeft, BottomRight, Left, Right, Top, TopLeft, TopRight};
use block::Block::{A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y};
use point_block::PointBlock;
use fragments::{self, line, arc, open_circle, arrow_line, dashed_line};
use properties::Can::{ConnectTo,Is,IsStrongAll};

pub trait EnhanceCircle {
    fn enhance_circle(&self) -> (Vec<Fragment>, Vec<Location>);
}

impl<'g> EnhanceCircle for FocusChar<'g> {

    fn enhance_circle(&self) -> (Vec<Fragment>, Vec<Location>) {
        let mut elm = vec![];
        let mut consumed = vec![];
        let a = &PointBlock::block(A);
        let _b = &PointBlock::block(B);
        let c = &PointBlock::block(C);
        let _d = &PointBlock::block(D);
        let e = &PointBlock::block(E);
        let _f = &PointBlock::block(F);
        let _g = &PointBlock::block(G);
        let _h = &PointBlock::block(H);
        let _i = &PointBlock::block(I);
        let _j = &PointBlock::block(J);
        let k = &PointBlock::block(K);
        let l = &PointBlock::block(L);
        let m = &PointBlock::block(M);
        let n = &PointBlock::block(N);
        let o = &PointBlock::block(O);
        let _p = &PointBlock::block(P);
        let _q = &PointBlock::block(Q);
        let _r = &PointBlock::block(R);
        let _s = &PointBlock::block(S);
        let _t = &PointBlock::block(T);
        let u = &PointBlock::block(U);
        let _v = &PointBlock::block(V);
        let w = &PointBlock::block(W);
        let _x = &PointBlock::block(X);
        let y = &PointBlock::block(Y);

        let this = || Location::this();
        let top = || Location::go(Top);
        let bottom = || Location::go(Bottom);
        let left = || Location::go(Left);
        let right = || Location::go(Right);
        let top_left = || Location::go(TopLeft);
        let top_right = || Location::go(TopRight);
        let bottom_left = || Location::go(BottomLeft);
        let bottom_right = || Location::go(BottomRight);

        let top2 = || Location::jump(Top,2);
        let bottom2 = || Location::jump(Bottom,2);
        let left2 = || Location::jump(Left,2);
        let right2 = || Location::jump(Right,2);
        let top_right2 = || top().go_right(2);
        let top_left2 = || top().go_left(2);
        let bottom_right2 = || bottom().go_right(2);
        let bottom_left2 = || bottom().go_left(2);

        let top3 = || Location::jump(Top,3);
        let bottom3 = || Location::jump(Bottom,3);
        let left3 = || Location::jump(Left,3);
        let right3 = || Location::jump(Right,3);
        let top_right3 = || top().go_right(3);
        let top_left3 = || top().go_left(3);
        let bottom_right3 = || bottom().go_right(3);
        let bottom_left3 = || bottom().go_left(3);

        //  circle 4
        //   _
        //  (_)
        //
        if self.is('_')
            && self.left().is('(') && self.right().is(')')
            && self.top().is('_'){
            elm.push(open_circle(m, 4));
            consumed.extend(vec![this(), left(), right(),top()]);
        }

        //  circle 6
        //   __
        //  (__)
        //
        if self.is('_')
            && self.left().is('(') && self.in_right(2).is(')')
            && self.top().is('_') && self.top_right().is('_')
            && self.right().is('_'){
            elm.push(open_circle(m, 6));
            consumed.extend(vec![this(), left(), right2(), top(), top_right(), right()]);
        }

        // circle 8
        //       .-.
        //      ( + )
        //       '-'
        if self.in_left(2).is('(')
            && self.in_right(2).is(')')
            && self.top().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.bottom().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.bottom_left().any("`'")
            && self.bottom_right().is('\'')
            && self.top_left().any(".,")
            && self.top_right().is('.'){
            elm.push(open_circle(m,8));
            consumed.extend(vec![left2(), right2(), top(), bottom(),
                bottom_left(), bottom_right(), top_left(), top_right()]);
        }
        // circle 10
        //      .--.
        //     ( +  )
        //      `--'
        if self.in_left(2).is('(')
            && self.in_right(3).is(')')
            && self.top_left().any(".,")
            && self.top().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.top_right().is('-')
            && self.top_right().right().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.bottom_left().any("`'")
            && self.bottom().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.bottom_right().is_satisfied(&IsStrongAll(vec![K,O]))
            && self.bottom_right().right().is('\''){
            elm.push(open_circle(&this().o(),10));
            consumed.extend(vec![left2(), right3(), top_left(), top(), top_right(),
                top_right2(), bottom_left(), bottom(), bottom_right(), bottom_right2(),
            ]);
        }

        // Circle 12
        //        _
        //      .' '.
        //     (  +  )
        //      `._.'
        if self.in_left(3).is('(')
            && self.in_right(3).is(')')
            && self.in_top(2).is('_')
            && self.bottom().is('_')
            && self.top().in_left(2).any(",.")
            && self.top_left().is('\'')
            && self.top_right().any("`'")
            && self.top().in_right(2).is('.')
            && self.bottom().in_left(2).any("`'")
            && self.bottom_left().is('.')
            && self.bottom_right().any(".,")
            && self.bottom().in_right(2).is('\''){
                elm.push(open_circle(m, 12));
                consumed.extend(vec![
                        left3(), right3(), top2(), bottom(), top_left2(), top_left(), top_right(), top_right2(),
                        bottom_left2(), bottom_left(), bottom_right(), bottom_right2()
                ]);
        }
        //
        //        __
        //      ,'  `.
        //     (  +   )  14
        //      `.__,'
        //
        //        ___
        //      ,'   `.
        //     /   +   \  16
        //     \       /
        //      `.___,'
        //
        //        ____
        //      ,'    `.
        //     /   +    \  18
        //     \        /
        //      `.____,'
        //
        //        ____
        //      ,'    `.
        //     /        \
        //    (    +     )  20
        //     \        /
        //      `.____,'
        //
        //
        //        _____
        //      ,'     `.
        //     /         \
        //    (     +     )  22
        //     \         /
        //      `._____,'
        //
        //
        //        ______
        //      ,'      `.
        //     /          \
        //    |     +      | 24
        //    |            |
        //     \          /
        //      `.______,'
        //
        (elm, consumed)
    }
}

<|endoftext|>


<commit_before>use crate::admin::dialoguer;
use cargo_registry_index::{Repository, RepositoryConfig};
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
use reqwest::blocking::Client;

use crate::config;

#[derive(clap::Parser, Debug)]
#[clap(
    name = "upload-index",
    about = "Upload index from git to S3 (http-based index)"
)]
pub struct Opts {
    /// Incremental commit. Any changed files made after this commit will be uploaded.
    incremental_commit: Option<String>,
}

pub fn run(opts: Opts) -> anyhow::Result<()> {
    let config = config::Base::from_environment();
    let uploader = config.uploader();
    let client = Client::new();

    println!("fetching git repo");
    let config = RepositoryConfig::from_environment();
    let repo = Repository::open(&config)?;
    repo.reset_head()?;
    println!("HEAD is at {}", repo.head_oid()?);

    let files = repo.get_files_modified_since(opts.incremental_commit.as_deref())?;
    println!("found {} files to upload", files.len());
    if !dialoguer::confirm("continue with upload?") {
        return Ok(());
    }

    let pb = ProgressBar::new(files.len() as u64);
    pb.set_style(ProgressStyle::default_bar().template("{bar:60} ({pos}/{len}, ETA {eta})"));

    for file in files.iter().progress_with(pb) {
        let crate_name = file.file_name().unwrap().to_str().unwrap();
        let path = repo.index_file(crate_name);
        if !path.exists() {
            continue;
        }

        let contents = std::fs::read_to_string(&path)?;
        uploader.upload_index(&client, crate_name, contents)?;
    }

    println!(
        "uploading completed; use `upload-index {}` for an incremental run",
        repo.head_oid()?
    );
    Ok(())
}
<commit_msg>indicatif: Adjust to new `ProgressStyle` API<commit_after>use crate::admin::dialoguer;
use cargo_registry_index::{Repository, RepositoryConfig};
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
use reqwest::blocking::Client;

use crate::config;

#[derive(clap::Parser, Debug)]
#[clap(
    name = "upload-index",
    about = "Upload index from git to S3 (http-based index)"
)]
pub struct Opts {
    /// Incremental commit. Any changed files made after this commit will be uploaded.
    incremental_commit: Option<String>,
}

pub fn run(opts: Opts) -> anyhow::Result<()> {
    let config = config::Base::from_environment();
    let uploader = config.uploader();
    let client = Client::new();

    println!("fetching git repo");
    let config = RepositoryConfig::from_environment();
    let repo = Repository::open(&config)?;
    repo.reset_head()?;
    println!("HEAD is at {}", repo.head_oid()?);

    let files = repo.get_files_modified_since(opts.incremental_commit.as_deref())?;
    println!("found {} files to upload", files.len());
    if !dialoguer::confirm("continue with upload?") {
        return Ok(());
    }

    let pb = ProgressBar::new(files.len() as u64);
    pb.set_style(ProgressStyle::with_template("{bar:60} ({pos}/{len}, ETA {eta})").unwrap());

    for file in files.iter().progress_with(pb) {
        let crate_name = file.file_name().unwrap().to_str().unwrap();
        let path = repo.index_file(crate_name);
        if !path.exists() {
            continue;
        }

        let contents = std::fs::read_to_string(&path)?;
        uploader.upload_index(&client, crate_name, contents)?;
    }

    println!(
        "uploading completed; use `upload-index {}` for an incremental run",
        repo.head_oid()?
    );
    Ok(())
}
<|endoftext|>


<commit_before>//! The `run-script` command.

use args;
use command_runner::CommandRunner;
#[cfg(test)]
use command_runner::TestCommandRunner;
use errors::*;
use project::{Project, PodOrService};

/// Included into project in order to run named scripts on one ore more services
pub trait CommandRunScript {
    /// Run a named script on all matching services
    fn run_script<CR>(&self, runner: &CR, act_on: &args::ActOn, script_name: &str) -> Result<()>
        where CR: CommandRunner;
}

impl CommandRunScript for Project {
    fn run_script<CR>(&self, runner: &CR, act_on: &args::ActOn, script_name: &str) -> Result<()>
        where CR: CommandRunner
    {
        for pod_or_service in act_on.pods_or_services(self) {
            match pod_or_service? {
                PodOrService::Pod(pod) => {
                    for service_name in pod.service_names() {
                        pod.run_script(runner, &self, &service_name, &script_name)?;
                    }
                }
                PodOrService::Service(pod, service_name) => {
                    pod.run_script(runner, &self, &service_name, &script_name)?;
                }
            }
        }
        Ok(())
    }
}

#[test]
fn runs_scripts_on_all_services() {
    use env_logger;
    let _ = env_logger::init();
    let proj = Project::from_example("rails_hello").unwrap();
    let runner = TestCommandRunner::new();
    proj.output().unwrap();

    proj.run_script(&runner, &args::ActOn::All, "routes").unwrap();
    assert_ran!(runner, {
        ["docker-compose",
         "-p",
         "railshello",
         "-f",
         proj.output_dir().join("pods").join("rake.yml"),
         "run",
         "rake",
         "rake",
         "routes"]
    });

    proj.remove_test_output().unwrap();
}
<commit_msg>Only run-script on pods that are enabled in current target<commit_after>//! The `run-script` command.

use args;
use command_runner::CommandRunner;
#[cfg(test)]
use command_runner::TestCommandRunner;
use errors::*;
use project::{Project, PodOrService};

/// Included into project in order to run named scripts on one ore more services
pub trait CommandRunScript {
    /// Run a named script on all matching services
    fn run_script<CR>(&self, runner: &CR, act_on: &args::ActOn, script_name: &str) -> Result<()>
        where CR: CommandRunner;
}

impl CommandRunScript for Project {
    fn run_script<CR>(&self, runner: &CR, act_on: &args::ActOn, script_name: &str) -> Result<()>
        where CR: CommandRunner
    {
        let target = self.current_target();

        for pod_or_service in act_on.pods_or_services(self) {
            match pod_or_service? {
                PodOrService::Pod(pod) => {

                    // Ignore any pods that aren't enabled in the current target
                    if pod.enabled_in(&target) {
                        for service_name in pod.service_names() {
                            pod.run_script(runner, &self, &service_name, &script_name)?;
                        }
                    }
                }
                PodOrService::Service(pod, service_name) => {

                    // Don't run this on any service whose pod isn't enabled in
                    // the current target
                    if pod.enabled_in(&target) {
                        pod.run_script(runner, &self, &service_name, &script_name)?;
                    }
                }
            }
        }
        Ok(())
    }
}

#[test]
fn runs_scripts_on_all_services() {
    use env_logger;
    let _ = env_logger::init();
    let proj = Project::from_example("rails_hello").unwrap();
    let runner = TestCommandRunner::new();
    proj.output().unwrap();

    proj.run_script(&runner, &args::ActOn::All, "routes").unwrap();
    assert_ran!(runner, {
        ["docker-compose",
         "-p",
         "railshello",
         "-f",
         proj.output_dir().join("pods").join("rake.yml"),
         "run",
         "rake",
         "rake",
         "routes"]
    });

    proj.remove_test_output().unwrap();
}
<|endoftext|>


<commit_before>// Dependency Graph Library in Rust

//! dglr is a Dependency Graph Library in Rust.
//! In short, you register elements and their dependencies, and then
//! ask for the dependencies of any element in an order that satisfies.
//!
//! Elements are simply &str strings.  You register them with
//! register_dependency() or register_dependencies().
//!
//! Dependenies are (currently) just a list of other elements that
//! the element in question depends on.  [In the future, we may add
//! boolean logic, but currently they are all AND-ed together].
//!
//! Then call get_ordered_dependencies_of() and the library does the
//! magic and returns an order which will work.  It is possible that
//! other orders also work, but the library's algorithm is
//! deterministic, so you'll always get the same particular one.

#![crate_id = "dglr#0.1"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#[phase(plugin, link)]

extern crate log;

use std::collections::hashmap::{HashMap,HashSet};

/// This is the dependency graph.  You can create it yourself, or
/// use the convenience methods of new(), register_dependency() and
/// register_dependencies() to build one up (that must be mutable).
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,Vec<String>>,
}

// Internal structure keeping state between recursive functions
struct WalkState {
    // The path we have currently walked
    curpath: HashSet<String>,
    // The output so far
    output: Vec<String>,
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The thing does not need
    /// to pre-exist, nor do the dependency elements.  But if the
    /// thing does pre-exist, the dependsOn will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                thing: &'a str,
                                dependsOn: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(dependsOn)],
            |_,v| { v.push(String::from_str(dependsOn)); }
            );
    }

    /// Add multiple dependencies of one thing to a DepGraph.  The
    /// thing does not need to pre-exist, nor do the dependency elements.
    /// But if the thing does pre-exist, the dependsOn will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  dependsOn: &'a[&'a str] )
    {
        let newvec: Vec<String> = dependsOn.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    /// This returns either a vector of elements (Strings) in the
    /// order which they must be resolved as dependencies of thing,
    /// or in the case where there is a dependency cycle, an error
    /// string returned.
    pub fn get_ordered_dependencies_of(&self, thing: &str)
        -> Result<Vec<String>,String>
    {
        let mut state = WalkState {
            curpath: HashSet::new(),
            output: Vec::new(),
        };

        debug!("Recursing for the first time, with {}",thing);
        if ! self.get_deps_of_recurse(&String::from_str(thing), &mut state)
        {
            return Err(format!("Circular dependency detected at {}",thing));
        }

        debug!("output is {}",state.output);
        Ok(state.output)
    }

    // Internal function, recursion for get_ordered_dependencies_of
    fn get_deps_of_recurse(&self, thing: &String, state: &mut WalkState)
        -> bool
    {
        // If we find thing, we have a circular dependency:
        if state.curpath.contains(thing) { return false; }

        state.curpath.insert(thing.clone());

        match self.dependencies.find(thing) {
            None => {
                debug!("{} has no dependencies",thing);
            },

            Some(deplist) => {
                debug!("Handling the dependencies of {}",thing);
                for n in deplist.iter() {
                    // If thing was not yet visited, recurse into it
                    if !state.output.contains(n) {

                        debug!("Recursing for {}",n);
                        if ! self.get_deps_of_recurse(n, state) {
                            return false;
                        }

                        debug!("Appending {} to output",n);
                        state.output.push(n.clone());
                    }
                }
            },
        }

        state.curpath.remove(thing);

        return true;
    }
}

#[test]
fn dglr_test() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    let deps = depgraph.get_ordered_dependencies_of("a").unwrap();
    debug!("Deps of a = {}",deps);
    assert!( deps == vec![String::from_str("d"),
                          String::from_str("b"),
                          String::from_str("f"),
                          String::from_str("e"),
                          String::from_str("n"),
                          String::from_str("m"),
                          String::from_str("j"),
                          String::from_str("l"),
                          String::from_str("k"),
                          String::from_str("i"),
                          String::from_str("h"),
                          String::from_str("g"),
                          String::from_str("c")] );

    let deps2 = depgraph.get_ordered_dependencies_of("i").unwrap();
    debug!("Deps of i = {}",deps2);
    assert!( deps2 == vec![String::from_str("j"),
                           String::from_str("l"),
                           String::from_str("n"),
                           String::from_str("m"),
                           String::from_str("k")] );

    depgraph.register_dependency("i","g");
    let deps3 = depgraph.get_ordered_dependencies_of("a");
    match deps3 {
        Ok(_) => fail!("Unexpected result!"),
        Err(e) => {
            debug!("Circular dependency was detected {}",e);
        }
    }
}
<commit_msg>MAJOR rewrite, iterator, caller must mark nodes satisfied as you go<commit_after>// Dependency Graph Library in Rust

//! dglr is a Dependency Graph Library in Rust.
//! In short, you register elements and their dependencies, and then
//! ask for the dependencies of any element in an order that satisfies.
//!
//! Elements are simply &str strings.  You register them with
//! register_dependency() or register_dependencies().
//!
//! Dependenies are (currently) just a list of other elements that
//! the element in question depends on.  [In the future, we may add
//! boolean logic, but currently they are all AND-ed together].
//!
//! Then call get_ordered_dependencies_of() and the library does the
//! magic and returns an order which will work.  It is possible that
//! other orders also work, but the library's algorithm is
//! deterministic, so you'll always get the same particular one.

#![crate_id = "dglr#0.1"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#[phase(plugin, link)]

extern crate log;

use std::collections::hashmap::{HashMap,HashSet};
use std::iter::{Iterator};
use std::task;

/// This is the dependency graph.  You can create it yourself, or
/// use the convenience methods of new(), register_dependency() and
/// register_dependencies() to build one up (that must be mutable).
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,Vec<String>>,

    // (private) target we are trying to satisfy
    target: Option<String>,

    // (private) elements already satisfied
    satisfied: HashSet<String>,

    // (private) current path, for cycle detection
    curpath: HashSet<String>,
}

pub struct DepGraphIterator<'a> {
    depgraph: &'a mut DepGraph
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            target: None,
            curpath: HashSet::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The thing does not need
    /// to pre-exist, nor do the dependency elements.  But if the
    /// thing does pre-exist, the dependsOn will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                thing: &'a str,
                                dependsOn: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(dependsOn)],
            |_,v| { v.push(String::from_str(dependsOn)); }
            );
    }

    /// Add multiple dependencies of one thing to a DepGraph.  The
    /// thing does not need to pre-exist, nor do the dependency elements.
    /// But if the thing does pre-exist, the dependsOn will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  dependsOn: &'a[&'a str] )
    {
        let newvec: Vec<String> = dependsOn.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    pub fn set_target<'a>( &mut self, target: &'a str )
    {
        self.target = Some(String::from_str(target));
    }

    pub fn mark_as_satisfied<'a>( &mut self,
                                   things: &'a[&'a str] )
    {
        for thing in things.iter() {
            self.satisfied.insert(String::from_str(*thing));
        }
    }

    fn get_next_dependency(&mut self, thing: &String) -> String
    {
        if self.curpath.contains(thing) {
            fail!("Circular dependency graph at {}",thing);
        }
        self.curpath.insert(thing.clone());

        let deplist = match self.dependencies.find(thing) {
            None => return thing.clone(),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            if self.satisfied.contains(n) {
                continue;
            }
            return self.get_next_dependency(n);
        }
        // things dependencies are satisfied
        thing.clone()
    }

    pub fn iter<'a>(&'a mut self) -> DepGraphIterator<'a>
    {
        DepGraphIterator {
            depgraph: self
        }
    }
}

impl<'a> Iterator<String> for DepGraphIterator<'a> {
    fn next(&mut self) -> Option<String>
    {
        let thing = match self.depgraph.target {
            None => return None,
            Some(ref thing) => thing.clone()
        };
        if self.depgraph.satisfied.contains(&thing) {
            return None;
        }
        self.depgraph.curpath.clear();
        Some(self.depgraph.get_next_dependency(&thing))
    }
}

#[test]
fn dglr_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    depgraph.set_target("a");

    let mut results: Vec<String> = Vec::new();

    loop {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }

    assert!( results == vec![String::from_str("d"),
                             String::from_str("b"),
                             String::from_str("f"),
                             String::from_str("e"),
                             String::from_str("n"),
                             String::from_str("m"),
                             String::from_str("j"),
                             String::from_str("l"),
                             String::from_str("k"),
                             String::from_str("i"),
                             String::from_str("h"),
                             String::from_str("g"),
                             String::from_str("c"),
                             String::from_str("a")] );
    //info!("Deps of a = {}",results);
}

#[test]
fn dglr_test_circular() {

    let task_result = task::try(proc() {
        let mut depgraph: DepGraph = DepGraph::new();
        depgraph.register_dependency("a","b");
        depgraph.register_dependency("b","c");
        depgraph.register_dependency("c","a");
        depgraph.set_target("a");

        let mut results: Vec<String> = Vec::new();

        loop {
            // Detect infinite looping bugs by
            // breaking out successfully (successful
            // proc() means failed test!)
            if results.len() >= 30 { break; }

            let thing = match depgraph.iter().next() {
                Some(x) => x,
                None => break,
            };
            depgraph.mark_as_satisfied([thing.as_slice()]);
            results.push(thing);
        }
    });
    match task_result {
        Ok(_) => fail!("Should have failed at the circular dependency!"),
        Err(_) => () //info!("Successfully detected the circular dependency (ignore task failure)"),
    };
}

#[test]
fn dglr_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", []);
    depgraph.register_dependencies("owneruser", ["superconn"]);
    depgraph.register_dependencies("appuser", ["superconn"]);
    depgraph.register_dependencies("database", ["owneruser"]);
    depgraph.register_dependencies("ownerconn", ["database","owneruser"]);
    depgraph.register_dependencies("adminconn", ["database"]);
    depgraph.register_dependencies("extensions", ["database","adminconn"]);
    depgraph.register_dependencies("schema_table", ["database","ownerconn"]);
    depgraph.register_dependencies("schemas", ["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", ["database","appuser","schemas"]);

    depgraph.set_target("appconn");
    depgraph.mark_as_satisfied(["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    loop {
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }
    assert!( !results.contains(&String::from_str("superconn")) );
}
<|endoftext|>


<commit_before>// module export
pub mod input_map;

use parking_lot::RwLock;
use std::cell::RefCell;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Instant;
use std::vec::Vec;

use crate::core::document;
use crate::core::document::Document;
use crate::core::screen::Screen;

//
// TODO(ceg): implement functions ti update the counters
// on send (++) / receive (--)
// add per Event counters
//

//
static UI_PENDING_INPUT_EVENT_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn pending_input_event_inc(count: usize) -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.fetch_add(count, Ordering::SeqCst)
}

pub fn pending_input_event_dec(count: usize) -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.fetch_sub(count, Ordering::SeqCst)
}

pub fn pending_input_event_count() -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.load(Ordering::SeqCst)
}

//
static UI_PENDING_RENDER_EVENT_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn pending_render_event_inc(count: usize) -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.fetch_add(count, Ordering::SeqCst)
}

pub fn pending_render_event_dec(count: usize) -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.fetch_sub(count, Ordering::SeqCst)
}

pub fn pending_render_event_count() -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.load(Ordering::SeqCst)
}

/// Message sent between core and ui threads.
#[derive(Debug, Clone)]
pub struct EventMessage<'a> {
    /// sequence number. should be reused in corresponding answer.
    pub seq: usize,
    /// underlying event.
    pub event: Event<'a>,
    // pub reply_to: Sender<EventMessage>, // clone
}

impl<'a> EventMessage<'a> {
    pub fn new(seq: usize, event: Event<'a>) -> Self {
        EventMessage { seq, event }
    }
}

/// Events sent between core and ui threads via EventMessage encapsulation.
#[derive(Debug, Clone)]
pub enum Event<'a> {
    /// Sent by ui thread. Request the rendering of a given view.
    UpdateViewEvent {
        width: usize,  // used to detect change
        height: usize, // used to detect change
    },

    /// Sent to core thread to update the ui
    RefreshViewEvent,

    /// Sent by core thread. Contains the rendered screen that maps view_id.
    DrawEvent {
        screen: Arc<RwLock<Box<Screen>>>,
        time: Instant,
    },

    /// Sent by ui thread. contains user input information.
    InputEvents {
        events: Vec<InputEvent>,
    },

    /// Sent core -> worker thread.
    /// Saving the document's data is done in parallel in a thread.
    /// The user can still browse the document.
    SyncTask {
        doc: Arc<RwLock<Document<'a>>>,
    },
    // test
    IndexTask {
        document_map: Arc<RwLock<HashMap<document::Id, Arc<RwLock<Document<'a>>>>>>,
    },

    ApplicationQuitEvent,
}

#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub struct KeyModifiers {
    pub ctrl: bool,
    pub alt: bool,
    pub shift: bool,
}

impl KeyModifiers {
    pub fn new() -> KeyModifiers {
        KeyModifiers {
            ctrl: false,
            alt: false,
            shift: false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ButtonEvent {
    pub button: u32, // TODO(ceg):: use enum MouseButton { Left, Middle , Right } ?
    pub x: i32,
    pub y: i32,
    pub mods: KeyModifiers,
}

impl Hash for ButtonEvent {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.button.hash(state);
        // ignore (x, y) coordinates
        self.mods.hash(state);
    }
}

#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub struct PointerEvent {
    pub x: i32,
    pub y: i32,
    pub mods: KeyModifiers,
}

impl PointerEvent {
    pub fn hash(&mut self) -> u64 {
        let mut s = DefaultHasher::new();
        // ignore x, y
        self.x.hash(&mut s);
        self.y.hash(&mut s);
        self.mods.hash(&mut s);
        s.finish()
    }
}

// TODO(ceg): special hash for ButtonPress/ButtonRelease that ignores (x,y)

/// Supported input events
#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub enum InputEvent {
    InvalidInputEvent,
    NoInputEvent,
    FallbackEvent, // use to map default action in input table
    RefreshUi { width: usize, height: usize }, // resize
    KeyPress { key: Key, mods: KeyModifiers },
    ButtonPress(ButtonEvent),
    ButtonRelease(ButtonEvent),
    PointerMotion(PointerEvent),
    WheelUp { mods: KeyModifiers, x: i32, y: i32 },
    WheelDown { mods: KeyModifiers, x: i32, y: i32 },
}

/// List of supported keyboard keys
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    NUL,
    Unicode(char), // utf32 codepoints
    UnicodeArray(Vec<char>),
    Clear,
    Pause,
    ScrollLock,
    SysReq,
    Escape,
    Delete,
    BackSpace,
    Insert,
    Home,
    Left,
    Up,
    Right,
    Down,
    PageUp,
    PageDown,
    End,
    Begin,
    F(usize),
    ///
    KeypadPlus,
    KeypadMinus,
    KeypadMul,
    KeypadDiv,
    KeypadEnter,
    NoKey,
}

pub type InputEventHash = u64;
pub type InputEventMap = HashMap<InputEventHash, Rc<InputEventRule>>;

#[derive(Debug)]
pub struct InputEventRule {
    // range ?
    pub action: Option<String>,
    pub children: Option<Rc<RefCell<InputEventMap>>>,
}

/// This function is the central point where
/// we can identify event of the same class
/// example:
/// for ButtonEvent we do partial hashing , ie: we ignore the coordinates of the pointer
/// for other events we rely on #[derive(Hash)]
fn compute_input_event_hash(t: &InputEvent) -> InputEventHash {
    let mut s = DefaultHasher::new();

    match t {
        InputEvent::ButtonPress(ref button_event) => match button_event {
            ButtonEvent {
                mods,
                x: _,
                y: _,
                button,
            } => {
                "ButtonPress".hash(&mut s);
                (*button).hash(&mut s);
                // ignore x y
                // (*x).hash(&mut s);
                // (*y).hash(&mut s);
                (*mods).hash(&mut s)
            }
        },

        InputEvent::ButtonRelease(ref button_event) => match button_event {
            ButtonEvent {
                mods,
                x: _,
                y: _,
                button,
            } => {
                "ButtonRelease".hash(&mut s);
                (*button).hash(&mut s);
                // ignore x y
                // (*x).hash(&mut s);
                // (*y).hash(&mut s);
                (*mods).hash(&mut s)
            }
        },

        InputEvent::WheelUp { mods, x: _, y: _ } => {
            "WheelUp".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        InputEvent::WheelDown { mods, x: _, y: _ } => {
            "WheelDown".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        InputEvent::PointerMotion(PointerEvent { mods, x: _, y: _ }) => {
            "PointerMotion".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        _ => t.hash(&mut s),
    }

    s.finish()
}
<commit_msg>update comments<commit_after>// module export
pub mod input_map;

use parking_lot::RwLock;
use std::cell::RefCell;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Instant;
use std::vec::Vec;

use crate::core::document;
use crate::core::document::Document;
use crate::core::screen::Screen;

//
// TODO(ceg): implement functions ti update the counters
// on send (++) / receive (--)
// add per Event counters
//

//
static UI_PENDING_INPUT_EVENT_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn pending_input_event_inc(count: usize) -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.fetch_add(count, Ordering::SeqCst)
}

pub fn pending_input_event_dec(count: usize) -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.fetch_sub(count, Ordering::SeqCst)
}

pub fn pending_input_event_count() -> usize {
    UI_PENDING_INPUT_EVENT_COUNT.load(Ordering::SeqCst)
}

//
static UI_PENDING_RENDER_EVENT_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn pending_render_event_inc(count: usize) -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.fetch_add(count, Ordering::SeqCst)
}

pub fn pending_render_event_dec(count: usize) -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.fetch_sub(count, Ordering::SeqCst)
}

pub fn pending_render_event_count() -> usize {
    UI_PENDING_RENDER_EVENT_COUNT.load(Ordering::SeqCst)
}

/// Message sent between core and ui threads.
#[derive(Debug, Clone)]
pub struct EventMessage<'a> {
    /// sequence number. should be reused in corresponding answer.
    pub seq: usize,
    /// underlying event.
    pub event: Event<'a>,
    // pub reply_to: Sender<EventMessage>, // clone
}

impl<'a> EventMessage<'a> {
    pub fn new(seq: usize, event: Event<'a>) -> Self {
        EventMessage { seq, event }
    }
}

/// Events sent between core and ui threads via EventMessage encapsulation.
#[derive(Debug, Clone)]
pub enum Event<'a> {
    /// Sent by ui thread. Request the rendering of a given view.
    UpdateViewEvent {
        width: usize,  // used to detect change
        height: usize, // used to detect change
    },

    /// Sent to core thread to update the ui
    RefreshViewEvent,

    /// Sent by core thread. Contains the rendered screen that maps view_id.
    DrawEvent {
        screen: Arc<RwLock<Box<Screen>>>,
        time: Instant,
    },

    /// Sent by ui thread. contains user input information.
    InputEvents {
        events: Vec<InputEvent>,
    },

    /// Sent core -> worker thread.
    /// Saving the document's data is done in parallel in a thread.
    /// The user can still browse the document.
    SyncTask {
        doc: Arc<RwLock<Document<'a>>>,
    },
    // test
    IndexTask {
        document_map: Arc<RwLock<HashMap<document::Id, Arc<RwLock<Document<'a>>>>>>,
    },

    ApplicationQuitEvent,
}

#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub struct KeyModifiers {
    pub ctrl: bool,
    pub alt: bool,
    pub shift: bool,
}

impl KeyModifiers {
    pub fn new() -> KeyModifiers {
        KeyModifiers {
            ctrl: false,
            alt: false,
            shift: false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ButtonEvent {
    pub button: u32, // TODO(ceg):: use enum MouseButton { Left, Middle , Right } ?
    pub x: i32,
    pub y: i32,
    pub mods: KeyModifiers,
}

impl Hash for ButtonEvent {
    // special hash for ButtonPress/ButtonRelease that ignores (x,y)
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.button.hash(state);
        // ignore (x, y) coordinates
        self.mods.hash(state);
    }
}

#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub struct PointerEvent {
    pub x: i32,
    pub y: i32,
    pub mods: KeyModifiers,
}

impl PointerEvent {
    pub fn hash(&mut self) -> u64 {
        let mut s = DefaultHasher::new();
        // ignore x, y
        self.x.hash(&mut s);
        self.y.hash(&mut s);
        self.mods.hash(&mut s);
        s.finish()
    }
}

/// Supported input events
#[derive(Hash, Debug, Clone, PartialEq, Eq)]
pub enum InputEvent {
    InvalidInputEvent,
    NoInputEvent,
    FallbackEvent, // use to map default action in input table
    RefreshUi { width: usize, height: usize }, // resize
    KeyPress { key: Key, mods: KeyModifiers },
    ButtonPress(ButtonEvent),
    ButtonRelease(ButtonEvent),
    PointerMotion(PointerEvent),
    WheelUp { mods: KeyModifiers, x: i32, y: i32 },
    WheelDown { mods: KeyModifiers, x: i32, y: i32 },
}

/// List of supported keyboard keys
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    NUL,
    Unicode(char), // utf32 codepoints
    UnicodeArray(Vec<char>),
    Clear,
    Pause,
    ScrollLock,
    SysReq,
    Escape,
    Delete,
    BackSpace,
    Insert,
    Home,
    Left,
    Up,
    Right,
    Down,
    PageUp,
    PageDown,
    End,
    Begin,
    F(usize),
    ///
    KeypadPlus,
    KeypadMinus,
    KeypadMul,
    KeypadDiv,
    KeypadEnter,
    NoKey,
}

pub type InputEventHash = u64;
pub type InputEventMap = HashMap<InputEventHash, Rc<InputEventRule>>;

#[derive(Debug)]
pub struct InputEventRule {
    // range ?
    pub action: Option<String>,
    pub children: Option<Rc<RefCell<InputEventMap>>>,
}

/// This function is the central point where
/// we can identify event of the same class
/// example:
/// for ButtonEvent we do partial hashing , ie: we ignore the coordinates of the pointer
/// for other events we rely on #[derive(Hash)]
fn compute_input_event_hash(t: &InputEvent) -> InputEventHash {
    let mut s = DefaultHasher::new();

    match t {
        InputEvent::ButtonPress(ref button_event) => match button_event {
            ButtonEvent {
                mods,
                x: _,
                y: _,
                button,
            } => {
                "ButtonPress".hash(&mut s);
                (*button).hash(&mut s);
                // ignore x y
                // (*x).hash(&mut s);
                // (*y).hash(&mut s);
                (*mods).hash(&mut s)
            }
        },

        InputEvent::ButtonRelease(ref button_event) => match button_event {
            ButtonEvent {
                mods,
                x: _,
                y: _,
                button,
            } => {
                "ButtonRelease".hash(&mut s);
                (*button).hash(&mut s);
                // ignore x y
                // (*x).hash(&mut s);
                // (*y).hash(&mut s);
                (*mods).hash(&mut s)
            }
        },

        InputEvent::WheelUp { mods, x: _, y: _ } => {
            "WheelUp".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        InputEvent::WheelDown { mods, x: _, y: _ } => {
            "WheelDown".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        InputEvent::PointerMotion(PointerEvent { mods, x: _, y: _ }) => {
            "PointerMotion".hash(&mut s);
            // ignore x y
            // (*x).hash(&mut s);
            // (*y).hash(&mut s);
            (*mods).hash(&mut s)
        }

        _ => t.hash(&mut s),
    }

    s.finish()
}
<|endoftext|>


<commit_before>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

static mut LOCK: StaticMutex = MUTEX_INIT;

static mut registered_drivers: bool = false;

struct Dataset {
    c_dataset: *(),
}

struct Driver {
    c_driver: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}
<commit_msg>reorganize objects in module<commit_after>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}

static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

struct Dataset {
    c_dataset: *(),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

struct Driver {
    c_driver: *(),
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}
<|endoftext|>


<commit_before>use std::num::{NumCast};
use std::ops::{Add, Sub, Mul, Div, Neg};
use primitive::Primitive;
use ::{Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> { V2(self.0 * rhs, self.1 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> { V2(self.0 / rhs, self.1 / rhs) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Primitive> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> { V2(self.0 / rhs.0, self.1 / rhs.1) }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> { V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> { V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2) }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> { V3(-self.0, -self.1, -self.2) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> { V3(self.0 * rhs, self.1 * rhs, self.2 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> { V3(self.0 / rhs, self.1 / rhs, self.2 / rhs) }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] { [self.0, self.1, self.2] }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Primitive> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> { V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2) }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> { V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2) }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2 }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }
    pub fn mx(&self) -> V2<T> { self.0 + self.1 }
    pub fn dim(&self) -> V2<T> { self.1 }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1 / NumCast::from(2).unwrap())
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> { Rect(self.0 + rhs, self.1.clone()) }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Primitive> Iterator for RectIter<T> {
    type Item = V2<T>;
    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + NumCast::from(1).unwrap();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + NumCast::from(1).unwrap();
        }
        ret
    }
}
<commit_msg>Vecs implement total ordering if their elements do<commit_after>use std::num::{NumCast};
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::{Ordering};
use primitive::Primitive;
use ::{Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> { V2(self.0 * rhs, self.1 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> { V2(self.0 / rhs, self.1 / rhs) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Primitive> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> { V2(self.0 / rhs.0, self.1 / rhs.1) }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 }
}

impl<T: Ord+Copy> Ord for V2<T> {
    fn cmp(&self, other: &V2<T>) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1))
    }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> { V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> { V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2) }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> { V3(-self.0, -self.1, -self.2) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> { V3(self.0 * rhs, self.1 * rhs, self.2 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> { V3(self.0 / rhs, self.1 / rhs, self.2 / rhs) }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] { [self.0, self.1, self.2] }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Primitive> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> { V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2) }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> { V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2) }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2 }
}

impl<T: Ord+Copy> Ord for V3<T> {
    fn cmp(&self, other: &V3<T>) -> Ordering {
        (self.0, self.1, self.2).cmp(&(other.0, other.1, other.2))
    }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }
    pub fn mx(&self) -> V2<T> { self.0 + self.1 }
    pub fn dim(&self) -> V2<T> { self.1 }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1 / NumCast::from(2).unwrap())
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> { Rect(self.0 + rhs, self.1.clone()) }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Primitive> Iterator for RectIter<T> {
    type Item = V2<T>;
    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + NumCast::from(1).unwrap();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + NumCast::from(1).unwrap();
        }
        ret
    }
}
<|endoftext|>