<commit_before>#[link(name = "sdl_ttf",
       vers = "0.1",
       uuid = "1d776704-431f-4d5b-9361-b27958535321",
       url = "http://github.com/sfackler/rust-sdl_ttf")];

#[comment="SDL_ttf bindings"];
#[license="MIT"];
#[crate_type="lib"];

extern mod sdl;

use std::cast;
use std::libc::{c_int, c_long};
use std::str;

use sdl::video::{Color, Surface};

mod ffi {
    use std::libc::{c_int, c_char, c_void, c_long};
    use sdl::video::ll::{SDL_Color, SDL_Surface};

    pub type TTF_Font = c_void;

    pub type TTF_StyleFlag = c_int;
    pub static TTF_STYLE_NORMAL: TTF_StyleFlag = 0x00;
    pub static TTF_STYLE_BOLD: TTF_StyleFlag = 0x01;
    pub static TTF_STYLE_ITALIC: TTF_StyleFlag = 0x02;
    pub static TTF_STYLE_UNDERLINE: c_int = 0x04;
    pub static TTF_STYLE_STRIKETHROUGH: c_int = 0x08;

    pub type TTF_Hinting = c_int;
    pub static TTF_HINTING_NORMAL: TTF_Hinting = 0;
    pub static TTF_HINTING_LIGHT: TTF_Hinting = 1;
    pub static TTF_HINTING_MONO: TTF_Hinting = 2;
    pub static TTF_HINTING_NONE: TTF_Hinting = 3;

    #[link_args = "-lSDL_ttf"]
    extern "C" {
        fn TTF_Init() -> c_int;
        fn TTF_WasInit() -> c_int;
        fn TTF_Quit();
        fn TTF_OpenFont(file: *c_char, ptsize: c_int) -> *TTF_Font;
        fn TTF_OpenFontIndex(file: *c_char, ptsize: c_int, index: c_long)
            -> *TTF_Font;
        fn TTF_CloseFont(font: *TTF_Font);

        fn TTF_GetFontStyle(font: *TTF_Font) -> TTF_StyleFlag;
        fn TTF_SetFontStyle(font: *TTF_Font, style: TTF_StyleFlag);
        fn TTF_GetFontOutline(font: *TTF_Font) -> c_int;
        fn TTF_SetFontOutline(font: *TTF_Font, outline: c_int);
        fn TTF_GetFontHinting(font: *TTF_Font) -> TTF_Hinting;
        fn TTF_SetFontHinting(font: *TTF_Font, hinting: TTF_Hinting);
        fn TTF_GetFontKerning(font: *TTF_Font) -> c_int;
        fn TTF_SetFontKerning(font: *TTF_Font, kerning: c_int);
        fn TTF_FontHeight(font: *TTF_Font) -> c_int;
        fn TTF_FontAscent(font: *TTF_Font) -> c_int;
        fn TTF_FontDescent(font: *TTF_Font) -> c_int;
        fn TTF_FontLineSkip(font: *TTF_Font) -> c_int;
        fn TTF_FontFaces(font: *TTF_Font) -> c_long;
        fn TTF_FontFaceIsFixedWidth(font: *TTF_Font) -> c_int;
        fn TTF_FontFaceFamilyName(font: *TTF_Font) -> *c_char;
        fn TTF_FontGlyphIsProvided(font: *TTF_Font, glyph: u16) -> c_int;
        fn TTF_GlyphMetrics(font: *TTF_Font, glyph: u16, minx: *mut c_int,
            maxx: *mut c_int, miny: *mut c_int, maxy: *mut c_int,
            advance: *mut c_int) -> c_int;
        fn TTF_SizeUTF8(font: *TTF_Font, text: *c_char, w: *mut c_int,
            h: *mut c_int) -> c_int;

        fn TTF_RenderUTF8_Solid(font: *TTF_Font, text: *c_char,
            fg: SDL_Color) -> *SDL_Surface;
        fn TTF_RenderUTF8_Shaded(font: *TTF_Font, text: *c_char,
            fg: SDL_Color, bg: SDL_Color) -> *SDL_Surface;
        fn TTF_RenderUTF8_Blended(font: *TTF_Font, text: *c_char,
            fg: SDL_Color) -> *SDL_Surface;
    }
}

pub enum FontStyle {
    NormalStyle = ffi::TTF_STYLE_NORMAL as int,
    BoldStyle = ffi::TTF_STYLE_BOLD as int,
    ItalicStyle = ffi::TTF_STYLE_ITALIC as int,
    UnderlineStyle = ffi::TTF_STYLE_UNDERLINE as int,
    StrikethroughStyle = ffi::TTF_STYLE_STRIKETHROUGH as int
}

pub enum FontHinting {
    NormalHinting = ffi::TTF_HINTING_NORMAL as int,
    LightHinting = ffi::TTF_HINTING_LIGHT as int,
    MonoHinting = ffi::TTF_HINTING_MONO as int,
    NoneHinting = ffi::TTF_HINTING_NONE as int
}

pub struct GlyphMetrics {
    minx: int,
    maxx: int,
    miny: int,
    maxy: int,
    advance: int
}

pub struct Font {
    priv raw: *ffi::TTF_Font
}

impl Drop for Font {
    #[fixed_stack_segment]
    fn drop(&self) {
        unsafe {
            ffi::TTF_CloseFont(self.raw);
        }
    }
}

impl Font {
    #[fixed_stack_segment]
    pub fn get_style(&self) -> ~[FontStyle] {
        let bitflags = unsafe { ffi::TTF_GetFontStyle(self.raw) };

        let flags = [
            NormalStyle,
            BoldStyle,
            ItalicStyle,
            UnderlineStyle,
            StrikethroughStyle
        ];

        do flags.iter().filter_map |&flag| {
            if bitflags & (flag as ffi::TTF_StyleFlag) != 0 { Some(flag) }
            else {None}
        }.collect()
    }

    #[fixed_stack_segment]
    pub fn set_style(&mut self, flags: &[FontStyle]) {
        let bitflags = do flags.iter().fold(0) |bitflags, &flag| {
            bitflags | flag as ffi::TTF_StyleFlag
        };

        unsafe {
            ffi::TTF_SetFontStyle(self.raw, bitflags);
        }
    }

    #[fixed_stack_segment]
    pub fn get_outline(&self) -> int {
        unsafe {
            ffi::TTF_GetFontOutline(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn set_outline(&mut self, outline: int) {
        unsafe {
            ffi::TTF_SetFontOutline(self.raw, outline as c_int);
        }
    }

    #[fixed_stack_segment]
    pub fn get_hinting(&self) -> FontHinting {
        unsafe {
            cast::transmute(ffi::TTF_GetFontHinting(self.raw) as int)
        }
    }

    #[fixed_stack_segment]
    pub fn set_hinting(&mut self, hinting: FontHinting) {
        unsafe {
            ffi::TTF_SetFontHinting(self.raw, hinting as ffi::TTF_Hinting);
        }
    }

    #[fixed_stack_segment]
    pub fn get_kerning(&self) -> int {
        unsafe {
            ffi::TTF_GetFontKerning(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn set_kerning(&mut self, kerning: int) {
        unsafe {
            ffi::TTF_SetFontKerning(self.raw, kerning as c_int);
        }
    }

    #[fixed_stack_segment]
    pub fn height(&self) -> int {
        unsafe {
            ffi::TTF_FontHeight(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn ascent(&self) -> int {
        unsafe {
            ffi::TTF_FontAscent(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn descent(&self) -> int {
        unsafe {
            ffi::TTF_FontDescent(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn line_skip(&self) -> int {
        unsafe {
            ffi::TTF_FontLineSkip(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn faces(&self) -> int {
        unsafe {
            ffi::TTF_FontFaces(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn face_is_fixed_width(&self) -> bool {
        unsafe {
            ffi::TTF_FontFaceIsFixedWidth(self.raw) > 0
        }
    }

    #[fixed_stack_segment]
    pub fn face_family_name(&self) -> Option<~str> {
        unsafe {
            let ptr = ffi::TTF_FontFaceFamilyName(self.raw);

            if ptr.is_null() {
                None
            } else {
                Some(str::raw::from_c_str(ptr))
            }
        }
    }

    #[fixed_stack_segment]
    pub fn glyph_is_provided(&self, glyph: char) -> Option<int> {
        let ch = match char_to_utf16(glyph) {
            Some(ch) => ch,
            None => return None
        };

        unsafe {
            match ffi::TTF_FontGlyphIsProvided(self.raw, ch) {
                0 => None,
                ch => Some(ch as int)
            }
        }
    }

    #[fixed_stack_segment]
    pub fn glyph_metrics(&self, glyph: char) -> Result<~GlyphMetrics, ~str> {
        let ch = match char_to_utf16(glyph) {
            Some(ch) => ch,
            None => return Err(~"Glyph is not a UTF-16 character")
        };

        let mut minx: c_int = 0;
        let mut maxx: c_int = 0;
        let mut miny: c_int = 0;
        let mut maxy: c_int = 0;
        let mut advance: c_int = 0;

        unsafe {
            match ffi::TTF_GlyphMetrics(self.raw, ch, &mut minx, &mut maxx,
                    &mut miny, &mut maxy, &mut advance) {
                0 => Ok(~GlyphMetrics {minx: minx as int, maxx: maxx as int,
                    miny: miny as int, maxy: maxy as int,
                    advance: advance as int}),
                _ => Err(sdl::get_error())
            }
        }
    }

    #[fixed_stack_segment]
    pub fn text_size(&self, text: &str) -> Result<(int, int), ~str> {
        let mut w: c_int = 0;
        let mut h: c_int = 0;

        do text.with_c_str |c_text| {
            unsafe {
                match ffi::TTF_SizeUTF8(self.raw, c_text, &mut w, &mut h) {
                    0 => Ok((w as int, h as int)),
                    _ => Err(sdl::get_error())
                }
            }
        }
    }
}

fn char_to_utf16(glyph: char) -> Option<u16> {
    // TODO bounds checking
    if !str::is_utf16([glyph as u16]) {
        return None;
    }

    Some(str::from_char(glyph).to_utf16()[0])
}

#[fixed_stack_segment]
pub fn init() -> bool {
    unsafe {
        ffi::TTF_Init() == 0
    }
}

#[fixed_stack_segment]
pub fn was_init() -> bool {
    unsafe {
        ffi::TTF_WasInit() == 1
    }
}

#[fixed_stack_segment]
pub fn quit() {
    unsafe {
        ffi::TTF_Quit();
    }
}

#[fixed_stack_segment]
pub fn open_font(file: &str, ptsize: int) -> Result<~Font, ~str> {
    do file.with_c_str |c_str| {
        unsafe {
            let ptr = ffi::TTF_OpenFont(c_str, ptsize as c_int);
            if ptr.is_null() {
                Err(sdl::get_error())
            } else {
                Ok(~Font {raw: ptr})
            }
        }
    }
}

#[fixed_stack_segment]
pub fn open_font_index(file: &str, ptsize: int, index: int)
        -> Result<~Font, ~str> {
    do file.with_c_str |c_str| {
        let ptr = unsafe {
            ffi::TTF_OpenFontIndex(c_str, ptsize as c_int, index as c_long)
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Font {raw: ptr})
        }
    }
}

#[fixed_stack_segment]
pub fn render_solid(font: &Font, text: &str, fg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Solid(font.raw, c_text, fg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}

#[fixed_stack_segment]
pub fn render_shaded(font: &Font, text: &str, fg: Color, bg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Shaded(font.raw, c_text, fg.to_struct(),
                bg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}

#[fixed_stack_segment]
pub fn render_blended(font: &Font, text: &str, fg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Blended(font.raw, c_text, fg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}
<commit_msg>Fix for latest rust master<commit_after>#[link(name = "sdl_ttf",
       vers = "0.1",
       uuid = "1d776704-431f-4d5b-9361-b27958535321",
       url = "http://github.com/sfackler/rust-sdl_ttf")];

#[comment="SDL_ttf bindings"];
#[license="MIT"];
#[crate_type="lib"];

extern mod sdl;

use std::cast;
use std::libc::{c_int, c_long};
use std::str;

use sdl::video::{Color, Surface};

mod ffi {
    use std::libc::{c_int, c_char, c_void, c_long};
    use sdl::video::ll::{SDL_Color, SDL_Surface};

    pub type TTF_Font = c_void;

    pub type TTF_StyleFlag = c_int;
    pub static TTF_STYLE_NORMAL: TTF_StyleFlag = 0x00;
    pub static TTF_STYLE_BOLD: TTF_StyleFlag = 0x01;
    pub static TTF_STYLE_ITALIC: TTF_StyleFlag = 0x02;
    pub static TTF_STYLE_UNDERLINE: c_int = 0x04;
    pub static TTF_STYLE_STRIKETHROUGH: c_int = 0x08;

    pub type TTF_Hinting = c_int;
    pub static TTF_HINTING_NORMAL: TTF_Hinting = 0;
    pub static TTF_HINTING_LIGHT: TTF_Hinting = 1;
    pub static TTF_HINTING_MONO: TTF_Hinting = 2;
    pub static TTF_HINTING_NONE: TTF_Hinting = 3;

    #[link_args = "-lSDL_ttf"]
    extern "C" {
        fn TTF_Init() -> c_int;
        fn TTF_WasInit() -> c_int;
        fn TTF_Quit();
        fn TTF_OpenFont(file: *c_char, ptsize: c_int) -> *TTF_Font;
        fn TTF_OpenFontIndex(file: *c_char, ptsize: c_int, index: c_long)
            -> *TTF_Font;
        fn TTF_CloseFont(font: *TTF_Font);

        fn TTF_GetFontStyle(font: *TTF_Font) -> TTF_StyleFlag;
        fn TTF_SetFontStyle(font: *TTF_Font, style: TTF_StyleFlag);
        fn TTF_GetFontOutline(font: *TTF_Font) -> c_int;
        fn TTF_SetFontOutline(font: *TTF_Font, outline: c_int);
        fn TTF_GetFontHinting(font: *TTF_Font) -> TTF_Hinting;
        fn TTF_SetFontHinting(font: *TTF_Font, hinting: TTF_Hinting);
        fn TTF_GetFontKerning(font: *TTF_Font) -> c_int;
        fn TTF_SetFontKerning(font: *TTF_Font, kerning: c_int);
        fn TTF_FontHeight(font: *TTF_Font) -> c_int;
        fn TTF_FontAscent(font: *TTF_Font) -> c_int;
        fn TTF_FontDescent(font: *TTF_Font) -> c_int;
        fn TTF_FontLineSkip(font: *TTF_Font) -> c_int;
        fn TTF_FontFaces(font: *TTF_Font) -> c_long;
        fn TTF_FontFaceIsFixedWidth(font: *TTF_Font) -> c_int;
        fn TTF_FontFaceFamilyName(font: *TTF_Font) -> *c_char;
        fn TTF_FontGlyphIsProvided(font: *TTF_Font, glyph: u16) -> c_int;
        fn TTF_GlyphMetrics(font: *TTF_Font, glyph: u16, minx: *mut c_int,
            maxx: *mut c_int, miny: *mut c_int, maxy: *mut c_int,
            advance: *mut c_int) -> c_int;
        fn TTF_SizeUTF8(font: *TTF_Font, text: *c_char, w: *mut c_int,
            h: *mut c_int) -> c_int;

        fn TTF_RenderUTF8_Solid(font: *TTF_Font, text: *c_char,
            fg: SDL_Color) -> *SDL_Surface;
        fn TTF_RenderUTF8_Shaded(font: *TTF_Font, text: *c_char,
            fg: SDL_Color, bg: SDL_Color) -> *SDL_Surface;
        fn TTF_RenderUTF8_Blended(font: *TTF_Font, text: *c_char,
            fg: SDL_Color) -> *SDL_Surface;
    }
}

pub enum FontStyle {
    NormalStyle = ffi::TTF_STYLE_NORMAL as int,
    BoldStyle = ffi::TTF_STYLE_BOLD as int,
    ItalicStyle = ffi::TTF_STYLE_ITALIC as int,
    UnderlineStyle = ffi::TTF_STYLE_UNDERLINE as int,
    StrikethroughStyle = ffi::TTF_STYLE_STRIKETHROUGH as int
}

pub enum FontHinting {
    NormalHinting = ffi::TTF_HINTING_NORMAL as int,
    LightHinting = ffi::TTF_HINTING_LIGHT as int,
    MonoHinting = ffi::TTF_HINTING_MONO as int,
    NoneHinting = ffi::TTF_HINTING_NONE as int
}

pub struct GlyphMetrics {
    minx: int,
    maxx: int,
    miny: int,
    maxy: int,
    advance: int
}

pub struct Font {
    priv raw: *ffi::TTF_Font
}

impl Drop for Font {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            ffi::TTF_CloseFont(self.raw);
        }
    }
}

impl Font {
    #[fixed_stack_segment]
    pub fn get_style(&self) -> ~[FontStyle] {
        let bitflags = unsafe { ffi::TTF_GetFontStyle(self.raw) };

        let flags = [
            NormalStyle,
            BoldStyle,
            ItalicStyle,
            UnderlineStyle,
            StrikethroughStyle
        ];

        do flags.iter().filter_map |&flag| {
            if bitflags & (flag as ffi::TTF_StyleFlag) != 0 { Some(flag) }
            else {None}
        }.collect()
    }

    #[fixed_stack_segment]
    pub fn set_style(&mut self, flags: &[FontStyle]) {
        let bitflags = do flags.iter().fold(0) |bitflags, &flag| {
            bitflags | flag as ffi::TTF_StyleFlag
        };

        unsafe {
            ffi::TTF_SetFontStyle(self.raw, bitflags);
        }
    }

    #[fixed_stack_segment]
    pub fn get_outline(&self) -> int {
        unsafe {
            ffi::TTF_GetFontOutline(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn set_outline(&mut self, outline: int) {
        unsafe {
            ffi::TTF_SetFontOutline(self.raw, outline as c_int);
        }
    }

    #[fixed_stack_segment]
    pub fn get_hinting(&self) -> FontHinting {
        unsafe {
            cast::transmute(ffi::TTF_GetFontHinting(self.raw) as int)
        }
    }

    #[fixed_stack_segment]
    pub fn set_hinting(&mut self, hinting: FontHinting) {
        unsafe {
            ffi::TTF_SetFontHinting(self.raw, hinting as ffi::TTF_Hinting);
        }
    }

    #[fixed_stack_segment]
    pub fn get_kerning(&self) -> int {
        unsafe {
            ffi::TTF_GetFontKerning(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn set_kerning(&mut self, kerning: int) {
        unsafe {
            ffi::TTF_SetFontKerning(self.raw, kerning as c_int);
        }
    }

    #[fixed_stack_segment]
    pub fn height(&self) -> int {
        unsafe {
            ffi::TTF_FontHeight(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn ascent(&self) -> int {
        unsafe {
            ffi::TTF_FontAscent(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn descent(&self) -> int {
        unsafe {
            ffi::TTF_FontDescent(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn line_skip(&self) -> int {
        unsafe {
            ffi::TTF_FontLineSkip(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn faces(&self) -> int {
        unsafe {
            ffi::TTF_FontFaces(self.raw) as int
        }
    }

    #[fixed_stack_segment]
    pub fn face_is_fixed_width(&self) -> bool {
        unsafe {
            ffi::TTF_FontFaceIsFixedWidth(self.raw) > 0
        }
    }

    #[fixed_stack_segment]
    pub fn face_family_name(&self) -> Option<~str> {
        unsafe {
            let ptr = ffi::TTF_FontFaceFamilyName(self.raw);

            if ptr.is_null() {
                None
            } else {
                Some(str::raw::from_c_str(ptr))
            }
        }
    }

    #[fixed_stack_segment]
    pub fn glyph_is_provided(&self, glyph: char) -> Option<int> {
        let ch = match char_to_utf16(glyph) {
            Some(ch) => ch,
            None => return None
        };

        unsafe {
            match ffi::TTF_FontGlyphIsProvided(self.raw, ch) {
                0 => None,
                ch => Some(ch as int)
            }
        }
    }

    #[fixed_stack_segment]
    pub fn glyph_metrics(&self, glyph: char) -> Result<~GlyphMetrics, ~str> {
        let ch = match char_to_utf16(glyph) {
            Some(ch) => ch,
            None => return Err(~"Glyph is not a UTF-16 character")
        };

        let mut minx: c_int = 0;
        let mut maxx: c_int = 0;
        let mut miny: c_int = 0;
        let mut maxy: c_int = 0;
        let mut advance: c_int = 0;

        unsafe {
            match ffi::TTF_GlyphMetrics(self.raw, ch, &mut minx, &mut maxx,
                    &mut miny, &mut maxy, &mut advance) {
                0 => Ok(~GlyphMetrics {minx: minx as int, maxx: maxx as int,
                    miny: miny as int, maxy: maxy as int,
                    advance: advance as int}),
                _ => Err(sdl::get_error())
            }
        }
    }

    #[fixed_stack_segment]
    pub fn text_size(&self, text: &str) -> Result<(int, int), ~str> {
        let mut w: c_int = 0;
        let mut h: c_int = 0;

        do text.with_c_str |c_text| {
            unsafe {
                match ffi::TTF_SizeUTF8(self.raw, c_text, &mut w, &mut h) {
                    0 => Ok((w as int, h as int)),
                    _ => Err(sdl::get_error())
                }
            }
        }
    }
}

fn char_to_utf16(glyph: char) -> Option<u16> {
    // TODO bounds checking
    if !str::is_utf16([glyph as u16]) {
        return None;
    }

    Some(str::from_char(glyph).to_utf16()[0])
}

#[fixed_stack_segment]
pub fn init() -> bool {
    unsafe {
        ffi::TTF_Init() == 0
    }
}

#[fixed_stack_segment]
pub fn was_init() -> bool {
    unsafe {
        ffi::TTF_WasInit() == 1
    }
}

#[fixed_stack_segment]
pub fn quit() {
    unsafe {
        ffi::TTF_Quit();
    }
}

#[fixed_stack_segment]
pub fn open_font(file: &str, ptsize: int) -> Result<~Font, ~str> {
    do file.with_c_str |c_str| {
        unsafe {
            let ptr = ffi::TTF_OpenFont(c_str, ptsize as c_int);
            if ptr.is_null() {
                Err(sdl::get_error())
            } else {
                Ok(~Font {raw: ptr})
            }
        }
    }
}

#[fixed_stack_segment]
pub fn open_font_index(file: &str, ptsize: int, index: int)
        -> Result<~Font, ~str> {
    do file.with_c_str |c_str| {
        let ptr = unsafe {
            ffi::TTF_OpenFontIndex(c_str, ptsize as c_int, index as c_long)
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Font {raw: ptr})
        }
    }
}

#[fixed_stack_segment]
pub fn render_solid(font: &Font, text: &str, fg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Solid(font.raw, c_text, fg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}

#[fixed_stack_segment]
pub fn render_shaded(font: &Font, text: &str, fg: Color, bg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Shaded(font.raw, c_text, fg.to_struct(),
                bg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}

#[fixed_stack_segment]
pub fn render_blended(font: &Font, text: &str, fg: Color)
        -> Result<~Surface, ~str> {
    do text.with_c_str |c_text| {
        let ptr = unsafe {
            ffi::TTF_RenderUTF8_Blended(font.raw, c_text, fg.to_struct())
        };

        if ptr.is_null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface {raw: ptr, owned: true})
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#![macro_escape]

// use std;
// use gl;
// use gl::types::{GLuint, GLsizeiptr};
// use cgmath::{Vector3, rad, ortho};
// use core_misc::deg_to_rad;
// use core_types::{Size2, MInt};
// use visualizer::types::{MFloat, Color3, Color4, ScreenPos};
use visualizer_types::{/*MFloat,*/ Color3};
// use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4};
use libc::c_void;
use gl;
use gl::types::{GLuint, GLint, GLenum};
use std::ptr;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub struct Mgl {
    pub gl: gl::Gles2,
}

impl Mgl {
    pub fn new(get_proc_address: |&str| -> *const c_void) -> Mgl {
        let gl = gl::Gles2::load_with(|s| get_proc_address(s));
    	Mgl{gl: gl}
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    /*
    pub fn set_viewport(&mut self, size: Size2<MInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    pub fn tr(&self, m: Matrix4<MFloat>, v: Vector3<MFloat>) -> Matrix4<MFloat> {
        let mut t = Matrix4::<MFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    pub fn scale(&self, m: Matrix4<MFloat>, scale: MFloat) -> Matrix4<MFloat> {
        let mut t = Matrix4::<MFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }

    pub fn rot_x(&self, m: Matrix4<MFloat>, angle: MFloat) -> Matrix4<MFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<MFloat>, angle: MFloat) -> Matrix4<MFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }
    */

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }
}

/*
pub enum MeshRenderMode {
    Triangles,
    Lines,
}

impl MeshRenderMode {
    fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            MeshRenderMode::Lines => gl::LINES,
        }
    }
}
*/

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

/*
pub struct Vao {
    id: GLuint,
}

impl Vao {
    pub fn new(mgl: &Mgl) -> Vao {
        let mut id = 0;
        unsafe {
            mgl.gl.GenVertexArrays(1, &mut id);
        }
        mgl.check();
        let vao = Vao{id: id};
        vao.bind();
        vao
    }

    pub fn bind(&self) {
        gl.BindVertexArray(self.id);
        mgl.check();
    }

    pub fn unbind(&self) {
        gl.BindVertexArray(0);
        mgl.check();
    }

    pub fn draw_array(&self, mesh_mode: MeshRenderMode, faces_count: MInt) {
        let starting_index = 0;
        let vertices_count = faces_count * 3;
        let mode = mesh_mode.to_gl_type();
        gl.DrawArrays(mode, starting_index, vertices_count);
        mgl.check();
    }
}

impl Drop for Vao {
    fn drop(&mut self) {
        unsafe {
            gl.DeleteVertexArrays(1, &self.id);
        }
        mgl.check();
    }
}
*/

/*
pub struct Vbo {
    id: GLuint,
}

fn get_new_vbo_id() -> GLuint {
    let mut id = 0;
    unsafe {
        verify!(gl::GenBuffers(1, &mut id));
    }
    id
}

impl Vbo {
    pub fn from_data<T>(data: &[T]) -> Vbo {
        let vbo = Vbo{id: get_new_vbo_id()};
        vbo.bind();
        let size = std::mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = std::mem::transmute(&data[0]);
                verify!(gl::BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                ));
            }
        }
        vbo
    }

    pub fn bind(&self) {
        verify!(gl::BindBuffer(gl::ARRAY_BUFFER, self.id));
    }
}

impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn read_pixel_bytes(
    win_size: Size2<MInt>,
    mouse_pos: ScreenPos,
) -> (MInt, MInt, MInt, MInt) {
    let height = win_size.h;
    let reverted_h = height - mouse_pos.v.y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
        let data_ptr = std::mem::transmute(&data[0]);
        verify!(gl::ReadPixels(
            mouse_pos.v.x, reverted_h, 1, 1,
            gl::RGBA,
            gl::UNSIGNED_BYTE,
            data_ptr
        ));
    }
    (data[0] as MInt, data[1] as MInt, data[2] as MInt, data[3] as MInt)
}

pub fn get_2d_screen_matrix(win_size: Size2<MInt>) -> Matrix4<MFloat> {
    let left = 0.0;
    let right = win_size.w as MFloat;
    let bottom = 0.0;
    let top = win_size.h as MFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

pub fn compile_shader(gl: &gl::Gles2, src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl.CreateShader(ty);
        src.with_c_str(|ptr| gl.ShaderSource(shader, 1, &ptr, ptr::null()));
        gl.CompileShader(shader);
        {
            let mut status = gl::FALSE as GLint;
            gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
            assert!(status == gl::TRUE as GLint);
        }
    }
    shader
}

// TODO: Gles2 -> Gl
pub fn link_program(gl: &gl::Gles2, vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let program = gl.CreateProgram();
        gl.AttachShader(program, vs);
        gl.AttachShader(program, fs);
        gl.LinkProgram(program);
        {
            let mut status = gl::FALSE as GLint;
            gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);
            assert!(status == (gl::TRUE as GLint));
        }
        program
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/mgl.rs: 'use gl::Gles2 as Gl;'<commit_after>// See LICENSE file for copyright and license details.

#![macro_escape]

// use std;
// use gl;
// use gl::types::{GLuint, GLsizeiptr};
// use cgmath::{Vector3, rad, ortho};
// use core_misc::deg_to_rad;
// use core_types::{Size2, MInt};
// use visualizer::types::{MFloat, Color3, Color4, ScreenPos};
use visualizer_types::{/*MFloat,*/ Color3};
// use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4};
use libc::c_void;
use gl;
use gl::types::{GLuint, GLint, GLenum};
use std::ptr;

use gl::Gles2 as Gl;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub struct Mgl {
    pub gl: Gl,
}

impl Mgl {
    pub fn new(get_proc_address: |&str| -> *const c_void) -> Mgl {
        let gl = Gl::load_with(|s| get_proc_address(s));
    	Mgl{gl: gl}
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    /*
    pub fn set_viewport(&mut self, size: Size2<MInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    pub fn tr(&self, m: Matrix4<MFloat>, v: Vector3<MFloat>) -> Matrix4<MFloat> {
        let mut t = Matrix4::<MFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    pub fn scale(&self, m: Matrix4<MFloat>, scale: MFloat) -> Matrix4<MFloat> {
        let mut t = Matrix4::<MFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }

    pub fn rot_x(&self, m: Matrix4<MFloat>, angle: MFloat) -> Matrix4<MFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<MFloat>, angle: MFloat) -> Matrix4<MFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }
    */

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }
}

/*
pub enum MeshRenderMode {
    Triangles,
    Lines,
}

impl MeshRenderMode {
    fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            MeshRenderMode::Lines => gl::LINES,
        }
    }
}
*/

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

/*
pub struct Vao {
    id: GLuint,
}

impl Vao {
    pub fn new(mgl: &Mgl) -> Vao {
        let mut id = 0;
        unsafe {
            mgl.gl.GenVertexArrays(1, &mut id);
        }
        mgl.check();
        let vao = Vao{id: id};
        vao.bind();
        vao
    }

    pub fn bind(&self) {
        gl.BindVertexArray(self.id);
        mgl.check();
    }

    pub fn unbind(&self) {
        gl.BindVertexArray(0);
        mgl.check();
    }

    pub fn draw_array(&self, mesh_mode: MeshRenderMode, faces_count: MInt) {
        let starting_index = 0;
        let vertices_count = faces_count * 3;
        let mode = mesh_mode.to_gl_type();
        gl.DrawArrays(mode, starting_index, vertices_count);
        mgl.check();
    }
}

impl Drop for Vao {
    fn drop(&mut self) {
        unsafe {
            gl.DeleteVertexArrays(1, &self.id);
        }
        mgl.check();
    }
}
*/

/*
pub struct Vbo {
    id: GLuint,
}

fn get_new_vbo_id() -> GLuint {
    let mut id = 0;
    unsafe {
        verify!(gl::GenBuffers(1, &mut id));
    }
    id
}

impl Vbo {
    pub fn from_data<T>(data: &[T]) -> Vbo {
        let vbo = Vbo{id: get_new_vbo_id()};
        vbo.bind();
        let size = std::mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = std::mem::transmute(&data[0]);
                verify!(gl::BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                ));
            }
        }
        vbo
    }

    pub fn bind(&self) {
        verify!(gl::BindBuffer(gl::ARRAY_BUFFER, self.id));
    }
}

impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn read_pixel_bytes(
    win_size: Size2<MInt>,
    mouse_pos: ScreenPos,
) -> (MInt, MInt, MInt, MInt) {
    let height = win_size.h;
    let reverted_h = height - mouse_pos.v.y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
        let data_ptr = std::mem::transmute(&data[0]);
        verify!(gl::ReadPixels(
            mouse_pos.v.x, reverted_h, 1, 1,
            gl::RGBA,
            gl::UNSIGNED_BYTE,
            data_ptr
        ));
    }
    (data[0] as MInt, data[1] as MInt, data[2] as MInt, data[3] as MInt)
}

pub fn get_2d_screen_matrix(win_size: Size2<MInt>) -> Matrix4<MFloat> {
    let left = 0.0;
    let right = win_size.w as MFloat;
    let bottom = 0.0;
    let top = win_size.h as MFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

pub fn compile_shader(gl: &Gl, src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl.CreateShader(ty);
        src.with_c_str(|ptr| gl.ShaderSource(shader, 1, &ptr, ptr::null()));
        gl.CompileShader(shader);
        {
            let mut status = gl::FALSE as GLint;
            gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
            assert!(status == gl::TRUE as GLint);
        }
    }
    shader
}

pub fn link_program(gl: &Gl, vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let program = gl.CreateProgram();
        gl.AttachShader(program, vs);
        gl.AttachShader(program, fs);
        gl.LinkProgram(program);
        {
            let mut status = gl::FALSE as GLint;
            gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);
            assert!(status == (gl::TRUE as GLint));
        }
        program
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs;
use std::io::Write;
use error::*;
use config::Config;

const COBALT_YML: &'static [u8] = b"name: cobalt blog
source: \".\"
dest: \"build\"
ignore:
  - .git/*
  - build/*
";

const DEFAULT_LAYOUT: &'static [u8] = b"<!DOCTYPE html>

        <meta charset=\"utf-8\">
        {% if is_post %}
          <title>{{ title }}</title>
        {% else %}
          <title>Cobalt.rs Blog</title>
        {% endif %}

      {% if is_post %}
        {% include '_layouts/post.liquid' %}
      {% else %}
        {{ content }}
      {% endif %}

";

const POST_LAYOUT: &'static [u8] = b"

{{ title }}

    {{content}}

";

const POST_MD: &'static [u8] = b"extends: default.liquid

title: First Post
date: 14 January 2016 21:00:30 -0500
---

# This is our first Post!

Welcome to the first post ever on cobalt.rs!
";

const INDEX_LIQUID: &'static [u8] = b"extends: default.liquid
---

Blog!

    {% for post in posts %}

{{post.title}}

{{ post.title }}

    {% endfor %}

";

pub fn create_new_project<P: AsRef<Path>>(dest: P) -> Result<()> {
    create_new_project_for_path(dest.as_ref())
}

pub fn create_new_project_for_path(dest: &Path) -> Result<()> {
    fs::create_dir_all(dest)?;

    create_file(&dest.join(".cobalt.yml"), COBALT_YML)?;
    create_file(&dest.join("index.liquid"), INDEX_LIQUID)?;

    fs::create_dir_all(&dest.join("_layouts"))?;
    create_file(&dest.join("_layouts/default.liquid"), DEFAULT_LAYOUT)?;
    create_file(&dest.join("_layouts/post.liquid"), POST_LAYOUT)?;

    fs::create_dir_all(&dest.join("posts"))?;
    create_file(&dest.join("posts/post-1.md"), POST_MD)?;

    Ok(())
}

pub fn create_new_document(doc_type: &str, name: &str, config: &Config) -> Result<()> {
    let path = Path::new(&config.source);
    let full_path = &path.join(&config.posts.dir).join(name);

    match doc_type {
        "page" => create_file(name, INDEX_LIQUID)?,
        "post" => create_file(full_path, POST_MD)?,
        _ => bail!("Unsupported document type {}", doc_type),
    }

    Ok(())
}

fn create_file<P: AsRef<Path>>(path: P, content: &[u8]) -> Result<()> {
    create_file_for_path(path.as_ref(), content)
}

fn create_file_for_path(path: &Path, content: &[u8]) -> Result<()> {
    trace!("Creating file {:?}", path);

    let mut file = fs::OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(path)
        .chain_err(|| format!("Failed to create file {:?}", path))?;

    file.write_all(content)?;

    Ok(())
}
<commit_msg>feat(init): Update defaults<commit_after>use std::path::Path;
use std::fs;
use std::io::Write;
use error::*;
use config::Config;

const COBALT_YML: &'static [u8] = b"name: cobalt blog
source: \".\"
dest: \"./_site\"
";

const DEFAULT_LAYOUT: &'static [u8] = b"<!DOCTYPE html>

        <meta charset=\"utf-8\">
        {% if is_post %}
          <title>{{ title }}</title>
        {% else %}
          <title>Cobalt.rs Blog</title>
        {% endif %}

      {% if is_post %}
        {% include '_layouts/post.liquid' %}
      {% else %}
        {{ content }}
      {% endif %}

";

const POST_LAYOUT: &'static [u8] = b"

{{ title }}

    {{content}}

";

const POST_MD: &'static [u8] = b"extends: default.liquid

title: First Post
date: 14 January 2016 21:00:30 -0500
---

# This is our first Post!

Welcome to the first post ever on cobalt.rs!
";

const INDEX_LIQUID: &'static [u8] = b"extends: default.liquid
---

Blog!

    {% for post in posts %}

{{post.title}}

{{ post.title }}

    {% endfor %}

";

pub fn create_new_project<P: AsRef<Path>>(dest: P) -> Result<()> {
    create_new_project_for_path(dest.as_ref())
}

pub fn create_new_project_for_path(dest: &Path) -> Result<()> {
    fs::create_dir_all(dest)?;

    create_file(&dest.join(".cobalt.yml"), COBALT_YML)?;
    create_file(&dest.join("index.liquid"), INDEX_LIQUID)?;

    fs::create_dir_all(&dest.join("_layouts"))?;
    create_file(&dest.join("_layouts/default.liquid"), DEFAULT_LAYOUT)?;
    create_file(&dest.join("_layouts/post.liquid"), POST_LAYOUT)?;

    fs::create_dir_all(&dest.join("posts"))?;
    create_file(&dest.join("posts/post-1.md"), POST_MD)?;

    Ok(())
}

pub fn create_new_document(doc_type: &str, name: &str, config: &Config) -> Result<()> {
    let path = Path::new(&config.source);
    let full_path = &path.join(&config.posts.dir).join(name);

    match doc_type {
        "page" => create_file(name, INDEX_LIQUID)?,
        "post" => create_file(full_path, POST_MD)?,
        _ => bail!("Unsupported document type {}", doc_type),
    }

    Ok(())
}

fn create_file<P: AsRef<Path>>(path: P, content: &[u8]) -> Result<()> {
    create_file_for_path(path.as_ref(), content)
}

fn create_file_for_path(path: &Path, content: &[u8]) -> Result<()> {
    trace!("Creating file {:?}", path);

    let mut file = fs::OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(path)
        .chain_err(|| format!("Failed to create file {:?}", path))?;

    file.write_all(content)?;

    Ok(())
}
<|endoftext|>


<commit_before>use std::fmt::Write;

/* For branch name dedup */
use std::collections::HashSet;

use util::*;

use std::process;

use timesheet::traits::HasHTML;

#[derive(Serialize, Deserialize, Debug)]
pub enum EventType {
    Pause,
    Resume,
    Note,
    Commit { hash: String },
}

#[derive(Serialize, Deserialize, Debug)]
struct Event {
    timestamp : u64,
    note      : Option<String>,
    ty        : EventType
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Session {
    pub start    : u64,
    pub end      : u64,
    running  : bool,
    branches : HashSet<String>,
    events   : Vec<Event>,
}

impl Session {
    pub fn new(timestamp: Option<u64>) -> Session {
        let timestamp = match timestamp {
            Some(timestamp) => timestamp,
            None => get_seconds(),
        };
        Session {
            start    : timestamp,
            end      : timestamp + 1,
            running  : true,
            branches : HashSet::<String>::new(),
            events   : Vec::<Event>::new(),
        }
    }

    pub fn is_running(&self) -> bool {
        self.running
    }

    pub fn is_paused(&self) -> bool {
        match self.events.len() {
            0 => false,
            n => {
                match self.events[n - 1].ty {
                    EventType::Pause => true,
                    _ => false,
                }
            }
        }
    }

    pub fn update_end(&mut self) {
        self.end = match self.events.len() {
            0 => self.end,
            n => &self.events[n - 1].timestamp + 1,
        }
    }

    pub fn finalize(&mut self, timestamp: Option<u64>) {
        let timestamp = match timestamp {
            None => get_seconds(),
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => {
                        let last_ev = &self.events[n - 1];
                        timestamp > last_ev.timestamp
                    }
                };
                if is_valid_ts {
                    timestamp
                } else {
                    println!("That is not a valid timestamp!");
                    process::exit(0);
                }
            }
        };
        if self.is_running() {
            if self.is_paused() {
                self.push_event(Some(timestamp), None, EventType::Resume);
            }
            self.running = false;
            self.end = timestamp + 1;
        }
    }

    pub fn push_event(&mut self,
                  timestamp : Option<u64>,
                  note      : Option<String>,
                  type_of_event : EventType)
                  -> bool {
        /* Cannot push if session is already finalized. */
        if !self.is_running() {
            println!("Already finalized, cannot push event.");
            return false;
        }

        let timestamp = match timestamp {
            None => {
                let now = get_seconds();
                self.end = now;
                now
            }
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => timestamp > self.events[n - 1].timestamp,
                };
                if is_valid_ts {
                    self.end = timestamp + 1;
                    timestamp
                } else {
                    println!("That timestamp is before the last event.");
                    return false;
                }
            }
        };
        /* TODO: improve logic */
        match type_of_event {
            // TODO: fix this, so both note and ago work...
            EventType::Pause => {
                if self.is_paused() {
                    println!("Already paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty      : EventType::Pause,
                              });
                    true
                }
            }
            EventType::Resume => {
                if !self.is_paused() {
                    println!("Currently not paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty        : EventType::Resume,
                              });
                    true
                }
            }
            EventType::Note => {
                if self.is_paused() {
                    /* Add note to previous pause (last of events vec) */
                    /* If self.is_paused(), then self.len() is always at least 1 */
                    let len = self.events.len();
                    let pause = &mut self.events[len - 1];
                    match pause.note {
                        Some(ref mut already) => {
                            // TODO: handle long strings (also in other types)
                            // TODO: there must be another way other than

                            already.push_str("
");
                            already.push_str(&note.unwrap());
                        }
                        None => pause.note = note,
                    }
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty        : EventType::Note,
                              })
                };
                true
            }
            /* Commit adding possible only in present */
            EventType::Commit { hash } => {
                if self.is_paused() {
                    self.push_event(None, None, EventType::Resume);
                }
                /* Commit message must be provided */
                if note.is_none() {
                    println!("No commit message found for commit {}.", hash);
                }
                self.events
                    .push(Event {
                              timestamp : get_seconds(),
                              note      : note,
                              ty        : EventType::Commit { hash },
                          });
                true
            }
        }
    }

    pub fn pause_time(&self) -> u64 {
        let mut pause_time = 0;
        let mut last_pause_ts = 0;
        for event in &self.events {
            match event.ty {
                EventType::Pause => last_pause_ts = event.timestamp,
                EventType::Resume => pause_time += event.timestamp - last_pause_ts,
                _ => {}
            }
        }
        pause_time
    }

    pub fn working_time(&self) -> u64 {
        let pause_time = self.pause_time();
        self.end - self.start - pause_time
    }

    pub fn add_branch(&mut self, name: String) {
        if self.is_running() {
            self.branches.insert(name);
        }
    }

    pub fn status(&self) -> String {
        let mut status = String::new();
        write!(&mut status,
               r#"Session running since {}.
"#,
               sec_to_hms_string(get_seconds() - self.start))
                .unwrap();
        if self.is_paused() {
            write!(&mut status,
                   r#"    Paused since {}.
"#,
                   sec_to_hms_string(get_seconds() - self.events[self.events.len() - 1].timestamp))
                    .unwrap();
        } else {
            match self.events.len() {
                0 => write!(&mut status, "    No events in this session yet!\n").unwrap(),
                n => {
                    write!(&mut status,
                           "    Last event: {:?}, {} ago.\n",
                           &self.events[n - 1].ty,
                           sec_to_hms_string(get_seconds() - self.events[n - 1].timestamp))
                            .unwrap()
                }
            }
        }
        match self.branches.len() {
            0 => {}
            n => {
                let mut branch_str = String::new();
                for branch in &self.branches {
                    write!(&mut branch_str, "{} ", branch).unwrap();
                }
                write!(&mut status, "Worked on {} branches: {}", n, branch_str).unwrap();
            }
        }
        status
    }
}

impl HasHTML for Event {
    fn to_html(&self) -> String {
        match self.ty {
            EventType::Pause => {
                match self.note {
                    Some(ref info) => {
                        format!(r#"
{}: Started a pause

{}

"#,
                                ts_to_date(self.timestamp),
                                info.clone())
                    }
                    None => {
                        format!(r#"
{}: Started a pause

"#,
                                ts_to_date(self.timestamp))
                    }
                }
            }
            EventType::Resume => {
                format!(r#"
{}: Resumed work

"#,
                        ts_to_date(self.timestamp))
            }
            /* An EventType::Note note is a Some because it's
             * 'constructor' function takes a String
             * (and not Option<String>)
             */
            EventType::Note => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Note: {
}

"#,
                                ts_to_date(self.timestamp),
                                text)
                    }
                    None => unreachable!(),
                }
            }
            /* It is safe to unwrap an EventType::Commit note because if
             * a commit has no message something went really wrong
             * (like parsing the output of `git log` in git_commit_message()
             */
            EventType::Commit { ref hash } => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Commit id: {}

message: {}

"#,
                                ts_to_date(self.timestamp),
                                hash,
                                text)
                    }
                    None => unreachable!(),
                }
            }
        }
    }
}

impl HasHTML for Session {
    fn to_html(&self) -> String {
        let mut html = format!(r#"

Session on {}
"#,
                               ts_to_date(self.start));

        for event in &self.events {
            write!(&mut html, "{}", event.to_html()).unwrap();
        }

        write!(&mut html,
               r#"
Ended on {}
"#,
               ts_to_date(self.end))
                .unwrap();

        let mut branch_str = String::new();
        match self.branches.len() {
            0 => {}
            n => {
                write!(&mut branch_str, "Worked on {} branches: ", n).unwrap();
                for branch in &self.branches {
                    write!(&mut branch_str, "{} ", branch).unwrap();
                }
            }
        };

        write!(&mut html,
               r#"

{}

Worked for {}

Paused for {}

"#,
               branch_str,
               sec_to_hms_string(self.working_time()),
               sec_to_hms_string(self.pause_time()))
                .unwrap();

        write!(&mut html, "
").unwrap();
        html
    }
}<commit_msg>idiomize branch string with fold<commit_after>use std::fmt::Write;

/* For branch name dedup */
use std::collections::HashSet;

use util::*;

use std::process;

use timesheet::traits::HasHTML;

#[derive(Serialize, Deserialize, Debug)]
pub enum EventType {
    Pause,
    Resume,
    Note,
    Commit { hash: String },
}

#[derive(Serialize, Deserialize, Debug)]
struct Event {
    timestamp : u64,
    note      : Option<String>,
    ty        : EventType
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Session {
    pub start    : u64,
    pub end      : u64,
    running  : bool,
    branches : HashSet<String>,
    events   : Vec<Event>,
}

impl Session {
    pub fn new(timestamp: Option<u64>) -> Session {
        let timestamp = match timestamp {
            Some(timestamp) => timestamp,
            None => get_seconds(),
        };
        Session {
            start    : timestamp,
            end      : timestamp + 1,
            running  : true,
            branches : HashSet::<String>::new(),
            events   : Vec::<Event>::new(),
        }
    }

    pub fn is_running(&self) -> bool {
        self.running
    }

    pub fn is_paused(&self) -> bool {
        match self.events.len() {
            0 => false,
            n => {
                match self.events[n - 1].ty {
                    EventType::Pause => true,
                    _ => false,
                }
            }
        }
    }

    pub fn update_end(&mut self) {
        self.end = match self.events.len() {
            0 => self.end,
            n => &self.events[n - 1].timestamp + 1,
        }
    }

    pub fn finalize(&mut self, timestamp: Option<u64>) {
        let timestamp = match timestamp {
            None => get_seconds(),
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => {
                        let last_ev = &self.events[n - 1];
                        timestamp > last_ev.timestamp
                    }
                };
                if is_valid_ts {
                    timestamp
                } else {
                    println!("That is not a valid timestamp!");
                    process::exit(0);
                }
            }
        };
        if self.is_running() {
            if self.is_paused() {
                self.push_event(Some(timestamp), None, EventType::Resume);
            }
            self.running = false;
            self.end = timestamp + 1;
        }
    }

    pub fn push_event(&mut self,
                  timestamp : Option<u64>,
                  note      : Option<String>,
                  type_of_event : EventType)
                  -> bool {
        /* Cannot push if session is already finalized. */
        if !self.is_running() {
            println!("Already finalized, cannot push event.");
            return false;
        }

        let timestamp = match timestamp {
            None => {
                let now = get_seconds();
                self.end = now;
                now
            }
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => timestamp > self.events[n - 1].timestamp,
                };
                if is_valid_ts {
                    self.end = timestamp + 1;
                    timestamp
                } else {
                    println!("That timestamp is before the last event.");
                    return false;
                }
            }
        };
        /* TODO: improve logic */
        match type_of_event {
            // TODO: fix this, so both note and ago work...
            EventType::Pause => {
                if self.is_paused() {
                    println!("Already paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty      : EventType::Pause,
                              });
                    true
                }
            }
            EventType::Resume => {
                if !self.is_paused() {
                    println!("Currently not paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty        : EventType::Resume,
                              });
                    true
                }
            }
            EventType::Note => {
                if self.is_paused() {
                    /* Add note to previous pause (last of events vec) */
                    /* If self.is_paused(), then self.len() is always at least 1 */
                    let len = self.events.len();
                    let pause = &mut self.events[len - 1];
                    match pause.note {
                        Some(ref mut already) => {
                            // TODO: handle long strings (also in other types)
                            // TODO: there must be another way other than

                            already.push_str("
");
                            already.push_str(&note.unwrap());
                        }
                        None => pause.note = note,
                    }
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ty        : EventType::Note,
                              })
                };
                true
            }
            /* Commit adding possible only in present */
            EventType::Commit { hash } => {
                if self.is_paused() {
                    self.push_event(None, None, EventType::Resume);
                }
                /* Commit message must be provided */
                if note.is_none() {
                    println!("No commit message found for commit {}.", hash);
                }
                self.events
                    .push(Event {
                              timestamp : get_seconds(),
                              note      : note,
                              ty        : EventType::Commit { hash },
                          });
                true
            }
        }
    }

    pub fn pause_time(&self) -> u64 {
        let mut pause_time = 0;
        let mut last_pause_ts = 0;
        for event in &self.events {
            match event.ty {
                EventType::Pause => last_pause_ts = event.timestamp,
                EventType::Resume => pause_time += event.timestamp - last_pause_ts,
                _ => {}
            }
        }
        pause_time
    }

    pub fn working_time(&self) -> u64 {
        let pause_time = self.pause_time();
        self.end - self.start - pause_time
    }

    pub fn add_branch(&mut self, name: String) {
        if self.is_running() {
            self.branches.insert(name);
        }
    }

    pub fn status(&self) -> String {
        let mut status = String::new();
        write!(&mut status,
               r#"Session running since {}.
"#,
               sec_to_hms_string(get_seconds() - self.start))
                .unwrap();
        if self.is_paused() {
            write!(&mut status,
                   r#"    Paused since {}.
"#,
                   sec_to_hms_string(get_seconds() - self.events[self.events.len() - 1].timestamp))
                    .unwrap();
        } else {
            match self.events.len() {
                0 => write!(&mut status, "    No events in this session yet!\n").unwrap(),
                n => {
                    write!(&mut status,
                           "    Last event: {:?}, {} ago.\n",
                           &self.events[n - 1].ty,
                           sec_to_hms_string(get_seconds() - self.events[n - 1].timestamp))
                            .unwrap()
                }
            }
        }
        let branch_str = match self.branches.len() {
            0 => String::new(),
            n => {
                self.branches.iter().fold(
                    format!("Worked on {} branches: ", n),
                    |res, s| res + s + " "
                )
            }
        };
        status.push_str(&branch_str);
        status
    }
}

impl HasHTML for Event {
    fn to_html(&self) -> String {
        match self.ty {
            EventType::Pause => {
                match self.note {
                    Some(ref info) => {
                        format!(r#"
{}: Started a pause

{}

"#,
                                ts_to_date(self.timestamp),
                                info.clone())
                    }
                    None => {
                        format!(r#"
{}: Started a pause

"#,
                                ts_to_date(self.timestamp))
                    }
                }
            }
            EventType::Resume => {
                format!(r#"
{}: Resumed work

"#,
                        ts_to_date(self.timestamp))
            }
            /* An EventType::Note note is a Some because it's
             * 'constructor' function takes a String
             * (and not Option<String>)
             */
            EventType::Note => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Note: {
}

"#,
                                ts_to_date(self.timestamp),
                                text)
                    }
                    None => unreachable!(),
                }
            }
            /* It is safe to unwrap an EventType::Commit note because if
             * a commit has no message something went really wrong
             * (like parsing the output of `git log` in git_commit_message()
             */
            EventType::Commit { ref hash } => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Commit id: {}

message: {}

"#,
                                ts_to_date(self.timestamp),
                                hash,
                                text)
                    }
                    None => unreachable!(),
                }
            }
        }
    }
}

impl HasHTML for Session {
    fn to_html(&self) -> String {
        let mut html = format!(r#"

Session on {}
"#,
                               ts_to_date(self.start));

        for event in &self.events {
            write!(&mut html, "{}", event.to_html()).unwrap();
        }

        write!(&mut html,
               r#"
Ended on {}
"#,
               ts_to_date(self.end))
                .unwrap();

        let mut branch_str = String::new();
        match self.branches.len() {
            0 => {}
            n => {
                write!(&mut branch_str, "Worked on {} branches: ", n).unwrap();
                for branch in &self.branches {
                    write!(&mut branch_str, "{} ", branch).unwrap();
                }
            }
        };

        write!(&mut html,
               r#"

{}

Worked for {}

Paused for {}

"#,
               branch_str,
               sec_to_hms_string(self.working_time()),
               sec_to_hms_string(self.pause_time()))
                .unwrap();

        write!(&mut html, "
").unwrap();
        html
    }
}<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

/// Default Depot URL
pub const DEFAULT_DEPOT_URL: &'static str = "http://52.37.151.35:9632";

/// Default Depot URL environment variable
pub const DEPOT_URL_ENVVAR: &'static str = "HAB_DEPOT_URL";
<commit_msg>Update the `HAB_DEPOT_URL` default from IP to hostname.<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

/// Default Depot URL
pub const DEFAULT_DEPOT_URL: &'static str = "http://willem.habitat.sh:9632";

/// Default Depot URL environment variable
pub const DEPOT_URL_ENVVAR: &'static str = "HAB_DEPOT_URL";
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::PathBuf;
use std::path::Path;

use error::*;

#[derive(Debug, Clone)]
pub struct VfsConfig {
	pub mount_points: HashMap<String, PathBuf>,
}

impl VfsConfig {
    pub fn new() -> VfsConfig {
        VfsConfig {
            mount_points: HashMap::new(),
        }
    }
}

pub struct Vfs {
    mount_points: HashMap<String, PathBuf>,
}

impl Vfs {
    pub fn new(config: VfsConfig) -> Vfs {
        Vfs { mount_points: config.mount_points }
    }

    pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            match real_path.strip_prefix(target) {
                Ok(p) => {
                    let mount_path = Path::new(&name);
                    return Ok(mount_path.join(p));
                }
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            let mount_path = Path::new(&name);
            match virtual_path.strip_prefix(mount_path) {
                Ok(p) => return Ok(target.join(p)),
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
        return &self.mount_points;
    }
}

#[test]
fn test_virtual_to_real() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let correct_path = Path::new("test_dir/somewhere/something.png");
    let found_path = vfs.virtual_to_real(Path::new("root/somewhere/something.png")).unwrap();
    assert!(found_path == correct_path);
}

#[test]
fn test_real_to_virtual() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let correct_path = Path::new("root/somewhere/something.png");
    let found_path = vfs.real_to_virtual(Path::new("test_dir/somewhere/something.png")).unwrap();
    assert!(found_path == correct_path);
}
<commit_msg>Fixed a bug where exact match to mount points could generate paths with a trailing slash<commit_after>use std::collections::HashMap;
use std::path::PathBuf;
use std::path::Path;

use error::*;

#[derive(Debug, Clone)]
pub struct VfsConfig {
	pub mount_points: HashMap<String, PathBuf>,
}

impl VfsConfig {
    pub fn new() -> VfsConfig {
        VfsConfig {
            mount_points: HashMap::new(),
        }
    }
}

pub struct Vfs {
    mount_points: HashMap<String, PathBuf>,
}

impl Vfs {
    pub fn new(config: VfsConfig) -> Vfs {
        Vfs { mount_points: config.mount_points }
    }

    pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            match real_path.strip_prefix(target) {
                Ok(p) => {
                    let mount_path = Path::new(&name);
                    return Ok(mount_path.join(p));
                }
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
        for (name, target) in &self.mount_points {
            let mount_path = Path::new(&name);
            match virtual_path.strip_prefix(mount_path) {
                Ok(p) => return if p.components().count() == 0 {
                    Ok(target.clone())
                } else {
                    Ok(target.join(p))
                },
                Err(_) => (),
            }
        }
        Err(PError::PathNotInVfs)
    }

    pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
        return &self.mount_points;
    }
}

#[test]
fn test_virtual_to_real() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);
    let correct_path = Path::new(r"test_dir\somewhere\something.png");
    let found_path = vfs.virtual_to_real(Path::new(r"root\somewhere\something.png")).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_virtual_to_real_no_trail() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);
    let correct_path = Path::new("test_dir");
    let found_path = vfs.virtual_to_real(Path::new("root")).unwrap();
    assert!(found_path.to_str() == correct_path.to_str());
}

#[test]
fn test_real_to_virtual() {
    let mut config = VfsConfig::new();
    config.mount_points.insert("root".to_owned(), Path::new("test_dir").to_path_buf());
    let vfs = Vfs::new(config);

    let correct_path = Path::new("root/somewhere/something.png");
    let found_path = vfs.real_to_virtual(Path::new("test_dir/somewhere/something.png")).unwrap();
    assert!(found_path == correct_path);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#![feature(collections)]
#![feature(core)]
#![feature(hash)]
#![feature(fs)]
#![feature(int_uint)]
#![feature(io)]
#![feature(libc)]
#![feature(path)]
#![feature(rustc_private)]
#![feature(unicode)]

#![cfg_attr(test, feature(os))]
#![cfg_attr(test, feature(std_misc))]

#[macro_use]
extern crate bitflags;

#[cfg(not(test))]
use std::collections::HashMap;
#[cfg(not(test))]
use std::path::Path;

#[allow(dead_code, unused_imports)]  // temporary until buffer is used for real
mod buffer;
mod frame;
mod input;
mod keymap;
mod screen;
mod view;

#[cfg(not(test))]
struct Rim {
  frame: frame::Frame,
  frame_ctx: frame::FrameContext,
  windows: HashMap<frame::WindowId, view::View>,
  focus: frame::WindowId,
  buffer: buffer::Buffer,
}

#[cfg(not(test))]
impl Rim {
  fn new() -> Rim {
    let (frame, frame_ctx, first_window) = frame::Frame::new();
    let mut windows = HashMap::new();
    windows.insert(first_window.clone(), view::View::new());
    Rim {
      frame: frame,
      frame_ctx: frame_ctx,
      windows: windows,
      focus: first_window,
      buffer: buffer::Buffer::open(&Path::new("src/rim.rs")).unwrap(),
    }
  }

  fn switch_focus(&mut self, direction: frame::Direction)
      -> Option<(frame::WindowId, frame::WindowId)> {
    self.frame.get_adjacent_window(&self.frame_ctx, &self.focus, direction).
    map(|window| self.move_focus(window)).ok()
  }

  fn shift_focus(&mut self, order: frame::WindowOrder)
      -> Option<(frame::WindowId, frame::WindowId)> {
    self.frame.get_sequent_window(&self.frame_ctx, &self.focus, order, true).
    map(|window| self.move_focus(window)).ok()
  }

  fn move_focus(&mut self, window: frame::WindowId)
      -> (frame::WindowId, frame::WindowId) {
    let old_focus = std::mem::replace(&mut self.focus, window);
    (old_focus, self.focus.clone())
  }

  fn split_window(&mut self, orientation: frame::Orientation) {
    self.frame.split_window(&mut self.frame_ctx, &self.focus, orientation).
    map(|new_window| self.windows.insert(new_window, view::View::new())).
    ok().expect("Failed to split window.");
  }

  fn resize_window(&mut self, orientation: frame::Orientation, amount: int)
     -> bool {
    self.frame.resize_window(&self.frame_ctx, &self.focus, orientation, amount).
    map(|absorbed| absorbed != 0).unwrap()
  }

  fn close_window(&mut self) -> bool {
    self.frame.get_closest_neighbouring_window(&self.frame_ctx, &self.focus).
    map(|neighbour| {
      let (old_focus, _) = self.move_focus(neighbour);
      self.frame.close_window(&mut self.frame_ctx, &old_focus).unwrap();
      self.windows.remove(&old_focus); }).
    is_ok()
  }

  fn draw_window(&self, window: &frame::WindowId, screen: &mut screen::Screen) {
    self.windows.get(window).
    map(|view| self.draw_view(window, view, screen)).
    expect("Couldn't find view for window.");
    screen.flush();
  }

  fn draw_view(&self, window: &frame::WindowId, view: &view::View,
               screen: &mut screen::Screen) {
    self.frame.get_window_rect(&self.frame_ctx, window).
    map(|rect| { let screen::Rect(position, _) = rect; position }).
    map(|pos| view.draw(&self.buffer, self.focus == *window, pos, screen)).
    ok().expect("Couldn't find rect for window.");
  }

  fn draw_all(&self, screen: &mut screen::Screen) {
    screen.clear();
    self.frame.draw_borders(screen);
    for (window, view) in self.windows.iter() {
      self.draw_view(window, view, screen);
    }
    screen.flush();
  }

  fn update_view_sizes(&mut self) {
    let window_sizes: Vec<(frame::WindowId, screen::Size)> =
      self.windows.iter().
      map(|(win, _)|
        self.frame.get_window_rect(&self.frame_ctx, win).
        map(|rect| { let screen::Rect(_, size) = rect; (win.clone(), size) }).
        ok().expect("Couldn't find rect for window.")).
      collect();
    for &(ref win, size) in window_sizes.iter() {
      self.windows.remove(win).
      map(|mut view| {
        view.set_size(size, &self.buffer);
        self.windows.insert(win.clone(), view); }).
      expect("Couldn't find view for window.");
    }
  }

  fn handle_key_by_view(&mut self, key: keymap::Key) -> bool {
     self.windows.remove(&self.focus).
     map(|mut view| {
       let swallowed = match key {
         keymap::Key::Sym{sym: keymap::KeySym::Left, mods:_}  => {
           view.move_caret(view::CaretMovement::CharPrev, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Right, mods:_} => {
           view.move_caret(view::CaretMovement::CharNext, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Up, mods:_}    => {
           view.move_caret(view::CaretMovement::LineUp, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Down, mods:_}  => {
           view.move_caret(view::CaretMovement::LineDown, &self.buffer); true
         }
         _                                                    => false,
       };
       self.windows.insert(self.focus.clone(), view);
       swallowed }).
     expect("Found no view for focused window.")
  }
}

#[cfg(not(test))]
impl Drop for Rim {
  fn drop(&mut self) {
    self.buffer.write().unwrap();  // what could go wrong!
  }
}

#[cfg(not(test))]
fn main() {
  let mut screen = screen::Screen::setup().unwrap();

  let mut rim = Rim::new();

  let (key_tx, key_rx) = std::sync::mpsc::channel();
  let _term_input = input::start(key_tx);

  let draw_window_pair =
    |&: (win1, win2), rim: &Rim, screen: &mut screen::Screen|
      { rim.draw_window(&win1, screen); rim.draw_window(&win2, screen); };

  loop {
    match key_rx.try_recv().ok().and_then(|key|
        if !rim.handle_key_by_view(key) { Some(key) }
        else { rim.draw_window(&rim.focus, &mut screen); None }) {
      Some(keymap::Key::Unicode{codepoint: 'h', mods:_}) => {
        rim.switch_focus(frame::Direction::Left).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'l', mods:_}) => {
        rim.switch_focus(frame::Direction::Right).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'k', mods:_}) => {
        rim.switch_focus(frame::Direction::Up).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'j', mods:_}) => {
        rim.switch_focus(frame::Direction::Down).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'n', mods:_}) => {
        rim.shift_focus(frame::WindowOrder::NextWindow).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'N', mods:_}) => {
        rim.shift_focus(frame::WindowOrder::PreviousWindow).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: '=', mods:_}) => {
        rim.frame.reset_layout();
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 'v', mods:_}) => {
        rim.split_window(frame::Orientation::Vertical);
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 's', mods:_}) => {
        rim.split_window(frame::Orientation::Horizontal);
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 'y', mods})   => {
        let amount = if mods.contains(keymap::MOD_CTRL) { -10 }
                     else                               { 10 };
        if rim.resize_window(frame::Orientation::Horizontal, amount) {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        }
      }
      Some(keymap::Key::Unicode{codepoint: 'u', mods})   => {
        let amount = if mods.contains(keymap::MOD_CTRL) { -10 }
                     else                               { 10 };
        if rim.resize_window(frame::Orientation::Vertical, amount) {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        }
      }
      Some(keymap::Key::Unicode{codepoint: 'c', mods:_}) =>
        if rim.close_window() {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        },
      Some(keymap::Key::Unicode{codepoint: 'q', mods:_}) =>
        break,
      _                                                  =>
        (),
    }

    if screen.update_size() {
      rim.frame.set_size(screen.size());
      rim.update_view_sizes();
      rim.draw_all(&mut screen);
    }
  }
}
<commit_msg>Use feature(old_io)<commit_after>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#![feature(collections)]
#![feature(core)]
#![feature(hash)]
#![feature(fs)]
#![feature(int_uint)]
#![feature(io)]
#![feature(libc)]
#![feature(old_io)]
#![feature(path)]
#![feature(rustc_private)]
#![feature(unicode)]

#![cfg_attr(test, feature(os))]
#![cfg_attr(test, feature(std_misc))]

#[macro_use]
extern crate bitflags;

#[cfg(not(test))]
use std::collections::HashMap;
#[cfg(not(test))]
use std::path::Path;

#[allow(dead_code, unused_imports)]  // temporary until buffer is used for real
mod buffer;
mod frame;
mod input;
mod keymap;
mod screen;
mod view;

#[cfg(not(test))]
struct Rim {
  frame: frame::Frame,
  frame_ctx: frame::FrameContext,
  windows: HashMap<frame::WindowId, view::View>,
  focus: frame::WindowId,
  buffer: buffer::Buffer,
}

#[cfg(not(test))]
impl Rim {
  fn new() -> Rim {
    let (frame, frame_ctx, first_window) = frame::Frame::new();
    let mut windows = HashMap::new();
    windows.insert(first_window.clone(), view::View::new());
    Rim {
      frame: frame,
      frame_ctx: frame_ctx,
      windows: windows,
      focus: first_window,
      buffer: buffer::Buffer::open(&Path::new("src/rim.rs")).unwrap(),
    }
  }

  fn switch_focus(&mut self, direction: frame::Direction)
      -> Option<(frame::WindowId, frame::WindowId)> {
    self.frame.get_adjacent_window(&self.frame_ctx, &self.focus, direction).
    map(|window| self.move_focus(window)).ok()
  }

  fn shift_focus(&mut self, order: frame::WindowOrder)
      -> Option<(frame::WindowId, frame::WindowId)> {
    self.frame.get_sequent_window(&self.frame_ctx, &self.focus, order, true).
    map(|window| self.move_focus(window)).ok()
  }

  fn move_focus(&mut self, window: frame::WindowId)
      -> (frame::WindowId, frame::WindowId) {
    let old_focus = std::mem::replace(&mut self.focus, window);
    (old_focus, self.focus.clone())
  }

  fn split_window(&mut self, orientation: frame::Orientation) {
    self.frame.split_window(&mut self.frame_ctx, &self.focus, orientation).
    map(|new_window| self.windows.insert(new_window, view::View::new())).
    ok().expect("Failed to split window.");
  }

  fn resize_window(&mut self, orientation: frame::Orientation, amount: int)
     -> bool {
    self.frame.resize_window(&self.frame_ctx, &self.focus, orientation, amount).
    map(|absorbed| absorbed != 0).unwrap()
  }

  fn close_window(&mut self) -> bool {
    self.frame.get_closest_neighbouring_window(&self.frame_ctx, &self.focus).
    map(|neighbour| {
      let (old_focus, _) = self.move_focus(neighbour);
      self.frame.close_window(&mut self.frame_ctx, &old_focus).unwrap();
      self.windows.remove(&old_focus); }).
    is_ok()
  }

  fn draw_window(&self, window: &frame::WindowId, screen: &mut screen::Screen) {
    self.windows.get(window).
    map(|view| self.draw_view(window, view, screen)).
    expect("Couldn't find view for window.");
    screen.flush();
  }

  fn draw_view(&self, window: &frame::WindowId, view: &view::View,
               screen: &mut screen::Screen) {
    self.frame.get_window_rect(&self.frame_ctx, window).
    map(|rect| { let screen::Rect(position, _) = rect; position }).
    map(|pos| view.draw(&self.buffer, self.focus == *window, pos, screen)).
    ok().expect("Couldn't find rect for window.");
  }

  fn draw_all(&self, screen: &mut screen::Screen) {
    screen.clear();
    self.frame.draw_borders(screen);
    for (window, view) in self.windows.iter() {
      self.draw_view(window, view, screen);
    }
    screen.flush();
  }

  fn update_view_sizes(&mut self) {
    let window_sizes: Vec<(frame::WindowId, screen::Size)> =
      self.windows.iter().
      map(|(win, _)|
        self.frame.get_window_rect(&self.frame_ctx, win).
        map(|rect| { let screen::Rect(_, size) = rect; (win.clone(), size) }).
        ok().expect("Couldn't find rect for window.")).
      collect();
    for &(ref win, size) in window_sizes.iter() {
      self.windows.remove(win).
      map(|mut view| {
        view.set_size(size, &self.buffer);
        self.windows.insert(win.clone(), view); }).
      expect("Couldn't find view for window.");
    }
  }

  fn handle_key_by_view(&mut self, key: keymap::Key) -> bool {
     self.windows.remove(&self.focus).
     map(|mut view| {
       let swallowed = match key {
         keymap::Key::Sym{sym: keymap::KeySym::Left, mods:_}  => {
           view.move_caret(view::CaretMovement::CharPrev, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Right, mods:_} => {
           view.move_caret(view::CaretMovement::CharNext, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Up, mods:_}    => {
           view.move_caret(view::CaretMovement::LineUp, &self.buffer); true
         }
         keymap::Key::Sym{sym: keymap::KeySym::Down, mods:_}  => {
           view.move_caret(view::CaretMovement::LineDown, &self.buffer); true
         }
         _                                                    => false,
       };
       self.windows.insert(self.focus.clone(), view);
       swallowed }).
     expect("Found no view for focused window.")
  }
}

#[cfg(not(test))]
impl Drop for Rim {
  fn drop(&mut self) {
    self.buffer.write().unwrap();  // what could go wrong!
  }
}

#[cfg(not(test))]
fn main() {
  let mut screen = screen::Screen::setup().unwrap();

  let mut rim = Rim::new();

  let (key_tx, key_rx) = std::sync::mpsc::channel();
  let _term_input = input::start(key_tx);

  let draw_window_pair =
    |&: (win1, win2), rim: &Rim, screen: &mut screen::Screen|
      { rim.draw_window(&win1, screen); rim.draw_window(&win2, screen); };

  loop {
    match key_rx.try_recv().ok().and_then(|key|
        if !rim.handle_key_by_view(key) { Some(key) }
        else { rim.draw_window(&rim.focus, &mut screen); None }) {
      Some(keymap::Key::Unicode{codepoint: 'h', mods:_}) => {
        rim.switch_focus(frame::Direction::Left).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'l', mods:_}) => {
        rim.switch_focus(frame::Direction::Right).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'k', mods:_}) => {
        rim.switch_focus(frame::Direction::Up).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'j', mods:_}) => {
        rim.switch_focus(frame::Direction::Down).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'n', mods:_}) => {
        rim.shift_focus(frame::WindowOrder::NextWindow).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: 'N', mods:_}) => {
        rim.shift_focus(frame::WindowOrder::PreviousWindow).
        map(|pair| draw_window_pair(pair, &rim, &mut screen));
      }
      Some(keymap::Key::Unicode{codepoint: '=', mods:_}) => {
        rim.frame.reset_layout();
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 'v', mods:_}) => {
        rim.split_window(frame::Orientation::Vertical);
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 's', mods:_}) => {
        rim.split_window(frame::Orientation::Horizontal);
        rim.update_view_sizes();
        rim.draw_all(&mut screen);
      }
      Some(keymap::Key::Unicode{codepoint: 'y', mods})   => {
        let amount = if mods.contains(keymap::MOD_CTRL) { -10 }
                     else                               { 10 };
        if rim.resize_window(frame::Orientation::Horizontal, amount) {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        }
      }
      Some(keymap::Key::Unicode{codepoint: 'u', mods})   => {
        let amount = if mods.contains(keymap::MOD_CTRL) { -10 }
                     else                               { 10 };
        if rim.resize_window(frame::Orientation::Vertical, amount) {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        }
      }
      Some(keymap::Key::Unicode{codepoint: 'c', mods:_}) =>
        if rim.close_window() {
          rim.update_view_sizes();
          rim.draw_all(&mut screen);
        },
      Some(keymap::Key::Unicode{codepoint: 'q', mods:_}) =>
        break,
      _                                                  =>
        (),
    }

    if screen.update_size() {
      rim.frame.set_size(screen.size());
      rim.update_view_sizes();
      rim.draw_all(&mut screen);
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the SPI0 and SPI1 peripherals.

use std::fs::{File, OpenOptions};
use std::io;
use std::result;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when accessing the SPI peripherals.
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `spi::Error`s.
pub type Result<T> = result::Result<T, Error>;

mod ioctl {}

/// SPI devices.
pub enum Device {
    Spi0 = 0, // Enabled by default
    Spi1 = 1, // Requires additional configuration
}

/// Chip Enable pins.
pub enum ChipEnable {
    Ce0 = 0, // SPI0: BCM GPIO 8    SPI1: BCM GPIO 18
    Ce1 = 1, // SPI0: BCM GPIO 7    SPI1: BCM GPIO 17
    Ce2 = 2, // SPI0: N/A,          SPI1: BCM GPIO 16
}

/// SPI modes.
///
/// Select the appropriate SPI mode for your device. Each mode
/// configures the clock polarity (CPOL) and clock phase (CPHA)
/// as shown below:
///
/// * Mode0: CPOL 0, CPHA 0
/// * Mode1: CPOL 0, CPHA 1
/// * Mode2: CPOL 1, CPHA 0
/// * Mode3: CPOL 1, CPHA 1
///
/// More information on clock polarity and phase can be found on [Wikipedia].
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase
pub enum Mode {
    Mode0 = 0, // CPOL 0, CPHA 0
    Mode1 = 1, // CPOL 0, CPHA 1
    Mode2 = 2, // CPOL 1, CPHA 0
    Mode3 = 3, // CPOL 1, CPHA 1
}

pub struct Spi {
    spidev: File,
}

impl Spi {
    pub fn new(device: Device, chip_enable: ChipEnable, mode: Mode, speed: u32) -> Result<Spi> {
        let spidev = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/spidev{}.{}", device as u8, chip_enable as u8))?;

        Ok(Spi { spidev })
    }

    pub fn read(&self, mut buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn write(&self, buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn transfer(&self, mut read_buffer: &[u8], write_buffer: &[u8]) -> Result<()> {
        Ok(())
    }
}
<commit_msg>Add support for SPI2 on Compute modules<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Interface for the SPI0 and SPI1 peripherals.

use std::fs::{File, OpenOptions};
use std::io;
use std::result;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when accessing the SPI peripherals.
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `spi::Error`s.
pub type Result<T> = result::Result<T, Error>;

mod ioctl {}

/// SPI buses.
///
/// The Raspberry Pi's GPIO header exposes several SPI buses. SPI0 is available
/// on all Raspberry Pi models. SPI1 is available on models with a 40-pin
/// header. SPI2 is only available on the Compute and Compute 3 module.
///
/// SPI0 is disabled by default. You can enable it by running
/// `sudo raspi-config`, or by manually adding `dtparam=spi=on` to
/// `/boot/config.txt`. The associated pins are listed below.
///
/// * MISO: BCM GPIO 9 (physical pin 21)
/// * MOSI: BCM GPIO 10 (physical pin 19)
/// * SCLK: BCM GPIO 11 (physical pin 23)
/// * SS: CE0: BCM GPIO 8 (physical pin 24), CE1: BCM GPIO 7 (physical pin 26)
///
/// SPI1 is an auxiliary peripheral that's referred to as mini SPI. According
/// to the documentation, using higher clock speeds on SPI1 requires additional
/// CPU time compared to SPI0, caused by shallow FIFOs and no DMA support. SPI1
/// can be enabled by adding `dtoverlay=spi1-3cs` to `/boot/config.txt`. Replace
/// `3cs` with either `2cs` or `1cs` if you only require 2 or 1 Slave Select pins.
/// The associated pins are listed below.
///
/// * MISO: BCM GPIO 19 (physical pin 35)
/// * MOSI: BCM GPIO 20 (physical pin 38)
/// * SCLK: BCM GPIO 21 (physical pin 40)
/// * SS: CE0: BCM GPIO 18 (physical pin 12), CE1: BCM GPIO 17 (physical pin 11), CE2: BCM GPIO 16 (physical pin 36)
///
/// SPI2 shares the same characteristics as SPI1. It can be enabled by adding
/// `dtoverlay=spi2-3cs` to `/boot/config.txt`. Replace `3cs` with either `2cs` or
/// `1cs` if you only require 2 or 1 Slave Select pins. The associated pins are
/// listed below.
///
/// * MISO: BCM GPIO 40
/// * MOSI: BCM GPIO 41
/// * SCLK: BCM GPIO 42
/// * SS: CE0: BCM GPIO 43, CE1: BCM GPIO 44, CE2: BCM GPIO 45
///
/// The GPIO pin numbers mentioned above are part of the default configuration. Some of
/// them can be moved to different pins. Read `/boot/overlays/README` for more information.
pub enum Bus {
    Spi0 = 0,
    Spi1 = 1,
    Spi2 = 2,
}

/// Chip Enable (Slave Select) pins.
///
/// Select a Chip Enable pin to signal which device should
/// interact with the SPI master. Chip Enable is more commonly
/// known as Slave Select or Chip Select.
///
/// Each of the available SPI buses has access to either two
/// or three Chip Enable pins, as shown below:
///
/// * Spi0: Ce0 (BCM GPIO 8), Ce1 (BCM GPIO 7)
/// * Spi1: Ce0 (BCM GPIO 18, Ce1 (BCM GPIO 17), Ce2 (BCM GPIO 16)
/// * Spi2: Ce0 (BCM GPIO 43, Ce1 (BCM GPIO 44), Ce2 (BCM GPIO 45)
pub enum ChipEnable {
    Ce0 = 0,
    Ce1 = 1,
    Ce2 = 2,
}

/// SPI modes.
///
/// Select the appropriate SPI mode for your device. Each mode
/// configures the clock polarity (CPOL) and clock phase (CPHA)
/// as shown below:
///
/// * Mode0: CPOL 0, CPHA 0
/// * Mode1: CPOL 0, CPHA 1
/// * Mode2: CPOL 1, CPHA 0
/// * Mode3: CPOL 1, CPHA 1
///
/// More information on clock polarity and phase can be found on [Wikipedia].
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase
pub enum Mode {
    Mode0 = 0, // CPOL 0, CPHA 0
    Mode1 = 1, // CPOL 0, CPHA 1
    Mode2 = 2, // CPOL 1, CPHA 0
    Mode3 = 3, // CPOL 1, CPHA 1
}

pub struct Spi {
    spidev: File,
}

impl Spi {
    pub fn new(bus: Bus, chip_enable: ChipEnable, mode: Mode, speed: u32) -> Result<Spi> {
        let spidev = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/spidev{}.{}", bus as u8, chip_enable as u8))?;

        Ok(Spi { spidev })
    }

    pub fn read(&self, mut buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn write(&self, buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn transfer(&self, mut read_buffer: &[u8], write_buffer: &[u8]) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Functions to flush the translation lookaside buffer (TLB).

/// Invalidate the given address in the TLB using the `invlpg` instruction.
///
/// # Safety
/// This function is unsafe as it causes a general protection fault (GP) if the current privilege
/// level is not 0.
pub unsafe fn flush(addr: usize) {
    asm!("invlpg ($0)" :: "r" (addr) : "memory");
}

/// Invalidate the TLB completely by reloading the CR3 register.
///
/// # Safety
/// This function is unsafe as it causes a general protection fault (GP) if the current privilege
/// level is not 0.
pub unsafe fn flush_all() {
    use crate::controlregs::{cr3, cr3_write};
    cr3_write(cr3())
}
<commit_msg>Add tests for tlb.rs<commit_after>//! Functions to flush the translation lookaside buffer (TLB).

/// Invalidate the given address in the TLB using the `invlpg` instruction.
///
/// # Safety
/// This function is unsafe as it causes a general protection fault (GP) if the current privilege
/// level is not 0.
pub unsafe fn flush(addr: usize) {
    asm!("invlpg ($0)" :: "r" (addr) : "memory");
}

/// Invalidate the TLB completely by reloading the CR3 register.
///
/// # Safety
/// This function is unsafe as it causes a general protection fault (GP) if the current privilege
/// level is not 0.
pub unsafe fn flush_all() {
    use crate::controlregs::{cr3, cr3_write};
    cr3_write(cr3())
}

#[cfg(all(test, feature = "vmtest"))]
mod x86testing {
    use super::*;
    use x86test::*;

    #[x86test]
    fn check_flush_all() {
        unsafe {
            flush_all();
        }
    }

    #[x86test]
    fn check_flush() {
        // A better test would be:
        // map page, read page, unmap page, read page, flush, read page -> pfault
        unsafe {
            flush(0xdeadbeef);
        }
    }
}
<|endoftext|>