<commit_before>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            println!("depend_add:({:?},{:?})", x, y);
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;4];
            let mut nodes = vec![];
            for i in 0..4 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                if nodes.len() == 7 { break; }
                else { item_num += 2 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn hourglass_big<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<commit_msg>possible fix; moved nodes off of the stack..?? confused.<commit_after>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: Art<u64,A::Loc>,y: Art<u64,A::Loc>) -> u64 {
            st.force(&x) * st.force(&y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: Art<u64,A::Loc>,y: Art<u64,A::Loc>) -> u64 {
            println!("depend_add:({:?},{:?})", x, y);
            st.force(&x) + st.force(&y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;4];
            let mut nodes = vec![];
            for i in 0..4 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:first, y:second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                if nodes.len() == 7 { break; }
                else { item_num += 2 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn hourglass_big<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:first, y:second));
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);

                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::path::Path;

use sdl2::event::Event;
use sdl2::gfx::primitives::DrawRenderer;
use sdl2::keyboard::*;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::Rect;
use sdl2::render::{BlendMode, Renderer, Texture, TextureQuery};
use sdl2::surface::Surface;
use sdl2::ttf::{Font, Sdl2TtfContext, STYLE_BOLD};

use position::Position;
use text::Text;

const BORDER_COLOR: Color = Color::RGBA(255, 255, 255, 64);

const PADDING: i32 = 10;

const FONT_COLOR: Color = Color::RGBA(45, 200, 45, 255);
const FONT_SIZE: u16 = 18;

pub struct Console<'a> {
    pub visible: bool,
    visible_start_time: u32, // Used to ensure that the KeyDown event that opens the console does not trigger text input

    font_file: &'a str,
    leader: Text,
    input_buffer: String,
    last_command: String,
    command_history: Vec<String>,
    history_position: usize,
    cursor_position: usize,
    buffer: Vec<String>,
    backbuffer_y: i32,
    texture: Texture,
    ttf_context: &'a Sdl2TtfContext,
    size: (u32, u32),
    font: Font<'a>,
    line_ending: bool, // Tracks where the next print call should append to
    ctrl: bool, // Tracks the Ctrl key being pressed
    shift: bool, // Tracks the Shift key being pressed
}

impl<'a> Console<'a> {
    /// Creates a new empty Console
    pub fn new(ttf_context: &'a Sdl2TtfContext,
               mut renderer: &mut Renderer,
               font_file: &'a str)
               -> Console<'a> {
        let (width, height) = renderer.window().unwrap().size();
        let mut texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, width / 2, height)
                .unwrap();
        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..height {
                    for x in 0..width / 2 {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        let mut font = ttf_context.load_font(Path::new(font_file), FONT_SIZE).unwrap();
        font.set_style(STYLE_BOLD);

        Console {
            visible: false,
            visible_start_time: 0,

            font_file: font_file,
            leader: Text::new(ttf_context,
                              &mut renderer,
                              "hakka>",
                              Position::XY(PADDING, height as i32 - FONT_SIZE as i32 - PADDING),
                              FONT_SIZE,
                              FONT_COLOR,
                              font_file),
            input_buffer: "".into(),
            last_command: "".into(),
            command_history: Vec::new(),
            history_position: 0,
            cursor_position: 0,
            buffer: Vec::new(),
            backbuffer_y: 0,
            texture: texture,
            ttf_context: ttf_context,
            size: (width / 2, height),
            font: font,
            line_ending: true,
            ctrl: false,
            shift: false,
        }
    }

    pub fn process(&mut self, event: &Event) {
        match *event {
            Event::TextInput { ref text, timestamp, .. } => {
                if self.visible && timestamp != self.visible_start_time {
                    self.add_text(text);
                }
            }
            Event::MouseWheel { y, .. } => {
                if self.visible {
                    if self.buffer.len() * FONT_SIZE as usize >
                       (self.size.1 - (FONT_SIZE as u32 * 2)) as usize {
                        self.backbuffer_y += y * 6;
                        if self.backbuffer_y < 0 {
                            self.backbuffer_y = 0;
                        }
                    }
                }
            }
            Event::KeyDown { keycode, scancode, timestamp, keymod, .. } => {
                if self.visible {
                    if !keymod.intersects(LALTMOD | LCTRLMOD | LSHIFTMOD | RALTMOD | RCTRLMOD | RSHIFTMOD) {
                        // The 'Grave' scancode coresponds to the key in the top-left corner of the
                        // keyboard, bellow escape, on (hopefully) all keyboard layouts.
                        if let Some(Scancode::Grave) = scancode {
                            self.toggle(timestamp);
                            return;
                        }
                    }

                    match keycode {
                        Some(Keycode::LCtrl) |
                        Some(Keycode::RCtrl) => self.ctrl = true,
                        Some(Keycode::LShift) |
                        Some(Keycode::RShift) => self.shift = true,
                        Some(Keycode::C) => {
                            if self.ctrl {
                                self.input_buffer.push_str("^C");
                                self.commit();
                            }
                        }
                        Some(Keycode::Left) => {
                            self.cursor_left();
                        }
                        Some(Keycode::Right) => {
                            self.cursor_right();
                        }
                        Some(Keycode::Backspace) => {
                            self.backspace();
                        }
                        Some(Keycode::Delete) => {
                            if self.cursor_position < self.input_buffer.len() {
                                self.cursor_position += 1;
                                self.backspace();
                            }
                        }
                        _ => (),
                    }
                }
            }
            Event::KeyUp { keycode, .. } => {
                if self.visible {
                    match keycode {
                        Some(Keycode::LCtrl) |
                        Some(Keycode::RCtrl) => self.ctrl = false,
                        Some(Keycode::LShift) |
                        Some(Keycode::RShift) => self.shift = false,
                        Some(Keycode::Up) => {
                            self.history_navigate_back();
                        }
                        Some(Keycode::Down) => {
                            self.history_navigate_forward();
                        }
                        Some(Keycode::Return) => {
                            self.commit();
                        }
                        Some(Keycode::End) => {
                            self.cursor_position = self.input_buffer.len();
                        }
                        Some(Keycode::Home) => {
                            self.cursor_position = 0;
                        }
                        _ => (),
                    }
                }
            }
            _ => (),
        }
    }

    pub fn process_command(&mut self) {
        let command = self.input_buffer.clone();
        if !command.is_empty() {
            self.command_history.push(command.clone());
            self.last_command = command.clone();

            if command == "exit" {
                std::process::exit(0);
            }
        }
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }

    fn history_navigate_back(&mut self) {
        if self.history_position > 0 {
            self.input_buffer = self.command_history[self.history_position - 1].clone();
            self.cursor_position = self.input_buffer.len();

            if self.history_position > 0 {
                self.history_position -= 1;
            }
        }
    }

    fn history_navigate_forward(&mut self) {
        if self.history_position < self.command_history.len() - 1 {
            self.input_buffer = self.command_history[self.history_position + 1].clone();
            self.cursor_position = self.input_buffer.len();
            if self.history_position < self.command_history.len() {
                self.history_position += 1;
            }
        }
    }

    pub fn try_process_command(&mut self) -> Option<String> {
        if !self.last_command.is_empty() {
            let cmd = self.last_command.clone();
            self.last_command.clear();
            Some(cmd)
        } else {
            None
        }
    }

    pub fn print<S>(&mut self, text: S)
        where S: Into<String>
    {
        if !self.line_ending {
            let last = self.buffer.last_mut().unwrap();
            last.push_str(&text.into());
        } else {
            self.buffer.push(text.into());
        }
        self.line_ending = false;
    }

    pub fn println<S>(&mut self, text: S)
        where S: Into<String>
    {
        self.buffer.push(text.into());
        self.line_ending = true;
    }

    pub fn print_lines<S>(&mut self, text: S)
        where S: Into<String>
    {
        for line in text.into().lines() {
            self.println(line);
        }
    }

    pub fn wrap_line(&mut self) {
        self.buffer.push("".into());
        self.line_ending = false;
    }

    /// Toggles the visibility of the Console
    pub fn toggle(&mut self, time: u32) {
        self.visible = !self.visible;
        if self.visible {
            self.visible_start_time = time;
        }
    }

    pub fn add_text(&mut self, input: &str) {
        self.input_buffer.insert(self.cursor_position, input.chars().next().unwrap());
        self.cursor_position += input.len();
    }

    pub fn commit(&mut self) {
        self.buffer.push(format!("hakka> {}", self.input_buffer.clone()));
        self.process_command();
        self.input_buffer.clear();
        self.cursor_position = 0;
        self.history_position = self.command_history.len();
    }

    pub fn cursor_left(&mut self) {
        if self.cursor_position > 0 {
            self.cursor_position -= 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position -= 1;
            }
        }
    }

    pub fn cursor_right(&mut self) {
        if self.cursor_position < self.input_buffer.len() {
            self.cursor_position += 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position += 1;
            }
        }
    }

    pub fn backspace(&mut self) {
        if self.visible && self.cursor_position > 0 {
            self.cursor_position -= 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position -= 1;
            }
            self.input_buffer.remove(self.cursor_position);
        }
    }

    /// Renders the Console
    pub fn render(&mut self, mut renderer: &mut Renderer) {
        if self.visible {

            renderer.set_blend_mode(BlendMode::Blend);
            self.texture.set_blend_mode(BlendMode::Blend);
            renderer.copy(&self.texture,
                      None,
                      Some(Rect::new(0, 0, self.size.0, self.size.1)))
                .unwrap();
            self.generate_backbuffer_texture(&mut renderer);
            self.render_leader(&mut renderer);

            // Insert the cursor via a dodgy vertical line
            let cursor_x =
                60 + PADDING as i16 +
                self.font.size_of(&self.input_buffer[..self.cursor_position]).unwrap().0 as i16;
            // Draw a dodgy cursor
            renderer.thick_line(cursor_x,
                            self.size.1 as i16 - FONT_SIZE as i16 - PADDING as i16,
                            cursor_x,
                            self.size.1 as i16 - PADDING as i16,
                            1,
                            FONT_COLOR)
                .unwrap();

            if !self.input_buffer.is_empty() {
                let text = Text::new(self.ttf_context,
                                     &mut renderer,
                                     &self.input_buffer[..],
                                     Position::XY(60 + PADDING,
                                                  self.size.1 as i32 - FONT_SIZE as i32 - PADDING),
                                     FONT_SIZE,
                                     FONT_COLOR,
                                     self.font_file);
                text.render(&mut renderer);
            }

            self.render_border(&mut renderer);
        }
    }

    fn render_border(&self, mut renderer: &mut Renderer) {
        // Render the border
        renderer.set_draw_color(Color::RGBA(255, 255, 255, 255));
        // North
        renderer.thick_line(0, 0, self.size.0 as i16, 0, 1, BORDER_COLOR).unwrap();

        // East
        renderer.thick_line(self.size.0 as i16,
                        0,
                        self.size.0 as i16,
                        self.size.1 as i16,
                        1,
                        BORDER_COLOR)
            .unwrap();

        // South
        renderer.thick_line(0,
                        self.size.1 as i16 - 1,
                        self.size.0 as i16,
                        self.size.1 as i16 - 1,
                        1,
                        BORDER_COLOR)
            .unwrap();
    }

    fn render_leader(&self, mut renderer: &mut Renderer) {
        // Render a black background behind it so the buffer scrolling looks
        // nicer.
        let rect_y = self.size.1 as i32 - FONT_SIZE as i32 - PADDING;
        renderer.set_draw_color(Color::RGBA(0, 0, 0, 255));
        renderer.fill_rect(Rect::new(0, rect_y, self.size.0, rect_y as u32)).unwrap();
        self.leader.render(&mut renderer);
    }

    fn generate_backbuffer_texture(&mut self, mut renderer: &mut Renderer) {
        let mut main_surface = Surface::new(self.size.0,
                                            (self.size.1 - (FONT_SIZE as u32)),
                                            PixelFormatEnum::RGBA8888)
            .unwrap();
        let mut counter = 2;
        for line in self.buffer.iter().rev().take(100) {
            let y_pos = self.size.1 as i32 - (FONT_SIZE as i32 * counter) + self.backbuffer_y;
            counter += 1;

            if line.trim().is_empty() {
                continue;
            }

            let surface = self.font
                .render(line)
                .blended(FONT_COLOR)
                .unwrap();
            surface.blit(None,
                      &mut main_surface,
                      Some(Rect::new(PADDING, y_pos - PADDING, self.size.1, FONT_SIZE as u32)))
                .unwrap();
        }
        let texture = renderer.create_texture_from_surface(&main_surface)
            .unwrap();

        let TextureQuery { width, height, .. } = texture.query();

        renderer.copy(&texture, None, Some(Rect::new(0, 0, width, height))).unwrap();
    }
}
<commit_msg>Fixed crash un UpKey when command history empty<commit_after>use std;
use std::path::Path;

use sdl2::event::Event;
use sdl2::gfx::primitives::DrawRenderer;
use sdl2::keyboard::*;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::Rect;
use sdl2::render::{BlendMode, Renderer, Texture, TextureQuery};
use sdl2::surface::Surface;
use sdl2::ttf::{Font, Sdl2TtfContext, STYLE_BOLD};

use position::Position;
use text::Text;

const BORDER_COLOR: Color = Color::RGBA(255, 255, 255, 64);

const PADDING: i32 = 10;

const FONT_COLOR: Color = Color::RGBA(45, 200, 45, 255);
const FONT_SIZE: u16 = 18;

pub struct Console<'a> {
    pub visible: bool,
    visible_start_time: u32, // Used to ensure that the KeyDown event that opens the console does not trigger text input

    font_file: &'a str,
    leader: Text,
    input_buffer: String,
    last_command: String,
    command_history: Vec<String>,
    history_position: usize,
    cursor_position: usize,
    buffer: Vec<String>,
    backbuffer_y: i32,
    texture: Texture,
    ttf_context: &'a Sdl2TtfContext,
    size: (u32, u32),
    font: Font<'a>,
    line_ending: bool, // Tracks where the next print call should append to
    ctrl: bool, // Tracks the Ctrl key being pressed
    shift: bool, // Tracks the Shift key being pressed
}

impl<'a> Console<'a> {
    /// Creates a new empty Console
    pub fn new(ttf_context: &'a Sdl2TtfContext,
               mut renderer: &mut Renderer,
               font_file: &'a str)
               -> Console<'a> {
        let (width, height) = renderer.window().unwrap().size();
        let mut texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, width / 2, height)
                .unwrap();
        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..height {
                    for x in 0..width / 2 {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        let mut font = ttf_context.load_font(Path::new(font_file), FONT_SIZE).unwrap();
        font.set_style(STYLE_BOLD);

        Console {
            visible: false,
            visible_start_time: 0,

            font_file: font_file,
            leader: Text::new(ttf_context,
                              &mut renderer,
                              "hakka>",
                              Position::XY(PADDING, height as i32 - FONT_SIZE as i32 - PADDING),
                              FONT_SIZE,
                              FONT_COLOR,
                              font_file),
            input_buffer: "".into(),
            last_command: "".into(),
            command_history: Vec::new(),
            history_position: 0,
            cursor_position: 0,
            buffer: Vec::new(),
            backbuffer_y: 0,
            texture: texture,
            ttf_context: ttf_context,
            size: (width / 2, height),
            font: font,
            line_ending: true,
            ctrl: false,
            shift: false,
        }
    }

    pub fn process(&mut self, event: &Event) {
        match *event {
            Event::TextInput { ref text, timestamp, .. } => {
                if self.visible && timestamp != self.visible_start_time {
                    self.add_text(text);
                }
            }
            Event::MouseWheel { y, .. } => {
                if self.visible {
                    if self.buffer.len() * FONT_SIZE as usize >
                       (self.size.1 - (FONT_SIZE as u32 * 2)) as usize {
                        self.backbuffer_y += y * 6;
                        if self.backbuffer_y < 0 {
                            self.backbuffer_y = 0;
                        }
                    }
                }
            }
            Event::KeyDown { keycode, scancode, timestamp, keymod, .. } => {
                if self.visible {
                    if !keymod.intersects(LALTMOD | LCTRLMOD | LSHIFTMOD | RALTMOD | RCTRLMOD | RSHIFTMOD) {
                        // The 'Grave' scancode coresponds to the key in the top-left corner of the
                        // keyboard, bellow escape, on (hopefully) all keyboard layouts.
                        if let Some(Scancode::Grave) = scancode {
                            self.toggle(timestamp);
                            return;
                        }
                    }

                    match keycode {
                        Some(Keycode::LCtrl) |
                        Some(Keycode::RCtrl) => self.ctrl = true,
                        Some(Keycode::LShift) |
                        Some(Keycode::RShift) => self.shift = true,
                        Some(Keycode::C) => {
                            if self.ctrl {
                                self.input_buffer.push_str("^C");
                                self.commit();
                            }
                        }
                        Some(Keycode::Left) => {
                            self.cursor_left();
                        }
                        Some(Keycode::Right) => {
                            self.cursor_right();
                        }
                        Some(Keycode::Backspace) => {
                            self.backspace();
                        }
                        Some(Keycode::Delete) => {
                            if self.cursor_position < self.input_buffer.len() {
                                self.cursor_position += 1;
                                self.backspace();
                            }
                        }
                        _ => (),
                    }
                }
            }
            Event::KeyUp { keycode, .. } => {
                if self.visible {
                    match keycode {
                        Some(Keycode::LCtrl) |
                        Some(Keycode::RCtrl) => self.ctrl = false,
                        Some(Keycode::LShift) |
                        Some(Keycode::RShift) => self.shift = false,
                        Some(Keycode::Up) => {
                            self.history_navigate_back();
                        }
                        Some(Keycode::Down) => {
                            self.history_navigate_forward();
                        }
                        Some(Keycode::Return) => {
                            self.commit();
                        }
                        Some(Keycode::End) => {
                            self.cursor_position = self.input_buffer.len();
                        }
                        Some(Keycode::Home) => {
                            self.cursor_position = 0;
                        }
                        _ => (),
                    }
                }
            }
            _ => (),
        }
    }

    pub fn process_command(&mut self) {
        let command = self.input_buffer.clone();
        if !command.is_empty() {
            self.command_history.push(command.clone());
            self.last_command = command.clone();

            if command == "exit" {
                std::process::exit(0);
            }
        }
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }

    fn history_navigate_back(&mut self) {
        if self.history_position > 0 {
            self.input_buffer = self.command_history[self.history_position - 1].clone();
            self.cursor_position = self.input_buffer.len();

            if self.history_position > 0 {
                self.history_position -= 1;
            }
        }
    }

    fn history_navigate_forward(&mut self) {
        if self.command_history.len() > 0 && self.history_position < self.command_history.len() - 1 {
            self.input_buffer = self.command_history[self.history_position + 1].clone();
            self.cursor_position = self.input_buffer.len();
            if self.history_position < self.command_history.len() {
                self.history_position += 1;
            }
        }
    }

    pub fn try_process_command(&mut self) -> Option<String> {
        if !self.last_command.is_empty() {
            let cmd = self.last_command.clone();
            self.last_command.clear();
            Some(cmd)
        } else {
            None
        }
    }

    pub fn print<S>(&mut self, text: S)
        where S: Into<String>
    {
        if !self.line_ending {
            let last = self.buffer.last_mut().unwrap();
            last.push_str(&text.into());
        } else {
            self.buffer.push(text.into());
        }
        self.line_ending = false;
    }

    pub fn println<S>(&mut self, text: S)
        where S: Into<String>
    {
        self.buffer.push(text.into());
        self.line_ending = true;
    }

    pub fn print_lines<S>(&mut self, text: S)
        where S: Into<String>
    {
        for line in text.into().lines() {
            self.println(line);
        }
    }

    pub fn wrap_line(&mut self) {
        self.buffer.push("".into());
        self.line_ending = false;
    }

    /// Toggles the visibility of the Console
    pub fn toggle(&mut self, time: u32) {
        self.visible = !self.visible;
        if self.visible {
            self.visible_start_time = time;
        }
    }

    pub fn add_text(&mut self, input: &str) {
        self.input_buffer.insert(self.cursor_position, input.chars().next().unwrap());
        self.cursor_position += input.len();
    }

    pub fn commit(&mut self) {
        self.buffer.push(format!("hakka> {}", self.input_buffer.clone()));
        self.process_command();
        self.input_buffer.clear();
        self.cursor_position = 0;
        self.history_position = self.command_history.len();
    }

    pub fn cursor_left(&mut self) {
        if self.cursor_position > 0 {
            self.cursor_position -= 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position -= 1;
            }
        }
    }

    pub fn cursor_right(&mut self) {
        if self.cursor_position < self.input_buffer.len() {
            self.cursor_position += 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position += 1;
            }
        }
    }

    pub fn backspace(&mut self) {
        if self.visible && self.cursor_position > 0 {
            self.cursor_position -= 1;
            while !self.input_buffer.is_char_boundary(self.cursor_position) {
                self.cursor_position -= 1;
            }
            self.input_buffer.remove(self.cursor_position);
        }
    }

    /// Renders the Console
    pub fn render(&mut self, mut renderer: &mut Renderer) {
        if self.visible {

            renderer.set_blend_mode(BlendMode::Blend);
            self.texture.set_blend_mode(BlendMode::Blend);
            renderer.copy(&self.texture,
                      None,
                      Some(Rect::new(0, 0, self.size.0, self.size.1)))
                .unwrap();
            self.generate_backbuffer_texture(&mut renderer);
            self.render_leader(&mut renderer);

            // Insert the cursor via a dodgy vertical line
            let cursor_x =
                60 + PADDING as i16 +
                self.font.size_of(&self.input_buffer[..self.cursor_position]).unwrap().0 as i16;
            // Draw a dodgy cursor
            renderer.thick_line(cursor_x,
                            self.size.1 as i16 - FONT_SIZE as i16 - PADDING as i16,
                            cursor_x,
                            self.size.1 as i16 - PADDING as i16,
                            1,
                            FONT_COLOR)
                .unwrap();

            if !self.input_buffer.is_empty() {
                let text = Text::new(self.ttf_context,
                                     &mut renderer,
                                     &self.input_buffer[..],
                                     Position::XY(60 + PADDING,
                                                  self.size.1 as i32 - FONT_SIZE as i32 - PADDING),
                                     FONT_SIZE,
                                     FONT_COLOR,
                                     self.font_file);
                text.render(&mut renderer);
            }

            self.render_border(&mut renderer);
        }
    }

    fn render_border(&self, mut renderer: &mut Renderer) {
        // Render the border
        renderer.set_draw_color(Color::RGBA(255, 255, 255, 255));
        // North
        renderer.thick_line(0, 0, self.size.0 as i16, 0, 1, BORDER_COLOR).unwrap();

        // East
        renderer.thick_line(self.size.0 as i16,
                        0,
                        self.size.0 as i16,
                        self.size.1 as i16,
                        1,
                        BORDER_COLOR)
            .unwrap();

        // South
        renderer.thick_line(0,
                        self.size.1 as i16 - 1,
                        self.size.0 as i16,
                        self.size.1 as i16 - 1,
                        1,
                        BORDER_COLOR)
            .unwrap();
    }

    fn render_leader(&self, mut renderer: &mut Renderer) {
        // Render a black background behind it so the buffer scrolling looks
        // nicer.
        let rect_y = self.size.1 as i32 - FONT_SIZE as i32 - PADDING;
        renderer.set_draw_color(Color::RGBA(0, 0, 0, 255));
        renderer.fill_rect(Rect::new(0, rect_y, self.size.0, rect_y as u32)).unwrap();
        self.leader.render(&mut renderer);
    }

    fn generate_backbuffer_texture(&mut self, mut renderer: &mut Renderer) {
        let mut main_surface = Surface::new(self.size.0,
                                            (self.size.1 - (FONT_SIZE as u32)),
                                            PixelFormatEnum::RGBA8888)
            .unwrap();
        let mut counter = 2;
        for line in self.buffer.iter().rev().take(100) {
            let y_pos = self.size.1 as i32 - (FONT_SIZE as i32 * counter) + self.backbuffer_y;
            counter += 1;

            if line.trim().is_empty() {
                continue;
            }

            let surface = self.font
                .render(line)
                .blended(FONT_COLOR)
                .unwrap();
            surface.blit(None,
                      &mut main_surface,
                      Some(Rect::new(PADDING, y_pos - PADDING, self.size.1, FONT_SIZE as u32)))
                .unwrap();
        }
        let texture = renderer.create_texture_from_surface(&main_surface)
            .unwrap();

        let TextureQuery { width, height, .. } = texture.query();

        renderer.copy(&texture, None, Some(Rect::new(0, 0, width, height))).unwrap();
    }
}
<|endoftext|>


<commit_before>//! List project issues
//!
//! https://docs.gitlab.com/ce/api/issues.html#list-project-issues
//!
//! # List project issues
//!
//! Get a list of a project's issues.
//!
//! ```text
//! GET /projects/ID/issues
//! GET /projects/ID/issues?state=opened
//! GET /projects/ID/issues?state=closed
//! GET /projects/ID/issues?labels=foo
//! GET /projects/ID/issues?labels=foo,bar
//! GET /projects/ID/issues?labels=foo,bar&state=opened
//! GET /projects/ID/issues?milestone=1.0.0
//! GET /projects/ID/issues?milestone=1.0.0&state=opened
//! GET /projects/ID/issues?iid=42
//! ```
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id`      | integer | yes   | The ID of a project |
//! | `iid`     | integer | no    | Return the issue having the given `iid` |
//! | `state`   | string  | no    | Return all issues or just those that are `opened` or `closed`|
//! | `labels`  | string  | no    | Comma-separated list of label names, issues with any of the labels will be returned |
//! | `milestone` | string| no    | The milestone title |
//! | `order_by`| string  | no    | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
//! | `sort`    | string  | no    | Return requests sorted in `asc` or `desc` order. Default is `desc`  |
//!

use serde_urlencoded;

use BuildQuery;
use Issues;
use issues::ProjectsIssuesListerInternal;

use ::errors::*;

#[derive(Debug, Clone)]
pub struct IssuesLister<'a> {
    gl: &'a ::GitLab,
    /// The ID of a group
    id: i64,
    internal: ProjectsIssuesListerInternal,
}

impl<'a> IssuesLister<'a> {
    pub fn new(gl: &'a ::GitLab, id: i64) -> IssuesLister {
        IssuesLister {
            gl: gl,
            id: id,
            internal: ProjectsIssuesListerInternal {
                iid: None,
                state: None,
                labels: None,
                milestone: None,
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn iid(&'a mut self, iid: i64) -> &'a mut IssuesLister {
        self.internal.iid = Some(iid);
        self
    }

    pub fn state(&'a mut self, state: ::issues::State) -> &'a mut IssuesLister {
        self.internal.state = Some(state);
        self
    }

    pub fn milestone(&'a mut self, milestone: String) -> &'a mut IssuesLister {
        self.internal.milestone = Some(milestone);
        self
    }

    pub fn labels(&'a mut self, labels: Vec<String>) -> &'a mut IssuesLister {
        self.internal.labels = Some(labels);
        self
    }

    pub fn order_by(&'a mut self, order_by: ::issues::ListingOrderBy) -> &'a mut IssuesLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut IssuesLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of issues.
    pub fn list(&self) -> Result<Issues> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for IssuesLister<'a> {
    fn build_query(&self) -> String {
        // NOTE: Can't use `serde_urlencoded` since it cannot serialize a Vec<T>
        //       See https://github.com/nox/serde_urlencoded/issues/6
        // let encoded = serde_urlencoded::to_string(&self.internal).unwrap();

        let mut query = format!("projects/{}/issues", self.id);
        let amp_char = "&";
        let comma_char = ",";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.internal.iid,
                              &self.internal.state,
                              &self.internal.labels,
                              &self.internal.milestone,
                              &self.internal.order_by,
                              &self.internal.sort) {
            (&None, &None, &None, &None, &None, &None) => "",
            _ => "?",
        });

        self.internal.iid.as_ref().map(|iid| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("iid=");
            query.push_str(&iid.to_string());
        });

        self.internal.state.map(|state| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("state=");
            query.push_str(match state {
                ::issues::State::Opened => "opened",
                ::issues::State::Closed => "closed",
            });
        });

        self.internal.labels.as_ref().map(|labels| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("labels=");

            let mut array_split_char = &none_char;
            for label in labels {
                query.push_str(array_split_char);
                query.push_str(&label.to_string());
                array_split_char = &comma_char;
            }
        });

        self.internal.milestone.as_ref().map(|milestone| {
            query.push_str(split_char);
            split_char = &amp_char;

            let params = &[("milestone", milestone)];
            query.push_str(&serde_urlencoded::to_string(&params).unwrap());
        });

        self.internal.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ::issues::ListingOrderBy::CreatedAt => "created_at",
                ::issues::ListingOrderBy::UpdatedAt => "updated_at",
            });
        });

        self.internal.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;

    const TEST_PROJECT_ID: i64 = 123;

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues", TEST_PROJECT_ID);

        let lister = gl.issues();
        let lister = lister.project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let lister = gl.issues().project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.issues().project(TEST_PROJECT_ID).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_iid() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?iid=42", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).iid(42).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_state() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?state=opened", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Opened).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?state=closed", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Closed).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_skip_groups() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?labels=label1,label2,label3",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .labels(vec![String::from("label1"), String::from("label2"), String::from("label3")])
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?order_by=updated_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::UpdatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?sort=asc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?sort=desc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at&sort=asc",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .sort(::ListingSort::Asc)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Add `issues::projects` unit test `build_query_milestone()`<commit_after>//! List project issues
//!
//! https://docs.gitlab.com/ce/api/issues.html#list-project-issues
//!
//! # List project issues
//!
//! Get a list of a project's issues.
//!
//! ```text
//! GET /projects/ID/issues
//! GET /projects/ID/issues?state=opened
//! GET /projects/ID/issues?state=closed
//! GET /projects/ID/issues?labels=foo
//! GET /projects/ID/issues?labels=foo,bar
//! GET /projects/ID/issues?labels=foo,bar&state=opened
//! GET /projects/ID/issues?milestone=1.0.0
//! GET /projects/ID/issues?milestone=1.0.0&state=opened
//! GET /projects/ID/issues?iid=42
//! ```
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id`      | integer | yes   | The ID of a project |
//! | `iid`     | integer | no    | Return the issue having the given `iid` |
//! | `state`   | string  | no    | Return all issues or just those that are `opened` or `closed`|
//! | `labels`  | string  | no    | Comma-separated list of label names, issues with any of the labels will be returned |
//! | `milestone` | string| no    | The milestone title |
//! | `order_by`| string  | no    | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
//! | `sort`    | string  | no    | Return requests sorted in `asc` or `desc` order. Default is `desc`  |
//!

use serde_urlencoded;

use BuildQuery;
use Issues;
use issues::ProjectsIssuesListerInternal;

use ::errors::*;

#[derive(Debug, Clone)]
pub struct IssuesLister<'a> {
    gl: &'a ::GitLab,
    /// The ID of a group
    id: i64,
    internal: ProjectsIssuesListerInternal,
}

impl<'a> IssuesLister<'a> {
    pub fn new(gl: &'a ::GitLab, id: i64) -> IssuesLister {
        IssuesLister {
            gl: gl,
            id: id,
            internal: ProjectsIssuesListerInternal {
                iid: None,
                state: None,
                labels: None,
                milestone: None,
                order_by: None,
                sort: None,
            },
        }
    }

    pub fn iid(&'a mut self, iid: i64) -> &'a mut IssuesLister {
        self.internal.iid = Some(iid);
        self
    }

    pub fn state(&'a mut self, state: ::issues::State) -> &'a mut IssuesLister {
        self.internal.state = Some(state);
        self
    }

    pub fn milestone(&'a mut self, milestone: String) -> &'a mut IssuesLister {
        self.internal.milestone = Some(milestone);
        self
    }

    pub fn labels(&'a mut self, labels: Vec<String>) -> &'a mut IssuesLister {
        self.internal.labels = Some(labels);
        self
    }

    pub fn order_by(&'a mut self, order_by: ::issues::ListingOrderBy) -> &'a mut IssuesLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut IssuesLister {
        self.internal.sort = Some(sort);
        self
    }

    /// Commit the lister: Query GitLab and return a list of issues.
    pub fn list(&self) -> Result<Issues> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for IssuesLister<'a> {
    fn build_query(&self) -> String {
        // NOTE: Can't use `serde_urlencoded` since it cannot serialize a Vec<T>
        //       See https://github.com/nox/serde_urlencoded/issues/6
        // let encoded = serde_urlencoded::to_string(&self.internal).unwrap();

        let mut query = format!("projects/{}/issues", self.id);
        let amp_char = "&";
        let comma_char = ",";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.internal.iid,
                              &self.internal.state,
                              &self.internal.labels,
                              &self.internal.milestone,
                              &self.internal.order_by,
                              &self.internal.sort) {
            (&None, &None, &None, &None, &None, &None) => "",
            _ => "?",
        });

        self.internal.iid.as_ref().map(|iid| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("iid=");
            query.push_str(&iid.to_string());
        });

        self.internal.state.map(|state| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("state=");
            query.push_str(match state {
                ::issues::State::Opened => "opened",
                ::issues::State::Closed => "closed",
            });
        });

        self.internal.labels.as_ref().map(|labels| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("labels=");

            let mut array_split_char = &none_char;
            for label in labels {
                query.push_str(array_split_char);
                query.push_str(&label.to_string());
                array_split_char = &comma_char;
            }
        });

        self.internal.milestone.as_ref().map(|milestone| {
            query.push_str(split_char);
            split_char = &amp_char;

            let params = &[("milestone", milestone)];
            query.push_str(&serde_urlencoded::to_string(&params).unwrap());
        });

        self.internal.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ::issues::ListingOrderBy::CreatedAt => "created_at",
                ::issues::ListingOrderBy::UpdatedAt => "updated_at",
            });
        });

        self.internal.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        query
    }
}

#[cfg(test)]
mod tests {
    use BuildQuery;

    const TEST_PROJECT_ID: i64 = 123;

    #[test]
    fn build_query_default() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues", TEST_PROJECT_ID);

        let lister = gl.issues();
        let lister = lister.project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let lister = gl.issues().project(TEST_PROJECT_ID);
        let query = lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.issues().project(TEST_PROJECT_ID).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_iid() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?iid=42", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).iid(42).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_milestone() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?milestone=Test+Milestone", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).milestone("Test Milestone".to_string()).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_state() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?state=opened", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Opened).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?state=closed", TEST_PROJECT_ID);
        let query =
            gl.issues().project(TEST_PROJECT_ID).state(::issues::State::Closed).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_skip_groups() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?labels=label1,label2,label3",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .labels(vec![String::from("label1"), String::from("label2"), String::from("label3")])
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?order_by=updated_at", TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .order_by(::issues::ListingOrderBy::UpdatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?sort=asc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = format!("projects/{}/issues?sort=desc", TEST_PROJECT_ID);
        let query = gl.issues().project(TEST_PROJECT_ID).sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = format!("projects/{}/issues?order_by=created_at&sort=asc",
                                      TEST_PROJECT_ID);
        let query = gl.issues()
            .project(TEST_PROJECT_ID)
            .sort(::ListingSort::Asc)
            .order_by(::issues::ListingOrderBy::CreatedAt)
            .build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>#[doc = "
Operations on the ubiquitous `option` type.

Type `option` represents an optional value.

Every `option<T>` value can either be `some(T)` or `none`. Where in other
languages you might use a nullable type, in Rust you would use an option type.
"];

#[doc = "The option type"]
enum option<T> {
    none,
    some(T),
}

pure fn get<T: copy>(opt: option<T>) -> T {
    #[doc = "
    Gets the value out of an option

    # Failure

    Fails if the value equals `none`
    "];

    alt opt { some(x) { ret x; } none { fail "option none"; } }
}

pure fn map<T, U: copy>(opt: option<T>, f: fn(T) -> U) -> option<U> {
    #[doc = "Maps a `some` value from one type to another"];

    alt opt { some(x) { some(f(x)) } none { none } }
}

pure fn chain<T, U>(opt: option<T>, f: fn(T) -> option<U>) -> option<U> {
    #[doc = "
    Update an optional value by optionally running its content through a
    function that returns an option.
    "];

    alt opt { some(x) { f(x) } none { none } }
}

pure fn is_none<T>(opt: option<T>) -> bool {
    #[doc = "Returns true if the option equals `none`"];

    alt opt { none { true } some(_) { false } }
}

pure fn is_some<T>(opt: option<T>) -> bool {
    #[doc = "Returns true if the option contains some value"];

    !is_none(opt)
}

pure fn get_default<T: copy>(opt: option<T>, def: T) -> T {
    #[doc = "Returns the contained value or a default"];

    alt opt { some(x) { x } none { def } }
}

pure fn map_default<T, U: copy>(opt: option<T>, def: U, f: fn(T) -> U) -> U {
    #[doc = "Applies a function to the contained value or returns a default"];

    alt opt { none { def } some(t) { f(t) } }
}

pure fn iter<T>(opt: option<T>, f: fn(T)) {
    #[doc = "Performs an operation on the contained value or does nothing"];

    alt opt { none { } some(t) { f(t); } }
}

pure fn unwrap<T>(-opt: option<T>) -> T {
    #[doc = "
    Moves a value out of an option type and returns it.

    Useful primarily for getting strings, vectors and unique pointers out of
    option types without copying them.
    "];

    unsafe {
        let addr = alt opt {
          some(x) { ptr::addr_of(x) }
          none { fail "option none" }
        };
        let liberated_value = unsafe::reinterpret_cast(*addr);
        unsafe::forget(opt);
        ret liberated_value;
    }
}

impl extensions<T> for option<T> {
    #[doc = "
    Update an optional value by optionally running its content through a
    function that returns an option.
    "]
    fn chain<U>(f: fn(T) -> option<U>) -> option<U> { chain(self, f) }
    #[doc = "Applies a function to the contained value or returns a default"]
    fn map_default<U: copy>(def: U, f: fn(T) -> U) -> U
        { map_default(self, def, f) }
    #[doc = "Performs an operation on the contained value or does nothing"]
    fn iter(f: fn(T)) { iter(self, f) }
    #[doc = "Returns true if the option equals `none`"]
    fn is_none() -> bool { is_none(self) }
    #[doc = "Returns true if the option contains some value"]
    fn is_some() -> bool { is_some(self) }
    #[doc = "Maps a `some` value from one type to another"]
    fn map<U:copy>(f: fn(T) -> U) -> option<U> { map(self, f) }
}

impl extensions<T: copy> for option<T> {
    #[doc = "
    Gets the value out of an option

    # Failure

    Fails if the value equals `none`
    "]
    fn get() -> T { get(self) }
    fn get_default(def: T) -> T { get_default(self, def) }
}

#[test]
fn test_unwrap_ptr() {
    let x = ~0;
    let addr_x = ptr::addr_of(*x);
    let opt = some(x);
    let y = unwrap(opt);
    let addr_y = ptr::addr_of(*y);
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_str() {
    let x = "test";
    let addr_x = str::as_buf(x, |buf| ptr::addr_of(buf));
    let opt = some(x);
    let y = unwrap(opt);
    let addr_y = str::as_buf(y, |buf| ptr::addr_of(buf));
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_resource() {
    class r {
       let i: @mut int;
       new(i: @mut int) { self.i = i; }
       drop { *(self.i) += 1; }
    }
    let i = @mut 0;
    {
        let x = r(i);
        let opt = some(x);
        let _y = unwrap(opt);
    }
    assert *i == 1;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>add option::expect and mark option methods as pure<commit_after>#[doc = "
Operations on the ubiquitous `option` type.

Type `option` represents an optional value.

Every `option<T>` value can either be `some(T)` or `none`. Where in other
languages you might use a nullable type, in Rust you would use an option type.
"];

#[doc = "The option type"]
enum option<T> {
    none,
    some(T),
}

pure fn get<T: copy>(opt: option<T>) -> T {
    #[doc = "
    Gets the value out of an option

    # Failure

    Fails if the value equals `none`
    "];

    alt opt { some(x) { ret x; } none { fail "option none"; } }
}

pure fn expect<T: copy>(opt: option<T>, reason: str) -> T {
    #[doc = "
    Gets the value out of an option, printing a specified message on failure

    # Failure

    Fails if the value equals `none`
    "];
    alt opt { some(x) { x } none { fail reason; } }
}

pure fn map<T, U: copy>(opt: option<T>, f: fn(T) -> U) -> option<U> {
    #[doc = "Maps a `some` value from one type to another"];

    alt opt { some(x) { some(f(x)) } none { none } }
}

pure fn chain<T, U>(opt: option<T>, f: fn(T) -> option<U>) -> option<U> {
    #[doc = "
    Update an optional value by optionally running its content through a
    function that returns an option.
    "];

    alt opt { some(x) { f(x) } none { none } }
}

pure fn is_none<T>(opt: option<T>) -> bool {
    #[doc = "Returns true if the option equals `none`"];

    alt opt { none { true } some(_) { false } }
}

pure fn is_some<T>(opt: option<T>) -> bool {
    #[doc = "Returns true if the option contains some value"];

    !is_none(opt)
}

pure fn get_default<T: copy>(opt: option<T>, def: T) -> T {
    #[doc = "Returns the contained value or a default"];

    alt opt { some(x) { x } none { def } }
}

pure fn map_default<T, U: copy>(opt: option<T>, def: U, f: fn(T) -> U) -> U {
    #[doc = "Applies a function to the contained value or returns a default"];

    alt opt { none { def } some(t) { f(t) } }
}

pure fn iter<T>(opt: option<T>, f: fn(T)) {
    #[doc = "Performs an operation on the contained value or does nothing"];

    alt opt { none { } some(t) { f(t); } }
}

pure fn unwrap<T>(-opt: option<T>) -> T {
    #[doc = "
    Moves a value out of an option type and returns it.

    Useful primarily for getting strings, vectors and unique pointers out of
    option types without copying them.
    "];

    unsafe {
        let addr = alt opt {
          some(x) { ptr::addr_of(x) }
          none { fail "option none" }
        };
        let liberated_value = unsafe::reinterpret_cast(*addr);
        unsafe::forget(opt);
        ret liberated_value;
    }
}

impl extensions<T> for option<T> {
    #[doc = "
    Update an optional value by optionally running its content through a
    function that returns an option.
    "]
    pure fn chain<U>(f: fn(T) -> option<U>) -> option<U> { chain(self, f) }
    #[doc = "Applies a function to the contained value or returns a default"]
    pure fn map_default<U: copy>(def: U, f: fn(T) -> U) -> U
        { map_default(self, def, f) }
    #[doc = "Performs an operation on the contained value or does nothing"]
    pure fn iter(f: fn(T)) { iter(self, f) }
    #[doc = "Returns true if the option equals `none`"]
    pure fn is_none() -> bool { is_none(self) }
    #[doc = "Returns true if the option contains some value"]
    pure fn is_some() -> bool { is_some(self) }
    #[doc = "Maps a `some` value from one type to another"]
    pure fn map<U:copy>(f: fn(T) -> U) -> option<U> { map(self, f) }
}

impl extensions<T: copy> for option<T> {
    #[doc = "
    Gets the value out of an option

    # Failure

    Fails if the value equals `none`
    "]
    pure fn get() -> T { get(self) }
    pure fn get_default(def: T) -> T { get_default(self, def) }
    #[doc = "
    Gets the value out of an option, printing a specified message on failure

    # Failure

    Fails if the value equals `none`
    "]
    pure fn expect<T: copy>(reason: str) -> T { expect(self, reason) }
}

#[test]
fn test_unwrap_ptr() {
    let x = ~0;
    let addr_x = ptr::addr_of(*x);
    let opt = some(x);
    let y = unwrap(opt);
    let addr_y = ptr::addr_of(*y);
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_str() {
    let x = "test";
    let addr_x = str::as_buf(x, |buf| ptr::addr_of(buf));
    let opt = some(x);
    let y = unwrap(opt);
    let addr_y = str::as_buf(y, |buf| ptr::addr_of(buf));
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_resource() {
    class r {
       let i: @mut int;
       new(i: @mut int) { self.i = i; }
       drop { *(self.i) += 1; }
    }
    let i = @mut 0;
    {
        let x = r(i);
        let opt = some(x);
        let _y = unwrap(opt);
    }
    assert *i == 1;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use std::{cmp, ptr};
use std::io::{self,Write,Read};
use std::iter::repeat;

pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity: capacity,
      position: 0,
      end:      0
    }
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut[u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub fn shift(&mut self) {
    if self.position > 0 {
      unsafe {
        let length = self.end - self.position;
        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
        self.position = 0;
        self.end      = length;
      }
    }
  }

  pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
    if start + length >= self.available_data() {
      return None
    }

    unsafe {
      let begin    = self.position + start;
      let next_end = self.end - length;
      ptr::copy( (&self.memory[begin+length..self.end]).as_ptr(), (&mut self.memory[begin..next_end]).as_mut_ptr(), length);
      self.end = next_end;
    }
    Some(self.available_data())
  }

  pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
    let data_len = data.len();
    if start + length > self.available_data() ||
      self.position + start + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      // we reduced the data size
      if data_len < length {
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);

        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
        self.end = self.end - (length - data_len);

      // we put more data in the buffer
      } else {
        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
        self.end = self.end + data_len - length;
      }
    }
    Some(self.available_data())
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.space().write(buf) {
      Ok(size) => { self.fill(size); Ok(size) },
      err      => err
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    unsafe {
      ptr::copy((&self.memory[self.position..len]).as_ptr(), buf.as_mut_ptr(), len);
      self.position += len;
    }
    Ok(len)
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }

  #[test]
  fn delete() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.delete_slice(2, 3), Some(5));
    assert_eq!(b.available_data(), 5);
    assert_eq!(b.available_space(), 5);
    assert_eq!(b.data(), &b"abfgh"[..]);

    assert_eq!(b.delete_slice(5, 2), None);
    assert_eq!(b.delete_slice(4, 2), None);
  }

  #[test]
  fn replace() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"abABCfgh"[..]);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
    assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
    assert_eq!(b.available_data(), 7);
    assert_eq!(b.available_space(), 3);
    assert_eq!(b.data(), &b"abXYZgh"[..]);

    assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"ab123Zgh"[..]);
  }
}
<commit_msg>Reset the buffer position on shift and consume if necessary<commit_after>use std::{cmp, ptr};
use std::io::{self,Write,Read};
use std::iter::repeat;

pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity: capacity,
      position: 0,
      end:      0
    }
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      //println!("consume shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    if self.available_space() < self.available_data() + cnt {
      //println!("fill shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }

    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut[u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub fn shift(&mut self) {
    if self.position > 0 {
      unsafe {
        let length = self.end - self.position;
        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
        self.position = 0;
        self.end      = length;
      }
    }
  }

  pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
    if start + length >= self.available_data() {
      return None
    }

    unsafe {
      let begin    = self.position + start;
      let next_end = self.end - length;
      ptr::copy( (&self.memory[begin+length..self.end]).as_ptr(), (&mut self.memory[begin..next_end]).as_mut_ptr(), length);
      self.end = next_end;
    }
    Some(self.available_data())
  }

  pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
    let data_len = data.len();
    if start + length > self.available_data() ||
      self.position + start + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      // we reduced the data size
      if data_len < length {
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);

        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
        self.end = self.end - (length - data_len);

      // we put more data in the buffer
      } else {
        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
        self.end = self.end + data_len - length;
      }
    }
    Some(self.available_data())
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.space().write(buf) {
      Ok(size) => { self.fill(size); Ok(size) },
      err      => err
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    unsafe {
      ptr::copy((&self.memory[self.position..len]).as_ptr(), buf.as_mut_ptr(), len);
      self.position += len;
    }
    Ok(len)
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }

  #[test]
  fn delete() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.delete_slice(2, 3), Some(5));
    assert_eq!(b.available_data(), 5);
    assert_eq!(b.available_space(), 5);
    assert_eq!(b.data(), &b"abfgh"[..]);

    assert_eq!(b.delete_slice(5, 2), None);
    assert_eq!(b.delete_slice(4, 2), None);
  }

  #[test]
  fn replace() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"abABCfgh"[..]);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
    assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
    assert_eq!(b.available_data(), 7);
    assert_eq!(b.available_space(), 3);
    assert_eq!(b.data(), &b"abXYZgh"[..]);

    assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"ab123Zgh"[..]);
  }
}
<|endoftext|>


<commit_before>#[repr(i32)]
pub enum Extend {
  None = 0,
  Repeat = 1,
  Reflect = 2
}
<commit_msg>Copied Cairo documentation for extend<commit_after>//! Describe color/alpha for areas "outside" pattern's natural area

///  cairo_extend_t is used to describe how pattern color/alpha will be determined for areas "outside" the pattern's natural area, (for example, outside the surface bounds or outside the gradient geometry).
///
/// Mesh patterns are not affected by the extend mode.
///
/// The default extend mode is CAIRO_EXTEND_NONE for surface patterns and CAIRO_EXTEND_PAD for gradient patterns.
///
/// New entries may be added in future versions.
///
/// Since 1.0
#[repr(i32)]
pub enum Extend {
  /// pixels outside of the source pattern are fully transparent (Since 1.0)
  None = 0,
  /// the pattern is tiled by repeating (Since 1.0)
  Repeat = 1,
  /// the pattern is tiled by reflecting at the edges (Since 1.0; but only implemented for surface patterns since 1.6)
  Reflect = 2,
  /// pixels outside of the pattern copy the closest pixel from the source (Since 1.2; but only implemented for surface patterns since 1.6)
  Pad = 3,
}

<|endoftext|>