<commit_before>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;
pub mod relocation;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek(bytes: &[u8], offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    /// The mach-o header
    pub header: header::Header,
    /// The load commands tell the kernel and dynamic linker how to use/interpret this binary
    pub load_commands: Vec<load_command::LoadCommand>,
    /// The load command "segments" - typically the pieces of the binary that are loaded into memory
    pub segments: load_command::Segments<'a>,
    /// The "Nlist" style symbols in this binary - strippable
    pub symbols: Option<symbols::Symbols<'a>>,
    /// The dylibs this library depends on
    pub libs: Vec<&'a str>,
    /// The entry point, 0 if none
    pub entry: u64,
    /// The name of the dylib, if any
    pub name: Option<&'a str>,
    /// Are we a little-endian binary?
    pub little_endian: bool,
    /// Are we a 64-bit binary
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = scroll::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE);
            self.index += 1;
            Some(arch)
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = scroll::Result<fat::FatArch>;
    type IntoIter = FatArchIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.into_iter() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.into_iter() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    /// A "fat" multi-architecture binary container
    Fat(MultiArch<'a>),
    /// A regular Mach-o binary
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<commit_msg>mach: add a MachO iterator to fat binaries. remove arch iterator as into, which is breaking change :(<commit_after>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;
pub mod relocation;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek(bytes: &[u8], offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    /// The mach-o header
    pub header: header::Header,
    /// The load commands tell the kernel and dynamic linker how to use/interpret this binary
    pub load_commands: Vec<load_command::LoadCommand>,
    /// The load command "segments" - typically the pieces of the binary that are loaded into memory
    pub segments: load_command::Segments<'a>,
    /// The "Nlist" style symbols in this binary - strippable
    pub symbols: Option<symbols::Symbols<'a>>,
    /// The dylibs this library depends on
    pub libs: Vec<&'a str>,
    /// The entry point, 0 if none
    pub entry: u64,
    /// The name of the dylib, if any
    pub name: Option<&'a str>,
    /// Are we a little-endian binary?
    pub little_endian: bool,
    /// Are we a 64-bit binary
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = error::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE).map_err(|e| e.into());
            self.index += 1;
            Some(arch)
        }
    }
}

/// Iterator over every `MachO` binary contained in this `MultiArch` container
pub struct MachOIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for MachOIterator<'a> {
    type Item = error::Result<MachO<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let index = self.index;
            let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
            self.index += 1;
            match self.data.pread_with::<fat::FatArch>(offset, scroll::BE) {
                Ok(arch) => {
                    let bytes = arch.slice(self.data);
                    let binary = MachO::parse(bytes, 0);
                    Some(binary)
                },
                Err(e) => Some(Err(e.into()))
            }
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = error::Result<MachO<'a>>;
    type IntoIter = MachOIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        MachOIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Iterate every fat arch header
    pub fn iter_arches(&self) -> FatArchIterator {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.iter_arches() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    pub fn find<F: (Fn(error::Result<fat::FatArch>) -> bool)>(&'a self, f: F) -> Option<error::Result<MachO<'a>>> {
        for (i, arch) in self.iter_arches().enumerate() {
            if f(arch) {
                return Some(self.get(i));
            }
        }
        None
    }
    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.iter_arches() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    /// A "fat" multi-architecture binary container
    Fat(MultiArch<'a>),
    /// A regular Mach-o binary
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<|endoftext|>


<commit_before>/*!
Memory map files from disk.
*/

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use self::windows::{FileMap, ImageMap};

#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::{FileMap};
<commit_msg>Fix optional mmap feature breaking if not present (#220)<commit_after>/*!
Memory map files from disk.
*/

#[cfg(all(windows, feature = "winapi"))]
mod windows;
#[cfg(all(windows, feature = "winapi"))]
pub use self::windows::{FileMap, ImageMap};

#[cfg(all(unix, feature = "libc"))]
mod unix;
#[cfg(all(unix, feature = "libc"))]
pub use self::unix::{FileMap};
<|endoftext|>


<commit_before>pub fn isalnum(arg1: ::int_t) -> ::int_t {
    extern { fn isalnum(arg1: ::int_t) -> ::int_t; }
    unsafe { isalnum(arg1) }
}

pub fn isalnum_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isalnum_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isalnum_l(arg1, arg2) }
}

pub fn isalpha(arg1: ::int_t) -> ::int_t {
    extern { fn isalpha(arg1: ::int_t) -> ::int_t; }
    unsafe { isalpha(arg1) }
}

pub fn isalpha_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isalpha_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isalpha_l(arg1, arg2) }
}

pub fn isascii(c: ::int_t) -> ::int_t {
    extern { fn isascii(c: ::int_t) -> ::int_t; }
    unsafe { isascii(c) }
}

pub fn isblank(c: ::int_t) -> ::int_t {
    extern { fn isblank(c: ::int_t) -> ::int_t; }
    unsafe { isblank(c) }
}

pub fn isblank_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isblank_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isblank_l(arg1, arg2) }
}

pub fn iscntrl(c: ::int_t) -> ::int_t {
    extern { fn iscntrl(c: ::int_t) -> ::int_t; }
    unsafe { iscntrl(c) }
}

pub fn iscntrl_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn iscntrl_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { iscntrl_l(arg1, arg2) }
}

pub fn isdigit(c: ::int_t) -> ::int_t {
    extern { fn isdigit(c: ::int_t) -> ::int_t; }
    unsafe { isdigit(c) }
}

pub fn isdigit_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isdigit_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isdigit_l(arg1, arg2) }
}

pub fn isgraph(c: ::int_t) -> ::int_t {
    extern { fn isgraph(c: ::int_t) -> ::int_t; }
    unsafe { isgraph(c) }
}

pub fn isgraph_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isgraph_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isgraph_l(arg1, arg2) }
}

pub fn islower(c: ::int_t) -> ::int_t {
    extern { fn islower(c: ::int_t) -> ::int_t; }
    unsafe { islower(c) }
}

pub fn islower_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn islower_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { islower_l(arg1, arg2) }
}

pub fn isprint(c: ::int_t) -> ::int_t {
    extern { fn isprint(c: ::int_t) -> ::int_t; }
    unsafe { isprint(c) }
}

pub fn isprint_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isprint_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isprint_l(arg1, arg2) }
}

pub fn ispunct(c: ::int_t) -> ::int_t {
    extern { fn ispunct(c: ::int_t) -> ::int_t; }
    unsafe { ispunct(c) }
}

pub fn ispunct_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn ispunct_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { ispunct_l(arg1, arg2) }
}

pub fn isspace(c: ::int_t) -> ::int_t {
    extern { fn isspace(c: ::int_t) -> ::int_t; }
    unsafe { isspace(c) }
}

pub fn isspace_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isspace_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isspace_l(arg1, arg2) }
}

pub fn isupper(c: ::int_t) -> ::int_t {
    extern { fn isupper(c: ::int_t) -> ::int_t; }
    unsafe { isupper(c) }
}

pub fn isupper_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isupper_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isupper_l(arg1, arg2) }
}

pub fn isxdigit(c: ::int_t) -> ::int_t {
    extern { fn isxdigit(c: ::int_t) -> ::int_t; }
    unsafe { isxdigit(c) }
}

pub fn isxdigit_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn isxdigit_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { isxdigit_l(arg1, arg2) }
}

pub fn toascii(c: ::int_t) -> ::int_t {
    extern { fn toascii(c: ::int_t) -> ::int_t; }
    unsafe { toascii(c) }
}

pub fn tolower(c: ::int_t) -> ::int_t {
    extern { fn tolower(c: ::int_t) -> ::int_t; }
    unsafe { tolower(c) }
}

pub fn tolower_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn tolower_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { tolower_l(arg1, arg2) }
}

pub fn toupper(c: ::int_t) -> ::int_t {
    extern { fn toupper(c: ::int_t) -> ::int_t; }
    unsafe { toupper(c) }
}

pub fn toupper_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t {
    extern { fn toupper_l(arg1: ::int_t, arg2: ::locale::locale_t) -> ::int_t; }
    unsafe { toupper_l(arg1, arg2) }
}
<commit_msg>ctype.h<commit_after>use {int_t};
use locale::{locale_t};

pub fn isalnum(arg1: int_t) -> int_t {
    extern { fn isalnum(arg1: int_t) -> int_t; }
    unsafe { isalnum(arg1) }
}

pub fn isalnum_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isalnum_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isalnum_l(arg1, arg2) }
}

pub fn isalpha(arg1: int_t) -> int_t {
    extern { fn isalpha(arg1: int_t) -> int_t; }
    unsafe { isalpha(arg1) }
}

pub fn isalpha_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isalpha_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isalpha_l(arg1, arg2) }
}

pub fn isascii(c: int_t) -> int_t {
    extern { fn isascii(c: int_t) -> int_t; }
    unsafe { isascii(c) }
}

pub fn isblank(c: int_t) -> int_t {
    extern { fn isblank(c: int_t) -> int_t; }
    unsafe { isblank(c) }
}

pub fn isblank_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isblank_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isblank_l(arg1, arg2) }
}

pub fn iscntrl(c: int_t) -> int_t {
    extern { fn iscntrl(c: int_t) -> int_t; }
    unsafe { iscntrl(c) }
}

pub fn iscntrl_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn iscntrl_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { iscntrl_l(arg1, arg2) }
}

pub fn isdigit(c: int_t) -> int_t {
    extern { fn isdigit(c: int_t) -> int_t; }
    unsafe { isdigit(c) }
}

pub fn isdigit_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isdigit_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isdigit_l(arg1, arg2) }
}

pub fn isgraph(c: int_t) -> int_t {
    extern { fn isgraph(c: int_t) -> int_t; }
    unsafe { isgraph(c) }
}

pub fn isgraph_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isgraph_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isgraph_l(arg1, arg2) }
}

pub fn islower(c: int_t) -> int_t {
    extern { fn islower(c: int_t) -> int_t; }
    unsafe { islower(c) }
}

pub fn islower_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn islower_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { islower_l(arg1, arg2) }
}

pub fn isprint(c: int_t) -> int_t {
    extern { fn isprint(c: int_t) -> int_t; }
    unsafe { isprint(c) }
}

pub fn isprint_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isprint_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isprint_l(arg1, arg2) }
}

pub fn ispunct(c: int_t) -> int_t {
    extern { fn ispunct(c: int_t) -> int_t; }
    unsafe { ispunct(c) }
}

pub fn ispunct_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn ispunct_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { ispunct_l(arg1, arg2) }
}

pub fn isspace(c: int_t) -> int_t {
    extern { fn isspace(c: int_t) -> int_t; }
    unsafe { isspace(c) }
}

pub fn isspace_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isspace_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isspace_l(arg1, arg2) }
}

pub fn isupper(c: int_t) -> int_t {
    extern { fn isupper(c: int_t) -> int_t; }
    unsafe { isupper(c) }
}

pub fn isupper_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isupper_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isupper_l(arg1, arg2) }
}

pub fn isxdigit(c: int_t) -> int_t {
    extern { fn isxdigit(c: int_t) -> int_t; }
    unsafe { isxdigit(c) }
}

pub fn isxdigit_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn isxdigit_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { isxdigit_l(arg1, arg2) }
}

pub fn toascii(c: int_t) -> int_t {
    extern { fn toascii(c: int_t) -> int_t; }
    unsafe { toascii(c) }
}

pub fn tolower(c: int_t) -> int_t {
    extern { fn tolower(c: int_t) -> int_t; }
    unsafe { tolower(c) }
}

pub fn tolower_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn tolower_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { tolower_l(arg1, arg2) }
}

pub fn toupper(c: int_t) -> int_t {
    extern { fn toupper(c: int_t) -> int_t; }
    unsafe { toupper(c) }
}

pub fn toupper_l(arg1: int_t, arg2: locale_t) -> int_t {
    extern { fn toupper_l(arg1: int_t, arg2: locale_t) -> int_t; }
    unsafe { toupper_l(arg1, arg2) }
}
<|endoftext|>


<commit_before>use mio::{Buf, MutBuf};
use std::mem;
use std::io::Write;
use std::cmp;
use std::str;
use std::fmt;
use tendril;
use queue_backend::Message;

pub type ByteTendril = tendril::Tendril<tendril::fmt::Bytes, tendril::Atomic>;
pub type StrTendril = tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>;

#[derive(Eq, PartialEq, Debug)]
pub enum ProtocolError {
    Incomplete,
    Invalid(&'static str),
}

impl From<&'static str> for ProtocolError {
    fn from(from: &'static str) -> ProtocolError {
        ProtocolError::Invalid(from)
    }
}

pub type ProtocolResult<T> = Result<T, ProtocolError>;

#[derive(Clone)]
pub enum Value {
    Nil,
    Int(i64),
    Data(ByteTendril),
    Array(Vec<Value>),
    Status(StrTendril),
    Error(StrTendril),
    Message((u64, Message)),
}

impl Value {
    fn serialize_to(self, f: &mut Vec<u8>) {
        match self {
            Value::Nil =>
                write!(f, "$-1\r\n"),
            Value::Int(v) =>
                write!(f, ":{}\r\n", v),
            Value::Data(v) => {
                write!(f, "${}\r\n", v.len32()).unwrap();
                f.write_all(v.as_ref()).unwrap();
                write!(f, "\r\n")
            }
            Value::Array(a) => {
                write!(f, "*{}\r\n", a.len()).unwrap();
                for v in a {
                    v.serialize_to(f);
                }
                Ok(())
            },
            Value::Status(v) =>
                write!(f, "+{}\r\n", v.as_ref()),
            Value::Error(v) =>
                write!(f, "-{}\r\n", v.as_ref()),
            Value::Message((ticket, message)) => {
                write!(f, "*2\r\n").unwrap();
                write!(f, ":{}\r\n${}\r\n", ticket, message.body().len()).unwrap();
                f.write(message.body()).unwrap();
                write!(f, "\r\n")
            }
        }.unwrap()
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Value::Nil =>
                write!(f, "Nil"),
            Value::Int(v) =>
                write!(f, "Int({:?})", v),
            Value::Data(ref v) =>
                match str::from_utf8(v) {
                    Ok(s) => write!(f, "Data({:?})", s),
                    Err(_) => write!(f, "Data({:?})", v.as_ref())
                },
            Value::Array(ref b) => {
                try!(write!(f, "Array("));
                try!(f.debug_list().entries(b).finish());
                write!(f, ")")
            },
            Value::Status(ref v) =>
                write!(f, "Status({:?})", v.as_ref()),
            Value::Error(ref v) =>
                write!(f, "Error({:?})", v.as_ref()),
            Value::Message(_) =>
                write!(f, "Message(..)"),
        }
    }
}

#[derive(Debug)]
pub struct ResponseBuffer {
    body: Vec<u8>,
    bytes_written: usize,
}

impl ResponseBuffer {
    pub fn new() -> ResponseBuffer {
        ResponseBuffer {
            body: Vec::new(),
            bytes_written: 0,
        }
    }

    pub fn push_value(&mut self, value: Value) {
        value.serialize_to(&mut self.body);
    }
}

impl Buf for ResponseBuffer {
    fn remaining(&self) -> usize {
        self.body.len() - self.bytes_written
    }

    fn advance(&mut self, cnt: usize) {
        self.bytes_written += cnt;
        // FIXME: poor mans vecdeque
        if self.bytes_written == self.body.len() {
            self.body.clear();
            self.bytes_written = 0;
        }
    }

    fn bytes(&self) -> &[u8] {
        &self.body[self.bytes_written..]
    }
}

#[derive(Debug)]
pub struct RequestBuffer {
    body: ByteTendril,
    bytes_read: u32,
}

impl RequestBuffer {
    pub fn new() -> RequestBuffer {
        RequestBuffer {
            body: ByteTendril::new(),
            bytes_read: 0,
        }
    }

    pub fn pop_value(&mut self) -> ProtocolResult<Value> {
        let mut parser = Parser::new(self.body.subtendril(0, self.bytes_read));
        let parsed = parser.parse();
        if parsed.is_ok() {
            self.body = parser.body;
            self.bytes_read = self.body.len32();
        }
        parsed
    }
}

const MIN_REQUESTBUFFER_SIZE: u32 = 4 * 1024;
impl MutBuf for RequestBuffer {
    fn remaining(&self) -> usize {
        cmp::max(MIN_REQUESTBUFFER_SIZE, self.body.len32() - self.bytes_read) as usize
    }

    fn advance(&mut self, cnt: usize) {
        self.bytes_read += cnt as u32
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        let cur_len = self.body.len32();
        if cur_len - self.bytes_read < MIN_REQUESTBUFFER_SIZE {
            self.body.reserve(MIN_REQUESTBUFFER_SIZE);
            let capacity = self.body.capacity();
            unsafe { self.body.set_len(capacity); }
        }
        &mut self.body[self.bytes_read as usize..]
    }
}

/// The internal redis response parser.
struct Parser {
    body: ByteTendril,
}

impl Parser {
    fn new<T: Into<ByteTendril>>(body: T) -> Parser {
        Parser {
            body: body.into()
        }
    }

    /// parses a single value out of the stream.  If there are multiple
    /// values you can call this multiple times.
    fn parse(&mut self) -> ProtocolResult<Value> {
        match try!(self.read_byte()) {
            b'+' => self.parse_status(),
            b':' => self.parse_int(),
            b'$' => self.parse_data(),
            b'*' => self.parse_array(),
            b'-' => self.parse_error(),
            _ => Err("Invalid response when parsing value".into()),
        }
    }

    #[inline]
    fn read_byte(&mut self) -> ProtocolResult<u8> {
        if self.body.len() >= 1 {
            let byte = self.body[0];
            self.body.pop_front(1);
            return Ok(byte)
        } else {
            Err(ProtocolError::Incomplete)
        }
    }

    #[inline]
    fn read(&mut self, bytes: usize) -> ProtocolResult<ByteTendril> {
        if self.body.len() >= bytes {
            let (first_part, second_part) = Self::split_at(self.body.clone(), bytes);
            self.body = second_part;
            return Ok(first_part)
        } else {
            Err(ProtocolError::Incomplete)
        }
    }

    fn split_at(mut tendril: ByteTendril, position: usize) -> (ByteTendril, ByteTendril) {
        let offset = position as u32;
        let len = tendril.len32() - offset;
        let second_part = tendril.subtendril(offset, len);
        tendril.pop_back(len);
        (tendril, second_part)
    }

    fn read_line(&mut self) -> ProtocolResult<ByteTendril> {
        let nl_pos = match self.body.iter().position(|&b| b == b'\r') {
            Some(nl_pos) => nl_pos,
            None => return Err("Missing line separator".into()),
        };
        let (first_part, second_part) = Self::split_at(try!(self.read(nl_pos + 2)), nl_pos);
        if second_part.as_ref() != b"\r\n" {
            return Err("Invalid line separator".into())
        }

        Ok(first_part)
    }

    fn read_string_line(&mut self) -> ProtocolResult<StrTendril> {
        let line = try!(self.read_line());
        match str::from_utf8(line.as_ref()) {
            Ok(_) => Ok(unsafe { mem::transmute(line) }),
            Err(_) => Err("Expected valid string, got garbage".into())
        }
    }

    fn read_int_line(&mut self) -> ProtocolResult<i64> {
        let line = try!(self.read_line());
        let line_str = unsafe { str::from_utf8_unchecked(line.as_ref()) };
        match line_str.parse::<i64>() {
            Err(_) => Err("Expected integer, got garbage".into()),
            Ok(value) => Ok(value)
        }
    }

    fn parse_status(&mut self) -> ProtocolResult<Value> {
        let line = try!(self.read_string_line());
        Ok(Value::Status(line))
    }

    fn parse_int(&mut self) -> ProtocolResult<Value> {
        Ok(Value::Int(try!(self.read_int_line())))
    }

    fn parse_data(&mut self) -> ProtocolResult<Value> {
        let length = try!(self.read_int_line());
        if length < 0 {
            Ok(Value::Nil)
        } else {
            let length = length as usize;
            let (data, line_sep) = Self::split_at(try!(self.read(length + 2)), length);
            if line_sep.as_ref() != b"\r\n" {
                return Err("Invalid line separator".into())
            }
            Ok(Value::Data(data))
        }
    }

    fn parse_array(&mut self) -> ProtocolResult<Value> {
        let length = try!(self.read_int_line());
        if length < 0 {
            Ok(Value::Nil)
        } else {
            let mut rv = Vec::with_capacity(length as usize);
            for _ in 0..length {
                let value = try!(self.parse());
                rv.push(value);
            }
            Ok(Value::Array(rv))
        }
    }

    fn parse_error(&mut self) -> ProtocolResult<Value> {
        let line = try!(self.read_string_line());
        Ok(Value::Error(line))
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestBuffer, ProtocolResult, ProtocolError, Parser, Value};
    use std::io::Write;
    use mio::MutBuf;

    fn parse(slice: &[u8]) -> ProtocolResult<Value> {
        Parser::new(slice).parse()
    }

    macro_rules! assert_eq_repr {
        ($left:expr , $right:expr) => ({
            match (format!("{:?}", &$left), format!("{:?}", &$right)) {
                (left_val, right_val) => {
                    if !(left_val == right_val) {
                        panic!("repr assertion failed: `(debug(left) == debug(right))` \
                               (left: `{:?}`, right: `{:?}`)", left_val, right_val)
                    }
                }
            }
        })
    }

    #[test]
    fn parse_incomplete() {
        let r = parse(b"*2\r\n$3\r\nfoo");
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
    }

    #[test]
    fn parse_error() {
        let r = parse(b"-foo\r\n");
        assert_eq_repr!(r.unwrap(), Value::Error("foo".into()));

        let r = parse(b"-invalid line sep\r\r");
        assert!(if let ProtocolError::Invalid(_) = r.unwrap_err() {true} else {false});
    }

    #[test]
    fn parse_valid_array() {
        let r = parse(b"*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n");
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(
            r.unwrap(),
            Value::Array(vec![
                Value::Data(b"foo".as_ref().into()),
                Value::Data(b"barz".as_ref().into())
            ])
        );
    }

    #[test]
    fn parser_multiple2() {
        let mut parser = Parser::new(
            b"*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n".as_ref(),
        );
        for _ in 0..2 {
            let r = parser.parse();
            assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
            assert_eq_repr!(
                r.unwrap(),
                Value::Array(vec![
                    Value::Data(b"foo".as_ref().into()),
                    Value::Data(b"barz".as_ref().into())
                ])
            );
        }
        let r = parser.parse();
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
    }

    #[test]
    fn request_parse() {
        let mut req = RequestBuffer::new();
        req.mut_bytes().write_all(b"+OK\r").unwrap();
        req.advance(4);
        let r = req.pop_value();
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
        req.mut_bytes().write_all(b"\n:100\r\n").unwrap();
        req.advance(7);
        let r = req.pop_value();
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(r.unwrap(), Value::Status("OK".into()));
        let r = req.pop_value();
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(r.unwrap(), Value::Int(100));
    }
}<commit_msg>use write_all to write to buffer<commit_after>use mio::{Buf, MutBuf};
use std::mem;
use std::io::Write;
use std::cmp;
use std::str;
use std::fmt;
use tendril;
use queue_backend::Message;

pub type ByteTendril = tendril::Tendril<tendril::fmt::Bytes, tendril::Atomic>;
pub type StrTendril = tendril::Tendril<tendril::fmt::UTF8, tendril::Atomic>;

#[derive(Eq, PartialEq, Debug)]
pub enum ProtocolError {
    Incomplete,
    Invalid(&'static str),
}

impl From<&'static str> for ProtocolError {
    fn from(from: &'static str) -> ProtocolError {
        ProtocolError::Invalid(from)
    }
}

pub type ProtocolResult<T> = Result<T, ProtocolError>;

#[derive(Clone)]
pub enum Value {
    Nil,
    Int(i64),
    Data(ByteTendril),
    Array(Vec<Value>),
    Status(StrTendril),
    Error(StrTendril),
    Message((u64, Message)),
}

impl Value {
    fn serialize_to(self, f: &mut Vec<u8>) {
        match self {
            Value::Nil =>
                write!(f, "$-1\r\n"),
            Value::Int(v) =>
                write!(f, ":{}\r\n", v),
            Value::Data(v) => {
                write!(f, "${}\r\n", v.len32()).unwrap();
                f.write_all(v.as_ref()).unwrap();
                write!(f, "\r\n")
            }
            Value::Array(a) => {
                write!(f, "*{}\r\n", a.len()).unwrap();
                for v in a {
                    v.serialize_to(f);
                }
                Ok(())
            },
            Value::Status(v) =>
                write!(f, "+{}\r\n", v.as_ref()),
            Value::Error(v) =>
                write!(f, "-{}\r\n", v.as_ref()),
            Value::Message((ticket, message)) => {
                write!(f, "*2\r\n:{}\r\n:${}\r\n", ticket, message.body().len()).unwrap();
                f.write_all(message.body()).unwrap();
                write!(f, "\r\n")
            }
        }.unwrap()
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Value::Nil =>
                write!(f, "Nil"),
            Value::Int(v) =>
                write!(f, "Int({:?})", v),
            Value::Data(ref v) =>
                match str::from_utf8(v) {
                    Ok(s) => write!(f, "Data({:?})", s),
                    Err(_) => write!(f, "Data({:?})", v.as_ref())
                },
            Value::Array(ref b) => {
                try!(write!(f, "Array("));
                try!(f.debug_list().entries(b).finish());
                write!(f, ")")
            },
            Value::Status(ref v) =>
                write!(f, "Status({:?})", v.as_ref()),
            Value::Error(ref v) =>
                write!(f, "Error({:?})", v.as_ref()),
            Value::Message(_) =>
                write!(f, "Message(..)"),
        }
    }
}

#[derive(Debug)]
pub struct ResponseBuffer {
    body: Vec<u8>,
    bytes_written: usize,
}

impl ResponseBuffer {
    pub fn new() -> ResponseBuffer {
        ResponseBuffer {
            body: Vec::new(),
            bytes_written: 0,
        }
    }

    pub fn push_value(&mut self, value: Value) {
        value.serialize_to(&mut self.body);
    }
}

impl Buf for ResponseBuffer {
    fn remaining(&self) -> usize {
        self.body.len() - self.bytes_written
    }

    fn advance(&mut self, cnt: usize) {
        self.bytes_written += cnt;
        // FIXME: poor mans vecdeque
        if self.bytes_written == self.body.len() {
            self.body.clear();
            self.bytes_written = 0;
        }
    }

    fn bytes(&self) -> &[u8] {
        &self.body[self.bytes_written..]
    }
}

#[derive(Debug)]
pub struct RequestBuffer {
    body: ByteTendril,
    bytes_read: u32,
}

impl RequestBuffer {
    pub fn new() -> RequestBuffer {
        RequestBuffer {
            body: ByteTendril::new(),
            bytes_read: 0,
        }
    }

    pub fn pop_value(&mut self) -> ProtocolResult<Value> {
        let mut parser = Parser::new(self.body.subtendril(0, self.bytes_read));
        let parsed = parser.parse();
        if parsed.is_ok() {
            self.body = parser.body;
            self.bytes_read = self.body.len32();
        }
        parsed
    }
}

const MIN_REQUESTBUFFER_SIZE: u32 = 4 * 1024;
impl MutBuf for RequestBuffer {
    fn remaining(&self) -> usize {
        cmp::max(MIN_REQUESTBUFFER_SIZE, self.body.len32() - self.bytes_read) as usize
    }

    fn advance(&mut self, cnt: usize) {
        self.bytes_read += cnt as u32
    }

    fn mut_bytes(&mut self) -> &mut [u8] {
        let cur_len = self.body.len32();
        if cur_len - self.bytes_read < MIN_REQUESTBUFFER_SIZE {
            self.body.reserve(MIN_REQUESTBUFFER_SIZE);
            let capacity = self.body.capacity();
            unsafe { self.body.set_len(capacity); }
        }
        &mut self.body[self.bytes_read as usize..]
    }
}

/// The internal redis response parser.
struct Parser {
    body: ByteTendril,
}

impl Parser {
    fn new<T: Into<ByteTendril>>(body: T) -> Parser {
        Parser {
            body: body.into()
        }
    }

    /// parses a single value out of the stream.  If there are multiple
    /// values you can call this multiple times.
    fn parse(&mut self) -> ProtocolResult<Value> {
        match try!(self.read_byte()) {
            b'+' => self.parse_status(),
            b':' => self.parse_int(),
            b'$' => self.parse_data(),
            b'*' => self.parse_array(),
            b'-' => self.parse_error(),
            _ => Err("Invalid response when parsing value".into()),
        }
    }

    #[inline]
    fn read_byte(&mut self) -> ProtocolResult<u8> {
        if self.body.len() >= 1 {
            let byte = self.body[0];
            self.body.pop_front(1);
            return Ok(byte)
        } else {
            Err(ProtocolError::Incomplete)
        }
    }

    #[inline]
    fn read(&mut self, bytes: usize) -> ProtocolResult<ByteTendril> {
        if self.body.len() >= bytes {
            let (first_part, second_part) = Self::split_at(self.body.clone(), bytes);
            self.body = second_part;
            return Ok(first_part)
        } else {
            Err(ProtocolError::Incomplete)
        }
    }

    fn split_at(mut tendril: ByteTendril, position: usize) -> (ByteTendril, ByteTendril) {
        let offset = position as u32;
        let len = tendril.len32() - offset;
        let second_part = tendril.subtendril(offset, len);
        tendril.pop_back(len);
        (tendril, second_part)
    }

    fn read_line(&mut self) -> ProtocolResult<ByteTendril> {
        let nl_pos = match self.body.iter().position(|&b| b == b'\r') {
            Some(nl_pos) => nl_pos,
            None => return Err("Missing line separator".into()),
        };
        let (first_part, second_part) = Self::split_at(try!(self.read(nl_pos + 2)), nl_pos);
        if second_part.as_ref() != b"\r\n" {
            return Err("Invalid line separator".into())
        }

        Ok(first_part)
    }

    fn read_string_line(&mut self) -> ProtocolResult<StrTendril> {
        let line = try!(self.read_line());
        match str::from_utf8(line.as_ref()) {
            Ok(_) => Ok(unsafe { mem::transmute(line) }),
            Err(_) => Err("Expected valid string, got garbage".into())
        }
    }

    fn read_int_line(&mut self) -> ProtocolResult<i64> {
        let line = try!(self.read_line());
        let line_str = unsafe { str::from_utf8_unchecked(line.as_ref()) };
        match line_str.parse::<i64>() {
            Err(_) => Err("Expected integer, got garbage".into()),
            Ok(value) => Ok(value)
        }
    }

    fn parse_status(&mut self) -> ProtocolResult<Value> {
        let line = try!(self.read_string_line());
        Ok(Value::Status(line))
    }

    fn parse_int(&mut self) -> ProtocolResult<Value> {
        Ok(Value::Int(try!(self.read_int_line())))
    }

    fn parse_data(&mut self) -> ProtocolResult<Value> {
        let length = try!(self.read_int_line());
        if length < 0 {
            Ok(Value::Nil)
        } else {
            let length = length as usize;
            let (data, line_sep) = Self::split_at(try!(self.read(length + 2)), length);
            if line_sep.as_ref() != b"\r\n" {
                return Err("Invalid line separator".into())
            }
            Ok(Value::Data(data))
        }
    }

    fn parse_array(&mut self) -> ProtocolResult<Value> {
        let length = try!(self.read_int_line());
        if length < 0 {
            Ok(Value::Nil)
        } else {
            let mut rv = Vec::with_capacity(length as usize);
            for _ in 0..length {
                let value = try!(self.parse());
                rv.push(value);
            }
            Ok(Value::Array(rv))
        }
    }

    fn parse_error(&mut self) -> ProtocolResult<Value> {
        let line = try!(self.read_string_line());
        Ok(Value::Error(line))
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestBuffer, ProtocolResult, ProtocolError, Parser, Value};
    use std::io::Write;
    use mio::MutBuf;

    fn parse(slice: &[u8]) -> ProtocolResult<Value> {
        Parser::new(slice).parse()
    }

    macro_rules! assert_eq_repr {
        ($left:expr , $right:expr) => ({
            match (format!("{:?}", &$left), format!("{:?}", &$right)) {
                (left_val, right_val) => {
                    if !(left_val == right_val) {
                        panic!("repr assertion failed: `(debug(left) == debug(right))` \
                               (left: `{:?}`, right: `{:?}`)", left_val, right_val)
                    }
                }
            }
        })
    }

    #[test]
    fn parse_incomplete() {
        let r = parse(b"*2\r\n$3\r\nfoo");
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
    }

    #[test]
    fn parse_error() {
        let r = parse(b"-foo\r\n");
        assert_eq_repr!(r.unwrap(), Value::Error("foo".into()));

        let r = parse(b"-invalid line sep\r\r");
        assert!(if let ProtocolError::Invalid(_) = r.unwrap_err() {true} else {false});
    }

    #[test]
    fn parse_valid_array() {
        let r = parse(b"*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n");
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(
            r.unwrap(),
            Value::Array(vec![
                Value::Data(b"foo".as_ref().into()),
                Value::Data(b"barz".as_ref().into())
            ])
        );
    }

    #[test]
    fn parser_multiple2() {
        let mut parser = Parser::new(
            b"*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n*2\r\n$3\r\nfoo\r\n$4\r\nbarz\r\n".as_ref(),
        );
        for _ in 0..2 {
            let r = parser.parse();
            assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
            assert_eq_repr!(
                r.unwrap(),
                Value::Array(vec![
                    Value::Data(b"foo".as_ref().into()),
                    Value::Data(b"barz".as_ref().into())
                ])
            );
        }
        let r = parser.parse();
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
    }

    #[test]
    fn request_parse() {
        let mut req = RequestBuffer::new();
        req.mut_bytes().write_all(b"+OK\r").unwrap();
        req.advance(4);
        let r = req.pop_value();
        assert_eq_repr!(r.unwrap_err(), ProtocolError::Incomplete);
        req.mut_bytes().write_all(b"\n:100\r\n").unwrap();
        req.advance(7);
        let r = req.pop_value();
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(r.unwrap(), Value::Status("OK".into()));
        let r = req.pop_value();
        assert!(r.is_ok(), "{:?} not ok", r.unwrap_err());
        assert_eq_repr!(r.unwrap(), Value::Int(100));
    }
}<|endoftext|>


<commit_before>use std::io::{Cursor, Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};
use std::str::{
    from_utf8
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};

enum Types {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Commands {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Protocol {
        assert_eq!(size_of::<Response>(), 24);
        Protocol{connection: TcpStream::connect(addr).unwrap()}
    }

    fn set(&mut self, key: &'static str, value: &'static str, time: u32) -> usize {
        let extras_length = size_of::<SetAddReplace>() as u8;
        println!("Using command {:?} with value {:?}", Commands::Set, Commands::Set as u8);
        println!("Extras length {:?}", extras_length);
        let request = Request{magic: Types::Request as u8, opcode: Commands::Set as u8,
            key_length: key.len() as u16,
            extras_length: extras_length,
            data_type: 0, reserved: 0, body_length: key.len() as u32 + value.len() as u32 + extras_length as u32,
            opaque: 0, cas: 0x00};
        let mut buf = vec![];
        buf.write_u8(request.magic).unwrap();
        buf.write_u8(request.opcode).unwrap();
        buf.write_u16::<BigEndian>(request.key_length).unwrap();
        buf.write_u8(request.extras_length).unwrap();
        buf.write_u8(request.data_type).unwrap();
        buf.write_u16::<BigEndian>(request.reserved).unwrap();
        buf.write_u32::<BigEndian>(request.body_length).unwrap();
        buf.write_u32::<BigEndian>(request.opaque).unwrap();
        buf.write_u64::<BigEndian>(request.cas).unwrap();
        // Flags
        buf.write_u32::<BigEndian>(0);
        buf.write_u32::<BigEndian>(time).unwrap();
        buf.write(key.as_bytes()).unwrap();
        buf.write(value.as_bytes()).unwrap();
        println!("{:?} {}", buf, buf.len());
        let wrote_size = self.connection.write(buf.as_slice()).unwrap();
        let mut outbuf = [0; 24];
        self.connection.read_exact(&mut outbuf).unwrap();
        println!("{:?} {}", outbuf, outbuf.len());
        wrote_size
    }

    fn get(&mut self, key: &'static str) -> String {
        println!("Get");
        let request = Request{magic: Types::Request as u8, opcode: Commands::Get as u8,
            key_length: key.len() as u16,
            extras_length: 0,
            data_type: 0, reserved: 0, body_length: key.len() as u32,
            opaque: 0, cas: 0x00};
            let mut buf = vec![];
            buf.write_u8(request.magic).unwrap();
            buf.write_u8(request.opcode).unwrap();
            buf.write_u16::<BigEndian>(request.key_length).unwrap();
            buf.write_u8(request.extras_length).unwrap();
            buf.write_u8(request.data_type).unwrap();
            buf.write_u16::<BigEndian>(request.reserved).unwrap();
            buf.write_u32::<BigEndian>(request.body_length).unwrap();
            buf.write_u32::<BigEndian>(request.opaque).unwrap();
            buf.write_u64::<BigEndian>(request.cas).unwrap();
            buf.write(key.as_bytes()).unwrap();
            println!("Request read {:?}", buf);
            self.connection.write(buf.as_slice()).unwrap();
            let mut outbuf = [0; 24];
            self.connection.read_exact(&mut outbuf).unwrap();
            println!("Got {:?} of size {:?}", outbuf, outbuf.len());
            let mut cur = Cursor::new(outbuf);
            assert_eq!(Types::Response as u8, cur.read_u8().unwrap());
            let mut read_return = [0; 5];
            self.connection.read_u32::<BigEndian>().unwrap();
            self.connection.read_exact(&mut read_return);
            let a = from_utf8(&read_return).unwrap();
            a.to_owned()
    }
}

#[test]
fn test_set_key() {
    let mut p = Protocol::connect("127.0.0.1:11211");
    assert_eq!(p.set("Hello", "World", 100), 201);
}

#[test]
fn test_get_key() {
    let mut p = Protocol::connect("127.0.0.1:11211");
    p.set("Hello", "World", 100);
    assert_eq!(p.get("Hello"),  "World");
}
<commit_msg>Cleanup code a bit<commit_after>use std::io::{Cursor, Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};
use std::str::{
    from_utf8
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};

enum Types {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Commands {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Protocol {
        assert_eq!(size_of::<Response>(), 24);
        Protocol{connection: TcpStream::connect(addr).unwrap()}
    }

    fn build_request(command: Commands, key_length: usize, value_length: usize, data_type: u8, extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Types::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0, body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: 0x00
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> usize {
        let mut buf = &self.connection;
        buf.write_u8(request.magic).unwrap();
        buf.write_u8(request.opcode).unwrap();
        buf.write_u16::<BigEndian>(request.key_length).unwrap();
        buf.write_u8(request.extras_length).unwrap();
        buf.write_u8(request.data_type).unwrap();
        buf.write_u16::<BigEndian>(request.reserved).unwrap();
        buf.write_u32::<BigEndian>(request.body_length).unwrap();
        buf.write_u32::<BigEndian>(request.opaque).unwrap();
        buf.write_u64::<BigEndian>(request.cas).unwrap();
        buf.write(final_payload).unwrap()
    }

    fn set_add_replace(&mut self, command: Commands, key: &'static str, value: &'static str, time: u32) -> usize {
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        final_payload.write_u32::<BigEndian>(0);
        final_payload.write_u32::<BigEndian>(time).unwrap();
        // After flags key and value
        final_payload.write(key.as_bytes()).unwrap();
        final_payload.write(value.as_bytes()).unwrap();
        let size = self.write_request(request, final_payload.as_slice());
        self.read_response();
        size
    }

    fn read_response(&mut self) -> Response {
        let mut buf = &self.connection;
        let magic: u8 = buf.read_u8().unwrap();
        assert_eq!(magic, Types::Response as u8);
        Response {
            magic: magic,
            opcode: buf.read_u8().unwrap(),
            key_length: buf.read_u16::<BigEndian>().unwrap(),
            extras_length: buf.read_u8().unwrap(),
            data_type: buf.read_u8().unwrap(),
            status: buf.read_u16::<BigEndian>().unwrap(),
            body_length: buf.read_u32::<BigEndian>().unwrap(),
            opaque: buf.read_u32::<BigEndian>().unwrap(),
            cas: buf.read_u64::<BigEndian>().unwrap()
        }
    }

    fn set(&mut self, key: &'static str, value: &'static str, time: u32) -> usize {
        self.set_add_replace(Commands::Set, key, value, time)
    }

    fn add(&mut self, key: &'static str, value: &'static str, time: u32) -> usize {
        self.set_add_replace(Commands::Add, key, value, time)
    }

    fn replace(&mut self, key: &'static str, value: &'static str, time: u32) -> usize {
        self.set_add_replace(Commands::Replace, key, value, time)
    }

    fn get(&mut self, key: &'static str) -> String {
        let request = Protocol::build_request(Commands::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key.as_bytes());
        let response = self.read_response();
        // Discard extras for now
        self.connection.read_u32::<BigEndian>().unwrap();
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        self.connection.read_exact(&mut outbuf).unwrap();
        println!("{:?} {:?}", outbuf, outbuf.len());
        let a = from_utf8(&outbuf).unwrap();
        a.to_owned()
    }
}

#[test]
fn test_get_key() {
    let mut p = Protocol::connect("127.0.0.1:11211");
    p.set("Hello", "World", 100);
    assert_eq!(p.get("Hello"),  "World");
}
<|endoftext|>


<commit_before>extern crate rand;

type Flt = f32;
type Flt2 = (Flt, Flt);

struct RaytraceParams {
    origin: Flt2,
    iters_per_frame: u32,
}

const PARAMS: RaytraceParams = RaytraceParams {
    origin: (10.0, 10.0),
    iters_per_frame: 50,
};

fn next_voxel(pos: Flt2, dir: Flt2) -> Flt2 {
    let tdelta = (1.0 / dir.0, 1.0 / dir.1);
    let tmax = (tdelta.0 * (1.0 - pos.0.fract()),
                tdelta.1 * (1.0 - pos.1.fract()));
    let max = if tmax.0 > 0.0 && tmax.0 < tmax.1 {
        tmax.0
    } else {
        tmax.1
    };
    (pos.0 + dir.0 * max, pos.1 + dir.1 * max)
}

fn validate_bounds(point: (i32, i32), size: (u32, u32)) -> Option<(u32, u32)> {
    if point.0 < 0 || point.0 >= size.0 as i32 || point.1 < 0 || point.1 >= size.1 as i32 {
        None
    } else {
        Some((point.0 as u32, point.1 as u32))
    }
}

fn write_pixel(data: &mut [u8], size: (u32, u32), index: (u32, u32)) {
    let offset = ((index.1 * size.0 + index.0) * 3) as usize;
    data[offset + 0] += 1;
    data[offset + 1] += 1;
    data[offset + 2] += 1;
}

fn raytrace(data: &mut [u8], width: u32) {
    let height = data.len() as u32 / width;
    let mut pos = PARAMS.origin;
    let dir = {
        let theta: Flt = rand::random::<Flt>() * 6.28318530718;
        (theta.cos(), theta.sin())
    };
    loop {
        let floor_pos = (pos.0.floor() as i32, pos.1.floor() as i32);
        if let Some(ipos) = validate_bounds(floor_pos, (width, height)) {
            write_pixel(data, (width, height), ipos);
        } else {
            break;
        }
        pos = next_voxel(pos, dir);
    }
}
<commit_msg>Fix wrapping add<commit_after>extern crate rand;

type Flt = f32;
type Flt2 = (Flt, Flt);

struct RaytraceParams {
    origin: Flt2,
    iters_per_frame: u32,
}

const PARAMS: RaytraceParams = RaytraceParams {
    origin: (10.0, 10.0),
    iters_per_frame: 50,
};

fn next_voxel(pos: Flt2, dir: Flt2) -> Flt2 {
    let tdelta = (1.0 / dir.0, 1.0 / dir.1);
    let tmax = (tdelta.0 * (1.0 - pos.0.fract()),
                tdelta.1 * (1.0 - pos.1.fract()));
    let max = if tmax.0 > 0.0 && tmax.0 < tmax.1 {
        tmax.0
    } else {
        tmax.1
    };
    (pos.0 + dir.0 * max, pos.1 + dir.1 * max)
}

fn validate_bounds(point: (i32, i32), size: (u32, u32)) -> Option<(u32, u32)> {
    if point.0 < 0 || point.0 >= size.0 as i32 || point.1 < 0 || point.1 >= size.1 as i32 {
        None
    } else {
        Some((point.0 as u32, point.1 as u32))
    }
}

fn write_pixel(data: &mut [u8], size: (u32, u32), index: (u32, u32)) {
    let offset = ((index.1 * size.0 + index.0) * 3) as usize;
    data[offset + 0] = data[offset + 0].wrapping_add(1);
    data[offset + 1] = data[offset + 1].wrapping_add(1);
    data[offset + 2] = data[offset + 2].wrapping_add(1);
}

pub fn raytrace(data: &mut [u8], width: u32) {
    let height = data.len() as u32 / width;
    let mut pos = PARAMS.origin;
    let dir = {
        let theta: Flt = rand::random::<Flt>() * 6.28318530718;
        (theta.cos(), theta.sin())
    };
    loop {
        let floor_pos = (pos.0.floor() as i32, pos.1.floor() as i32);
        if let Some(ipos) = validate_bounds(floor_pos, (width, height)) {
            write_pixel(data, (width, height), ipos);
        } else {
            break;
        }
        pos = next_voxel(pos, dir);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::Write;

use serialize::json::ToJson;

use template::{Template};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;
use TemplateError;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        let t = Template::compile(tpl_str);
        if let Ok(tpl) = t {
            self.templates.insert(name.to_string(), tpl);
            Ok(())
        } else {
            Err(t.err().unwrap())
        }
    }

    pub fn unregister_template(&mut self, name: &String) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

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

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        let context = Context::wraps(ctx);
        {
            try!(self.renderw(name, &context, &mut writer));
        }
        Ok(writer.to_string())
    }

    pub fn renderw(&self, name: &str, context: &Context, writer: &mut Write) -> Result<(), RenderError> {
        let template = self.get_template(&name.to_string());

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            (*t).render(context, self, &mut render_context)
        } else {
            Err(RenderError{
                desc: "Template not found."
            })
        }
    }
}

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};
    use support::str::StringWriter;

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }

    #[test]
    fn test_renderw() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let mut sw = StringWriter::new();
        let context = Context::null();

        {
            r.renderw("index", &context, &mut sw).ok().unwrap();
        }

        assert_eq!("

".to_string(), sw.to_string());

    }
}
<commit_msg>(fix) improve template registration<commit_after>use std::collections::HashMap;
use std::io::Write;

use serialize::json::ToJson;

use template::{Template};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;
use TemplateError;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        try!(Template::compile(tpl_str).and_then(|t| Ok(self.templates.insert(name.to_string(), t))));
        Ok(())
    }

    pub fn unregister_template(&mut self, name: &String) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

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

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        let context = Context::wraps(ctx);
        {
            try!(self.renderw(name, &context, &mut writer));
        }
        Ok(writer.to_string())
    }

    pub fn renderw(&self, name: &str, context: &Context, writer: &mut Write) -> Result<(), RenderError> {
        let template = self.get_template(&name.to_string());

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            (*t).render(context, self, &mut render_context)
        } else {
            Err(RenderError{
                desc: "Template not found."
            })
        }
    }
}

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};
    use support::str::StringWriter;

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }

    #[test]
    fn test_renderw() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let mut sw = StringWriter::new();
        let context = Context::null();

        {
            r.renderw("index", &context, &mut sw).ok().unwrap();
        }

        assert_eq!("

".to_string(), sw.to_string());

    }
}
<|endoftext|>


<commit_before>use std::slice;
use std::str;

// Not necessarily ABI compatible with &str. Codegen performs the translation.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RustStr {
    ptr: *const u8,
    len: usize,
}

impl RustStr {
    pub fn from(s: &str) -> Self {
        RustStr {
            ptr: s.as_ptr(),
            len: s.len(),
        }
    }

    pub unsafe fn as_str<'a>(self) -> &'a str {
        let slice = slice::from_raw_parts(self.ptr, self.len);
        str::from_utf8_unchecked(slice)
    }
}

#[export_name = "cxxbridge02$str$valid"]
unsafe extern "C" fn str_valid(ptr: *const u8, len: usize) -> bool {
    let slice = slice::from_raw_parts(ptr, len);
    str::from_utf8(slice).is_ok()
}
<commit_msg>Add niche to RustStr<commit_after>use std::mem;
use std::ptr::NonNull;
use std::slice;
use std::str;

// Not necessarily ABI compatible with &str. Codegen performs the translation.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RustStr {
    ptr: NonNull<u8>,
    len: usize,
}

impl RustStr {
    pub fn from(s: &str) -> Self {
        RustStr {
            ptr: NonNull::from(s).cast::<u8>(),
            len: s.len(),
        }
    }

    pub unsafe fn as_str<'a>(self) -> &'a str {
        let slice = slice::from_raw_parts(self.ptr.as_ptr(), self.len);
        str::from_utf8_unchecked(slice)
    }
}

#[export_name = "cxxbridge02$str$valid"]
unsafe extern "C" fn str_valid(ptr: *const u8, len: usize) -> bool {
    let slice = slice::from_raw_parts(ptr, len);
    str::from_utf8(slice).is_ok()
}

const_assert!(mem::size_of::<Option<RustStr>>() == mem::size_of::<RustStr>());
<|endoftext|>


<commit_before>use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use sys::sdl as ll;
use event::EventPump;
use keyboard::KeyboardState;
use video::WindowBuilder;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

pub type SdlResult<T> = Result<T, String>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// Only one instance of `Sdl` is allowed per process, and cannot be moved or
/// used across non-main threads.
///
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
pub struct Sdl {
    _nosyncsend: PhantomData<*mut ()>
}

impl Sdl {
    /// Returns the mask of the specified subsystems which have previously been initialized.
    pub fn was_init(&self, flags: u32) -> u32 {
        unsafe {
            ll::SDL_WasInit(flags)
        }
    }

    /// Obtains the SDL event pump.
    pub fn event_pump(&mut self) -> EventPump {
        EventPump::new(self)
    }

    pub fn keyboard_state(&self) -> KeyboardState {
        KeyboardState::new(self)
    }

    /// Initializes a new `WindowBuilder`; a convenience method that calls `WindowBuilder::new()`.
    pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
        WindowBuilder::new(self, title, width, height)
    }
}

impl Drop for Sdl {
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

/// A RAII value representing initalized SDL subsystems. See `sdl2::Sdl::init_subsystem()`.
///
/// Subsystem initialization is ref-counted. Once `Subsystem::drop()` is called,
/// the specified subsystems' ref-counts are decremented via `SDL_QuitSubSystem`.
pub struct Subsystem<'sdl> {
    flags: u32,
    _marker: PhantomData<&'sdl Sdl>
}

impl<'sdl> Drop for Subsystem<'sdl> {
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flags); }
    }
}

/// The type that allows you to build the SDL2 context.
pub struct InitBuilder {
    flags: u32
}

impl InitBuilder {
    /// Initializes a new `InitBuilder`.
    pub fn new() -> InitBuilder {
        InitBuilder { flags: 0 }
    }

    /// Builds the SDL2 context.
    pub fn build(&self) -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(format!("Cannot have more than one `Sdl` in use at the same time"))
            } else {
                if ll::SDL_Init(self.flags) == 0 {
                    Ok(Sdl {
                        _nosyncsend: PhantomData
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Builds the SDL2 context. Convenience method for `.build().unwrap()`.
    ///
    /// Panics if there was an error initializing SDL2.
    pub fn unwrap(&self) -> Sdl { self.build().unwrap() }

    /// Builds an SDL2 subsystem. Requires SDL2 to have already been initialized.
    pub fn build_subsystem(&self, _sdl: &Sdl) -> SdlResult<Subsystem> {
        unsafe {
            if ll::SDL_InitSubSystem(self.flags) == 0 {
                Ok(Subsystem {
                    flags: self.flags,
                    _marker: PhantomData
                })
            } else {
                Err(get_error())
            }
        }
    }

    /// Initializes every subsystem.
    pub fn everything(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_EVERYTHING as u32;
        self
    }

    /// Initializes the timer subsystem.
    pub fn timer(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_TIMER as u32;
        self
    }

    /// Initializes the audio subsystem.
    pub fn audio(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_AUDIO as u32;
        self
    }

    /// Initializes the video subsystem.
    pub fn video(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_VIDEO as u32;
        self
    }

    /// Initializes the joystick subsystem.
    pub fn joystick(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_JOYSTICK as u32;
        self
    }

    /// Initializes the haptic (force feedback) subsystem.
    pub fn haptic(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_HAPTIC as u32;
        self
    }

    /// Initializes the controller subsystem.
    pub fn game_controller(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_GAMECONTROLLER as u32;
        self
    }

    /// Initializes the events subsystem.
    pub fn events(&mut self) -> &mut InitBuilder {
        self.flags |= ll::SDL_INIT_EVENTS as u32;
        self
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let mut sdl_context = sdl2::init().everything().unwrap();
///
/// for event in sdl_context.event_pump().poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
pub fn init() -> InitBuilder { InitBuilder::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string()
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<commit_msg>Start implementing Subsystem types<commit_after>use std::ffi::{CStr, CString};
use std::rc::Rc;

use sys::sdl as ll;
use event::EventPump;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

pub type SdlResult<T> = Result<T, String>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// Only one instance of `Sdl` is allowed per process, and cannot be moved or
/// used across non-main threads.
///
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    pub fn new() -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(format!("Cannot have more than one `Sdl` in use at the same time"))
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> SdlResult<AudioSubsystem> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> SdlResult<EventSubsystem> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> SdlResult<JoystickSubsystem> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> SdlResult<HapticSubsystem> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> SdlResult<GameControllerSubsystem> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> SdlResult<TimerSubsystem> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> SdlResult<VideoSubsystem> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> SdlResult<EventPump> {
        EventPump::new(self)
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> SdlResult<$name> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_VIDEO, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> SdlResult<Sdl> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string()
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<|endoftext|>