<commit_before>use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Display;
use std::clone::Clone;

#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain less characters than %1.".to_string(),
                args: vec![min.to_string()],
            })
        }
    })
}

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
pub fn range<T: 'static + PartialOrd + Display + Clone>(a: T,
                                                        b: T)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        if *s >= a && *s <= b {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must be in the range %1..%2.".to_string(),
                args: vec![a.to_string(), b.to_string()],
            })
        }
    })
}

#[cfg(feature = "inclusive_range")]
pub fn range<T: 'static + PartialOrd + Display + Clone>(range: RangeInclusive<T>)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                if *s >= *start && *s <= *end {
                    Ok(())
                } else {
                    Err(::Invalid {
                        msg: "Must be in the range %1..%2.".to_string(),
                        args: vec![start.to_string(), end.to_string()],
                    })
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

/// Enforce that a string must contain `needle`.
pub fn contains(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that a string contains only characters in `accepted`
pub fn contain_only(accepted: &'static [char]) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        for c in s.chars() {
			if !accepted.contains(&c) {
				return Err(::Invalid {
					msg: "Must not contain %1.".to_string(),
					args: vec![c.to_string()],
				});
			}
		}
		Ok(())
    })
}

/// Enforce that a string must not contain `needle`.
pub fn not_contain(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if !s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that a string must not contain any of `needles`.
pub fn not_contain_any(needles: &'static [&'static str]) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        for needle in needles {
			if s.contains(needle) {
				return Err(::Invalid {
					msg: "Must not contain %1.".to_string(),
					args: vec![needle.to_string()],
				});
			}
		}
		Ok(())
    })
}

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
            })
        }
    })
}

#[cfg(test)]
mod tests {
    use validators::{length, range};

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_length() {
        assert!(length(3...5)(&"12".to_string()).is_err());
        assert!(length(3...5)(&"123".to_string()).is_ok());
        assert!(length(3...5)(&"1234".to_string()).is_ok());
        assert!(length(3...5)(&"12345".to_string()).is_ok());
        assert!(length(3...5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_length() {
        assert!(length(3, 5)(&"12".to_string()).is_err());
        assert!(length(3, 5)(&"123".to_string()).is_ok());
        assert!(length(3, 5)(&"1234".to_string()).is_ok());
        assert!(length(3, 5)(&"12345".to_string()).is_ok());
        assert!(length(3, 5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_range() {
        assert!(range(12...127)(&11).is_err());
        assert!(range(12...127)(&12).is_ok());
        assert!(range(12...127)(&50).is_ok());
        assert!(range(12...127)(&127).is_ok());
        assert!(range(12...127)(&128).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_range() {
        assert!(range(12, 127)(&11).is_err());
        assert!(range(12, 127)(&12).is_ok());
        assert!(range(12, 127)(&50).is_ok());
        assert!(range(12, 127)(&127).is_ok());
        assert!(range(12, 127)(&128).is_err());
    }
}
<commit_msg>Added alphanumeric & alphanumeric_dashes validators<commit_after>use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Display;
use std::clone::Clone;

#[cfg(feature = "inclusive_range")]
use std::ops::RangeInclusive;

/// Enforce that a `String` is minimum `min` characters long.
pub fn min(min: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() >= min {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain less characters than %1.".to_string(),
                args: vec![min.to_string()],
            })
        }
    })
}

/// Enforce that a `String` is maximum `max` characters long.
pub fn max(max: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.len() <= max {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain more characters than %1.".to_string(),
                args: vec![max.to_string()],
            })
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(mi: usize, ma: usize) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match (min(mi)(s), max(ma)(s)) {
            (Err(_), Err(_)) => {
                Err(::Invalid {
                    msg: "Must not be less characters than %1 and not more than %2.".to_string(),
                    args: vec![mi.to_string(), ma.to_string()],
                })
            }
            (Err(e), _) => Err(e),
            (_, Err(e)) => Err(e),
            (_, _) => Ok(()),
        }
    })
}

#[cfg(feature = "inclusive_range")]
/// Enforce that a string is minimum `mi` and maximum `ma` characters long.
pub fn length(range: RangeInclusive<usize>) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                match (min(*start)(s), max(*end)(s)) {
                    (Err(_), Err(_)) => {
                        Err(::Invalid {
                            msg: "Must not be less characters than %1 and not more than %2."
                                .to_string(),
                            args: vec![start.to_string(), end.to_string()],
                        })
                    }
                    (Err(e), _) => Err(e),
                    (_, Err(e)) => Err(e),
                    (_, _) => Ok(()),
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

#[cfg(not(feature = "inclusive_range"))]
pub fn range<T: 'static + PartialOrd + Display + Clone>(a: T,
                                                        b: T)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        if *s >= a && *s <= b {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must be in the range %1..%2.".to_string(),
                args: vec![a.to_string(), b.to_string()],
            })
        }
    })
}

#[cfg(feature = "inclusive_range")]
pub fn range<T: 'static + PartialOrd + Display + Clone>(range: RangeInclusive<T>)
                                                        -> Box<Fn(&T) -> ::ValidatorResult> {
    Box::new(move |s: &T| {
        match range {
            RangeInclusive::NonEmpty { ref start, ref end } => {
                if *s >= *start && *s <= *end {
                    Ok(())
                } else {
                    Err(::Invalid {
                        msg: "Must be in the range %1..%2.".to_string(),
                        args: vec![start.to_string(), end.to_string()],
                    })
                }
            }
            _ => panic!("range must be a RangeInclusive::NonEmpty"),
        }
    })
}

/// Enforce that a string must contain `needle`.
pub fn contains(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that a string contains only characters in `accepted`
pub fn contain_only(accepted: &'static [char]) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        for c in s.chars() {
			if !accepted.contains(&c) {
				return Err(::Invalid {
					msg: "Must not contain %1.".to_string(),
					args: vec![c.to_string()],
				});
			}
		}
		Ok(())
    })
}

/// Convenience function; 0-9, A-z
pub fn alphanumeric() -> Box<Fn(&String) -> ::ValidatorResult> {
	contain_only(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'])
}

/// Convenience function; Alphanumeric & underscore.
pub fn alphanumeric_dashes() -> Box<Fn(&String) -> ::ValidatorResult> {
	contain_only(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '-'])
}

/// Enforce that a string must not contain `needle`.
pub fn not_contain(needle: &'static str) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        if !s.contains(needle) {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Must not contain %1.".to_string(),
                args: vec![needle.to_string()],
            })
        }
    })
}

/// Enforce that a string must not contain any of `needles`.
pub fn not_contain_any(needles: &'static [&'static str]) -> Box<Fn(&String) -> ::ValidatorResult> {
    Box::new(move |s: &String| {
        for needle in needles {
			if s.contains(needle) {
				return Err(::Invalid {
					msg: "Must not contain %1.".to_string(),
					args: vec![needle.to_string()],
				});
			}
		}
		Ok(())
    })
}

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
            })
        }
    })
}

#[cfg(test)]
mod tests {
    use validators::{length, range};

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_length() {
        assert!(length(3...5)(&"12".to_string()).is_err());
        assert!(length(3...5)(&"123".to_string()).is_ok());
        assert!(length(3...5)(&"1234".to_string()).is_ok());
        assert!(length(3...5)(&"12345".to_string()).is_ok());
        assert!(length(3...5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_length() {
        assert!(length(3, 5)(&"12".to_string()).is_err());
        assert!(length(3, 5)(&"123".to_string()).is_ok());
        assert!(length(3, 5)(&"1234".to_string()).is_ok());
        assert!(length(3, 5)(&"12345".to_string()).is_ok());
        assert!(length(3, 5)(&"123456".to_string()).is_err());
    }

    #[test]
    #[cfg(feature = "inclusive_range")]
    fn test_range() {
        assert!(range(12...127)(&11).is_err());
        assert!(range(12...127)(&12).is_ok());
        assert!(range(12...127)(&50).is_ok());
        assert!(range(12...127)(&127).is_ok());
        assert!(range(12...127)(&128).is_err());
    }

    #[test]
    #[cfg(not(feature = "inclusive_range"))]
    fn test_range() {
        assert!(range(12, 127)(&11).is_err());
        assert!(range(12, 127)(&12).is_ok());
        assert!(range(12, 127)(&50).is_ok());
        assert!(range(12, 127)(&127).is_ok());
        assert!(range(12, 127)(&128).is_err());
    }
}
<|endoftext|>


<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 mod segment;

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(Copy,Clone,Eq,PartialEq,Hash)]
pub enum Entrypoint {
    None,
    /// The entrypoint was from an `LC_MAIN` load command (added in 10.8) and specifies an offset in
    /// the `__TEXT` segment.
    Offset(u64),
    /// The entrypoint was from an `LC_UNIXTHREAD`/`LC_THREAD` load command and specifies a virtual
    /// memory address.
    VirtualAddress(u64)
}

#[cfg(feature = "std")]
impl fmt::Debug for Entrypoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Entrypoint::None => write!(f, "Entrypoint::None"),
            Entrypoint::Offset(pos) => write!(f, "Entrypoint::Offset(0x{:x})", pos),
            Entrypoint::VirtualAddress(pos) => write!(f, "Entrypoint::VirtualAddress(0x{:x})", pos),
        }
    }
}

/// 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: segment::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
    pub entry: Entrypoint,
    /// 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,
    data: &'a [u8],
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MachO<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MachO")
            .field("header",        &self.header)
            .field("load_commands", &self.load_commands)
            .field("segments",      &self.segments)
            .field("entry",         &self.entry)
            .field("libs",          &self.libs)
            .field("name",          &self.name)
            .field("little_endian", &self.little_endian)
            .field("is_64",         &self.is_64)
            .field("symbols",       &self.symbols().collect::<Vec<_>>())
            .field("exports",       &self.exports().unwrap())
            .field("imports",       &self.imports().unwrap())
            .finish()
    }
}

impl<'a> MachO<'a> {
    pub fn is_object_file(&self) -> bool {
        self.header.filetype == header::MH_OBJECT
    }
    pub fn symbols(&self) -> symbols::SymbolIterator<'a> {
        if let &Some(ref symbols) = &self.symbols {
            symbols.into_iter()
        } else {
            symbols::SymbolIterator::default()
        }
    }
    pub fn relocations(&self) -> error::Result<Vec<(usize, segment::RelocationIterator, segment::Section)>> {
        debug!("Iterating relocations");
        let mut relocs = Vec::new();
        for (_i, segment) in (&self.segments).into_iter().enumerate() {
            for (j, section) in segment.into_iter().enumerate() {
                let (section, _data) = section?;
                if section.nreloc > 0 {
                    relocs.push((j, section.iter_relocations(self.data, self.ctx), section));
                }
            }
        }
        Ok(relocs)
    }
    /// 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 = Entrypoint::None;
        let mut name = None;
        let mut segments = segment::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(segment::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(segment::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) => {
                    // dyld uses the first LC_MAIN entrypoint, and if none is present, it uses the
                    // first LC_UNIXTHREAD entrypoint
                    // model that behavior
                    match entry {
                        Entrypoint::None => {
                            // remember this LC_UNIXTHREAD
                            entry = Entrypoint::VirtualAddress(command.instruction_pointer(header.cputype)?);
                        }
                        _ => {
                            // we either have an LC_MAIN or a previous LC_UNIXTHREAD
                            // in either case, do nothing
                        }
                    }
                },
                load_command::CommandVariant::Main(command) => {
                    match entry {
                        Entrypoint::None | Entrypoint::VirtualAddress(_) => {
                            // we either have no entrypoint or an LC_UNIXTHREAD
                            // in either case, use this LC_MAIN
                            entry = Entrypoint::Offset(command.entryoff);
                        }
                        _ => {
                            // we are not the first LC_MAIN
                            // ignore this load command
                        }
                    }
                },
                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,
            data: bytes,
        })
    }
}

#[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<'a>> {
        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))
            }
        }
    }
}
<commit_msg>Map LC_MAIN entrypoints to virtual memory addresses for consistency<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 mod segment;

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)?)
}

/// 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: segment::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 (as a virtual memory address), 0 if none
    pub entry: u64,
    /// Whether `entry` refers to an older `LC_UNIXTHREAD` instead of the newer `LC_MAIN` entrypoint
    pub old_style_entry: bool,
    /// 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,
    data: &'a [u8],
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MachO<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MachO")
            .field("header",          &self.header)
            .field("load_commands",   &self.load_commands)
            .field("segments",        &self.segments)
            .field("entry",           &self.entry)
            .field("old_style_entry", &self.old_style_entry)
            .field("libs",            &self.libs)
            .field("name",            &self.name)
            .field("little_endian",   &self.little_endian)
            .field("is_64",           &self.is_64)
            .field("symbols",         &self.symbols().collect::<Vec<_>>())
            .field("exports",         &self.exports().unwrap())
            .field("imports",         &self.imports().unwrap())
            .finish()
    }
}

impl<'a> MachO<'a> {
    pub fn is_object_file(&self) -> bool {
        self.header.filetype == header::MH_OBJECT
    }
    pub fn symbols(&self) -> symbols::SymbolIterator<'a> {
        if let &Some(ref symbols) = &self.symbols {
            symbols.into_iter()
        } else {
            symbols::SymbolIterator::default()
        }
    }
    pub fn relocations(&self) -> error::Result<Vec<(usize, segment::RelocationIterator, segment::Section)>> {
        debug!("Iterating relocations");
        let mut relocs = Vec::new();
        for (_i, segment) in (&self.segments).into_iter().enumerate() {
            for (j, section) in segment.into_iter().enumerate() {
                let (section, _data) = section?;
                if section.nreloc > 0 {
                    relocs.push((j, section.iter_relocations(self.data, self.ctx), section));
                }
            }
        }
        Ok(relocs)
    }
    /// 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 unixthread_entry_address = None;
        let mut main_entry_offset = None;
        let mut name = None;
        let mut segments = segment::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(segment::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(segment::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) => {
                    // dyld cares only about the first LC_UNIXTHREAD
                    if unixthread_entry_address.is_none() {
                        unixthread_entry_address = Some(command.instruction_pointer(header.cputype)?);
                    }
                },
                load_command::CommandVariant::Main(command) => {
                    // dyld cares only about the first LC_MAIN
                    if main_entry_offset.is_none() {
                        main_entry_offset = Some(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)
        }

        // dyld prefers LC_MAIN over LC_UNIXTHREAD
        // choose the same way here
        let (entry, old_style_entry) = if let Some(offset) = main_entry_offset {
            // map the entrypoint offset to a virtual memory address
            let base_address = segments.iter()
                .filter(|s| &s.segname[0..7] == b"__TEXT\0")
                .map(|s| s.vmaddr - s.fileoff)
                .next()
                .ok_or_else(||
                    error::Error::Malformed(format!("image specifies LC_MAIN offset {} but has no __TEXT segment", offset))
                )?;

            (base_address + offset, false)
        } else if let Some(address) = unixthread_entry_address {
            (address, true)
        } else {
            (0, false)
        };

        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            old_style_entry: old_style_entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
            data: bytes,
        })
    }
}

#[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<'a>> {
        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><commit_msg>admin::render_readmes: Return `Result` from `find_file_by_path()`<commit_after><|endoftext|>


<commit_before>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath;
use cgmath::{Deg, Point2};
use character::{CharacterDrawable, controls::CharacterInputState};
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{camera::CameraInputState, Dimensions, direction, direction_movement, get_orientation, load_texture, orientation::{Orientation, Stance}, overlaps};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = Dimensions::get_view_matrix();
    ZombieDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, character: &CharacterDrawable, bullets: &[BulletDrawable]) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);

    if self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
      let dir = direction(
        Point2::new(self.position.position[0], self.position.position[1]),
        Point2::new(character.position.position[0], character.position.position[1])
      );

      self.direction = get_orientation(dir);
    }

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x),
      self.position.position[1] + offset_delta.position[1] - (self.movement_direction.y)
    ]);
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 80.0, 80.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-25.0, -35.0], [0.0, 1.0]),
        VertexData::new([25.0, -35.0], [1.0, 1.0]),
        VertexData::new([25.0, 35.0], [1.0, 0.0]),
        VertexData::new([-25.0, 35.0], [0.0, 0.0]),
      ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, Bullets>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (mut zombies, camera_input, character_input, character, bullets, dim): Self::SystemData) {
    use specs::Join;

    for (zs, camera, ci, c, bs) in (&mut zombies, &camera_input, &character_input, &character, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, c, &bs.bullets);
      }
    }
  }
}
<commit_msg>Zombies walk towards player<commit_after>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath;
use cgmath::{Deg, Point2};
use character::{CharacterDrawable, controls::CharacterInputState};
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{camera::CameraInputState, Dimensions, direction, direction_movement, get_orientation, load_texture, orientation::{Orientation, Stance}, overlaps};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = Dimensions::get_view_matrix();
    ZombieDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, character: &CharacterDrawable, bullets: &[BulletDrawable]) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);
    let movement_speed = 0.2;

    if self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
      let dir = direction(
        Point2::new(self.position.position[0], self.position.position[1]),
        Point2::new(character.position.position[0], character.position.position[1])
      );

      self.direction = get_orientation(dir);

      self.movement_direction = direction_movement(dir);
      self.stance = Stance::Walking;
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x * movement_speed),
      self.position.position[1] + offset_delta.position[1] + (self.movement_direction.y * movement_speed)
    ]);
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 80.0, 80.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-25.0, -35.0], [0.0, 1.0]),
        VertexData::new([25.0, -35.0], [1.0, 1.0]),
        VertexData::new([25.0, 35.0], [1.0, 0.0]),
        VertexData::new([-25.0, 35.0], [0.0, 0.0]),
      ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, Bullets>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (mut zombies, camera_input, character_input, character, bullets, dim): Self::SystemData) {
    use specs::Join;

    for (zs, camera, ci, c, bs) in (&mut zombies, &camera_input, &character_input, &character, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, c, &bs.bullets);
      }
    }
  }
}
<|endoftext|>


<commit_before>//! This module defines the `Bits`, `Dibits`, and `Tribits` iterators as well as the
//! wrapper types `Bit`, `Dibit`, and `Tribit`, for working with sub-byte values.
//!
//! The wrapped values of `Bit`, `Dibit`, and `Tribit, are guaranteed to have only one,
//! two, or three bits, respectively.

use std;

/// Iterate over the dibits of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;
/// Iterates over the tribits in a byte source, MSB to LSB.
pub type Tribits<T> = SubByteIter<TribitParams, T>;

/// Defines parameters needed for (power of two) sub-byte iterators.
pub trait IterParams {
    /// Type to yield at each iteration.
    type Output;

    /// Number of bits to consume at each iteration.
    fn bits() -> usize;

    /// Number of bytes to buffer, where the number of bits contained should be the lcm of
    /// 8 and the number of bits per iteration.
    fn buffer() -> usize { 1 }

    /// Amount to shift buffer after loading in bytes.
    fn buffer_shift() -> usize { 32 - 8 * Self::buffer() }

    /// Number of iterations needed for each byte.
    fn iterations() -> usize { 8 * Self::buffer() / Self::bits() }

    /// Wrap the given bits in container type.
    fn wrap(bits: u8) -> Self::IterType;

    /// Verify the parameters are supported.
    fn validate() {
        // Maximum buffer size is currently 32 bits.
        assert!(Self::buffer() <= 4);
    }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits >> 2 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type Output = Dibit;

    fn bits() -> usize { 2 }
    fn wrap(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// Three bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Tribit(u8);

impl Tribit {
    /// Construct a new `Tribit` with the three given bits in the LSB position.
    pub fn new(bits: u8) -> Tribit {
        assert!(bits >> 3 == 0);
        Tribit(bits)
    }

    /// Get the wrapped tribit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Tribits` iterator.
pub struct TribitParams;

impl IterParams for TribitParams {
    type Output = Tribit;

    fn bits() -> usize { 3 }
    fn buffer() -> usize { 3 }
    fn wrap(bits: u8) -> Tribit { Tribit::new(bits) }
}

/// An iterator for sub-byte (bit-level) values.
struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current buffered bits.
    buf: u32,
    /// Current bit-level index into the current byte.
    idx: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter` over the given byte source. All bits are iterated
    /// over, so the number of bits must be a byte multiple.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            buf: 0,
            idx: 0,
        }
    }

    /// Consume one or more bytes to create a buffer of bits, filled starting from the
    /// MSB.
    fn buffer(&mut self) -> Option<u32> {
        let (buf, added) = (&mut self.src)
            .take(P::buffer())
            .fold((0, 0), |(buf, added), byte| {
                (buf << 8 | byte as u32, added + 1)
            });

        // It's okay if there are no more source bits here, because we're on a safe
        // boundary.
        if added == 0 {
            return None;
        }

        assert!(added == P::buffer(), "incomplete source");

        Some(buf << P::buffer_shift())
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    type Item = P::Output;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.buf = match self.buffer() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.buf >> (32 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.buf <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations() as u8;

        Some(P::wrap(bits as u8))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn validate_params() {
        DibitParams::validate();
        TribitParams::validate();
    }

    #[test]
    fn test_tribits() {
        let bytes = [
            0b00101001,
            0b11001011,
            0b10111000,
            0b00101001,
            0b11001011,
            0b10111000,
        ];
        let mut t = Tribits::new(bytes.iter().cloned());

        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribits_panic() {
        let bytes = [1, 2, 3, 4];
        let t = Tribits::new(bytes.iter().cloned());

        for _ in t {}
    }
}
<commit_msg>Add Hexbit and Hexbits, DibitBytes, TribitBytes, and HexbitBytes iterators<commit_after>//! This module defines wrapper types and iterators for working with sub-byte values, as
//! well as iterators to group those values back into bytes.

use std;

/// Iterate over the 2-bit symbols of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;
/// Iterates over the 3-bit symbols of a byte source, MSB to LSB.
pub type Tribits<T> = SubByteIter<TribitParams, T>;
/// Iterates over the 6-bit symbols of a byte source, MSB to LSB. The source must be a
/// multiple of 3 bytes.
pub type Hexbits<T> = SubByteIter<HexbitParams, T>;

/// Groups dibits into full bytes. The source must be a multiple of 4 dibits.
pub type DibitBytes<T> = SubByteIter<DibitByteParams, T>;
/// Groups tribits into full bytes. The source must be a multiple of 8 tribits.
pub type TribitBytes<T> = SubByteIter<TribitByteParams, T>;
/// Groups hexbits into full bytes. The source must be a multiple of 6 hexbits.
pub type HexbitBytes<T> = SubByteIter<HexbitByteParams, T>;

pub trait IterParams {
    /// Type to consume when buffering.
    type Input;
    /// Type to yield at each iteration.
    type Output;

    /// Number of bits to consume at each iteration.
    fn bits() -> usize;

    /// Number of input symbols to consume when buffering.
    fn buffer() -> usize;

    /// Amount to shift buffer after loading an input symbol.
    fn shift() -> usize;

    /// Amount to shift buffer after all buffering.
    fn post_shift() -> usize { 32 - Self::shift() * Self::buffer() }

    /// Number of iterations before buffering.
    fn iterations() -> usize { Self::shift() * Self::buffer() / Self::bits() }

    /// Convert input symbol to a byte.
    fn to_byte(input: Self::Input) -> u8;

    /// Convert bits to output type.
    fn to_output(bits: u8) -> Self::Output;

    /// Verify the parameters are supported.
    fn validate() {
        // Maximum buffer size is currently 32 bits.
        assert!(Self::buffer() * Self::shift() <= 32);
    }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits >> 2 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit, which is guaranteed to have only 2 LSBs.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type Input = u8;
    type Output = Dibit;

    fn bits() -> usize { 2 }
    fn buffer() -> usize { 1 }
    fn shift() -> usize { 8 }

    fn to_byte(input: Self::Input) -> u8 { input }
    fn to_output(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// Three bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Tribit(u8);

impl Tribit {
    /// Construct a new `Tribit` with the three given bits in the LSB position.
    pub fn new(bits: u8) -> Tribit {
        assert!(bits >> 3 == 0);
        Tribit(bits)
    }

    /// Get the wrapped tribit, which is guaranteed to have only 3 LSBs.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Tribits` iterator.
pub struct TribitParams;

impl IterParams for TribitParams {
    type Input = u8;
    type Output = Tribit;

    fn bits() -> usize { 3 }
    fn buffer() -> usize { 3 }
    fn shift() -> usize { 8 }

    fn to_byte(input: Self::Input) -> u8 { input }
    fn to_output(bits: u8) -> Tribit { Tribit::new(bits) }
}

/// Six bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Hexbit(u8);

impl Hexbit {
    /// Construct a new `Hexbit` with the 6 given bits in the LSB position.
    pub fn new(bits: u8) -> Hexbit {
        assert!(bits >> 6 == 0);
        Hexbit(bits)
    }

    /// Get the wrapped hexbit, which is guaranteed to have only 6 LSBs.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Hexbits` iterator.
pub struct HexbitParams;

impl IterParams for HexbitParams {
    type Input = u8;
    type Output = Hexbit;

    fn bits() -> usize { 6 }
    fn buffer() -> usize { 3 }
    fn shift() -> usize { 8 }

    fn to_byte(input: Self::Input) -> u8 { input }
    fn to_output(bits: u8) -> Hexbit { Hexbit::new(bits) }
}

/// Parameters for `DibitBytes` iterator.
pub struct DibitByteParams;

impl IterParams for DibitByteParams {
    type Input = Dibit;
    type Output = u8;

    fn bits() -> usize { 8 }
    fn buffer() -> usize { 4 }
    fn shift() -> usize { 2 }

    fn to_byte(input: Self::Input) -> u8 { input.bits() }
    fn to_output(bits: u8) -> Self::Output { bits }
}

/// Parameters for `TribitBytes` iterator.
pub struct TribitByteParams;

impl IterParams for TribitByteParams {
    type Input = Tribit;
    type Output = u8;

    fn bits() -> usize { 8 }
    fn buffer() -> usize { 8 }
    fn shift() -> usize { 3 }

    fn to_byte(input: Self::Input) -> u8 { input.bits() }
    fn to_output(bits: u8) -> Self::Output { bits }
}

/// Parameters for `HexbitBytes` iterator.
pub struct HexbitByteParams;

impl IterParams for HexbitByteParams {
    type Input = Hexbit;
    type Output = u8;

    fn bits() -> usize { 8 }
    fn buffer() -> usize { 4 }
    fn shift() -> usize { 6 }

    fn to_byte(input: Self::Input) -> u8 { input.bits() }
    fn to_output(bits: u8) -> Self::Output { bits }
}

/// An iterator for sub-byte (bit-level) values.
struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = P::Input>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current buffered bits.
    buf: u32,
    /// Current bit-level index into the current byte.
    idx: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = P::Input>
{
    /// Construct a new `SubByteIter` over the given symbol source.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            buf: 0,
            idx: 0,
        }
    }

    /// Consume one or more symbols to create a buffer of bits, filled starting from the
    /// MSB.
    fn buffer(&mut self) -> Option<u32> {
        let (buf, added) = (&mut self.src)
            .take(P::buffer())
            .fold((0, 0), |(buf, added), next| {
                (buf << P::shift() | P::to_byte(next) as u32, added + 1)
            });

        // It's okay if there are no more source symbols here, because we're on a safe
        // boundary.
        if added == 0 {
            return None;
        }

        assert!(added == P::buffer(), "incomplete source");

        Some(buf << P::post_shift())
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = P::Input>
{
    type Item = P::Output;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.buf = match self.buffer() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.buf >> (32 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.buf <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations() as u8;

        Some(P::to_output(bits as u8))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn validate_params() {
        DibitParams::validate();
        TribitParams::validate();
        HexbitParams::validate();
        DibitByteParams::validate();
        TribitByteParams::validate();
        HexbitByteParams::validate();
    }

    #[test]
    fn test_dibits() {
        let bytes = [
            0b00110011,
            0b10011001,
            0b11111111,
        ];

        let mut d = Dibits::new(bytes.iter().cloned());

        assert_eq!(d.next().unwrap().bits(), 0b00);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert_eq!(d.next().unwrap().bits(), 0b00);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert_eq!(d.next().unwrap().bits(), 0b10);
        assert_eq!(d.next().unwrap().bits(), 0b01);
        assert_eq!(d.next().unwrap().bits(), 0b10);
        assert_eq!(d.next().unwrap().bits(), 0b01);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert_eq!(d.next().unwrap().bits(), 0b11);
        assert!(d.next().is_none());
    }

    #[test]
    fn test_dibit_bytes() {
        let dibits = [
            Dibit::new(0b00),
            Dibit::new(0b11),
            Dibit::new(0b00),
            Dibit::new(0b11),
            Dibit::new(0b10),
            Dibit::new(0b01),
            Dibit::new(0b10),
            Dibit::new(0b01),
            Dibit::new(0b11),
            Dibit::new(0b11),
            Dibit::new(0b11),
            Dibit::new(0b11),
        ];

        let mut d = DibitBytes::new(dibits.iter().cloned());

        assert_eq!(d.next().unwrap(), 0b00110011);
        assert_eq!(d.next().unwrap(), 0b10011001);
        assert_eq!(d.next().unwrap(), 0b11111111);
        assert!(d.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_dibit_bytes_panic() {
        let dibits = [
            Dibit::new(0b00),
            Dibit::new(0b11),
            Dibit::new(0b00),
            Dibit::new(0b11),
            Dibit::new(0b10),
        ];

        let mut d = DibitBytes::new(dibits.iter().cloned());

        d.next();
        d.next();
    }

    #[test]
    fn test_tribits() {
        let bytes = [
            0b00101001,
            0b11001011,
            0b10111000,
            0b00101001,
            0b11001011,
            0b10111000,
        ];
        let mut t = Tribits::new(bytes.iter().cloned());

        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribits_panic() {
        let bytes = [1, 2, 3, 4];
        let t = Tribits::new(bytes.iter().cloned());

        for _ in t {}
    }

    #[test]
    fn test_tribit_bytes() {
        let tribits = [
            Tribit::new(0b001),
            Tribit::new(0b010),
            Tribit::new(0b011),
            Tribit::new(0b100),
            Tribit::new(0b101),
            Tribit::new(0b110),
            Tribit::new(0b111),
            Tribit::new(0b000),
            Tribit::new(0b001),
            Tribit::new(0b010),
            Tribit::new(0b011),
            Tribit::new(0b100),
            Tribit::new(0b101),
            Tribit::new(0b110),
            Tribit::new(0b111),
            Tribit::new(0b000),
        ];

        let mut t = TribitBytes::new(tribits.iter().cloned());

        assert_eq!(t.next().unwrap(), 0b00101001);
        assert_eq!(t.next().unwrap(), 0b11001011);
        assert_eq!(t.next().unwrap(), 0b10111000);
        assert_eq!(t.next().unwrap(), 0b00101001);
        assert_eq!(t.next().unwrap(), 0b11001011);
        assert_eq!(t.next().unwrap(), 0b10111000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribit_bytes_panic() {
        let tribits = [
            Tribit::new(0b001),
            Tribit::new(0b010),
            Tribit::new(0b011),
            Tribit::new(0b100),
        ];

        let mut t = TribitBytes::new(tribits.iter().cloned());

        t.next();
        t.next();
    }

    #[test]
    fn test_hexbits() {
        let bytes = [
            0b11111100,
            0b00001010,
            0b10010101,
            0b11111100,
            0b00001010,
            0b10010101,
        ];

        let mut h = Hexbits::new(bytes.iter().cloned());

        assert_eq!(h.next().unwrap().bits(), 0b111111);
        assert_eq!(h.next().unwrap().bits(), 0b000000);
        assert_eq!(h.next().unwrap().bits(), 0b101010);
        assert_eq!(h.next().unwrap().bits(), 0b010101);
        assert_eq!(h.next().unwrap().bits(), 0b111111);
        assert_eq!(h.next().unwrap().bits(), 0b000000);
        assert_eq!(h.next().unwrap().bits(), 0b101010);
        assert_eq!(h.next().unwrap().bits(), 0b010101);
        assert!(h.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_hexbits_panic() {
        let bytes = [
            0b11111100,
            0b00001010,
        ];

        let mut h = Hexbits::new(bytes.iter().cloned());

        assert_eq!(h.next().unwrap().bits(), 0b111111);
        assert_eq!(h.next().unwrap().bits(), 0b000000);
        h.next();
    }

    #[test]
    fn test_hexbit_bytes() {
        let hexbits = [
            Hexbit::new(0b111111),
            Hexbit::new(0b000000),
            Hexbit::new(0b101010),
            Hexbit::new(0b010101),
            Hexbit::new(0b111111),
            Hexbit::new(0b000000),
            Hexbit::new(0b101010),
            Hexbit::new(0b010101),
        ];

        let mut h = HexbitBytes::new(hexbits.iter().cloned());

        assert_eq!(h.next().unwrap(), 0b11111100);
        assert_eq!(h.next().unwrap(), 0b00001010);
        assert_eq!(h.next().unwrap(), 0b10010101);
        assert_eq!(h.next().unwrap(), 0b11111100);
        assert_eq!(h.next().unwrap(), 0b00001010);
        assert_eq!(h.next().unwrap(), 0b10010101);
        assert!(h.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_hexbit_bytes_panic() {
        let hexbits = [
            Hexbit::new(0b111111),
            Hexbit::new(0b000000),
            Hexbit::new(0b101010),
            Hexbit::new(0b010101),
            Hexbit::new(0b111111),
        ];

        let mut h = HexbitBytes::new(hexbits.iter().cloned());
        h.next();
        h.next();
        h.next();
        h.next();
        h.next();
        h.next();
    }
}
<|endoftext|>


<commit_before>use uuid::Uuid;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};

/// With the uuid we get the storeid and then we can delete the entry
pub fn delete(uuid: Uuid, store : &Store) -> Result<(),TodoError> {
	// With the uuid we get the storeid
	let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();
	// It deletes an entry
	match store.delete(store_id) {
		Ok(val) => Ok(val),
		Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
	}
}

<commit_msg>code cleanup<commit_after>use uuid::Uuid;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};

/// With the uuid we get the storeid and then we can delete the entry
pub fn delete(store : &Store, uuid: Uuid) -> Result<(),TodoError> {
	// With the uuid we get the storeid
	let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();
	// It deletes an entry
	match store.delete(store_id) {
		Ok(val) => Ok(val),
		Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
	}
}

<|endoftext|>