<commit_before>use super::*;

#[test]
fn test_splitpoint() {
    for idx in 0..=CAPACITY {
        let (middle_kv_idx, insertion) = splitpoint(idx);

        // Simulate performing the split:
        let mut left_len = middle_kv_idx;
        let mut right_len = CAPACITY - middle_kv_idx - 1;
        match insertion {
            InsertionPlace::Left(edge_idx) => {
                assert!(edge_idx <= left_len);
                left_len += 1;
            }
            InsertionPlace::Right(edge_idx) => {
                assert!(edge_idx <= right_len);
                right_len += 1;
            }
        }
        assert!(left_len >= MIN_LEN);
        assert!(right_len >= MIN_LEN);
        assert!(left_len + right_len == CAPACITY);
    }
}
<commit_msg>BTreeMap: keep an eye out on the size of the main components<commit_after>use super::*;

#[test]
fn test_splitpoint() {
    for idx in 0..=CAPACITY {
        let (middle_kv_idx, insertion) = splitpoint(idx);

        // Simulate performing the split:
        let mut left_len = middle_kv_idx;
        let mut right_len = CAPACITY - middle_kv_idx - 1;
        match insertion {
            InsertionPlace::Left(edge_idx) => {
                assert!(edge_idx <= left_len);
                left_len += 1;
            }
            InsertionPlace::Right(edge_idx) => {
                assert!(edge_idx <= right_len);
                right_len += 1;
            }
        }
        assert!(left_len >= MIN_LEN);
        assert!(right_len >= MIN_LEN);
        assert!(left_len + right_len == CAPACITY);
    }
}

#[test]
#[cfg(target_arch = "x86_64")]
fn test_sizes() {
    assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
    assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 8 * 2);
    assert_eq!(core::mem::size_of::<InternalNode<(), ()>>(), 112);
    assert_eq!(core::mem::size_of::<InternalNode<i64, i64>>(), 112 + CAPACITY * 8 * 2);
}
<|endoftext|>


<commit_before>//! Supply the command line.

// Standard library
use std::env;
use std::fmt;
use std::path::{PathBuf};

// Third party
use clap::App;

// First party
use lightning::Site;

const GENERATE: &'static str = "generate";
const CREATE: &'static str = "create";
const SERVE: &'static str = "serve";

/// Commands which can be called, mapped from strings of the same name.
pub enum Command {
    /// Generate the site
    Generate(Site),
    Create,
    Serve,
    Unspecified,
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Command::Generate(_) => write!(f, "{}", GENERATE),
            Command::Create => write!(f, "{}", CREATE),
            Command::Serve => write!(f, "{}", SERVE),
            _ => write!(f, "error!!!"),  // TODO: something else!
        }
    }
}

// TODO: figure out a way, eventually, to customize arguments based on whatever
//       external tools are supplied---without requiring a rebuild. (Compare
//       what Cargo does.)
/// Get arguments from the command line.
pub fn cli() -> Command  {
    let yaml = load_yaml!("cli.yml");
    let matches = App::from_yaml(yaml).get_matches();

    // Since a subcommand is required, if this fails it's clap's fault.
    // `unwrap()` at will, commander!
    match matches.subcommand_name().unwrap() {
        GENERATE => {
            let generate_args = matches.subcommand_matches(GENERATE).unwrap();
            Command::Generate(Site {
                source_directory: match generate_args.value_of("site_directory") {
                    Some(path_str) => PathBuf::from(path_str),
                    None => env::current_dir().unwrap(),
                },
                template_directory: match generate_args.value_of("template_directory") {
                    Some(path_str) => Some(PathBuf::from(path_str)),
                    None => None,
                }
            })
        },
        CREATE => Command::Create,
        SERVE => Command::Serve,
        _ => Command::Unspecified,

    }
}
<commit_msg>Extract building `Command::Generate` into own function.<commit_after>//! Supply the command line.

// Standard library
use std::env;
use std::fmt;
use std::path::{PathBuf};

// Third party
use clap::{App, ArgMatches};

// First party
use lightning::Site;

const GENERATE: &'static str = "generate";
const CREATE: &'static str = "create";
const SERVE: &'static str = "serve";

/// Commands which can be called, mapped from strings of the same name.
pub enum Command {
    /// Generate the site
    Generate(Site),
    Create,
    Serve,
    Unspecified,
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Command::Generate(_) => write!(f, "{}", GENERATE),
            Command::Create => write!(f, "{}", CREATE),
            Command::Serve => write!(f, "{}", SERVE),
            _ => write!(f, "error!!!"),  // TODO: something else!
        }
    }
}

// TODO: figure out a way, eventually, to customize arguments based on whatever
//       external tools are supplied---without requiring a rebuild. (Compare
//       what Cargo does.)
/// Get arguments from the command line.
pub fn cli() -> Command  {
    let yaml = load_yaml!("cli.yml");
    let matches = App::from_yaml(yaml).get_matches();

    // Since a subcommand is required, if this fails it's clap's fault.
    // `unwrap()` at will, commander!
    match matches.subcommand_name().unwrap() {
        GENERATE => generate_from_matches(matches.subcommand_matches(GENERATE).unwrap()),
        CREATE => Command::Create,
        SERVE => Command::Serve,
        _ => Command::Unspecified,
    }
}

fn generate_from_matches<'m>(matches: &'m ArgMatches) -> Command {
    Command::Generate(Site {
        source_directory: match matches.value_of("site_directory") {
            Some(path_str) => PathBuf::from(path_str),
            None => env::current_dir().unwrap(),
        },
        template_directory: match matches.value_of("template_directory") {
            Some(path_str) => Some(PathBuf::from(path_str)),
            None => None,
        }
    })
}
<|endoftext|>


<commit_before>fn get_digits(candidate: u32) -> Vec<u32> {
    fn inner(n: u32, digits: &mut Vec<u32>) {
        if n >= 10 {
            inner(n / 10, digits);
        }
        digits.push(n % 10);
    }
    let mut digits = Vec::new();
    inner(candidate, &mut digits);
    digits
}

fn two_adjacent(digits: &Vec<u32>) -> bool {
    digits.iter().zip(digits[1..].iter()).any(|(a,b)| {
        a == b
    })
}

fn non_decreasing(digits: &Vec<u32>) -> bool {
    digits.iter().zip(digits[1..].iter()).all(|(a,b)| {
        a <= b
    })
}

fn only_two(digits: &Vec<u32>) -> bool {
    let mut curr_digit = digits[0];
    let mut count = 1;
    for digit in digits[1..].iter() {
        if *digit == curr_digit {
            count += 1;
        } else if count == 2 {
            return true;
        } else {
            count = 1;
            curr_digit = *digit;
        }
    }
    return count == 2;
}

fn solve_part1(candidates: &Vec<u32>) -> u32{
    let valid_numbers: Vec<&u32> = candidates.iter().filter(|candidate| {
        let digits = get_digits(**candidate);
        two_adjacent(&digits) && non_decreasing(&digits)
    }).collect();
    valid_numbers.len() as u32
}

fn solve_part2(candidates: &Vec<u32>) -> u32{
    let valid_numbers: Vec<&u32> = candidates.iter().filter(|candidate| {
        let digits = get_digits(**candidate);
        only_two(&digits) && non_decreasing(&digits)
    }).collect();
    valid_numbers.len() as u32
}

fn main() {
    let candidates: Vec<u32> = (134564..585160).collect();
    println!("Part 1: {}", solve_part1(&candidates));
    println!("Part 2: {}", solve_part2(&candidates));
}

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

    #[test]
    fn test_two_adjacent() {
        assert_eq!(two_adjacent(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(two_adjacent(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(two_adjacent(&vec![0, 1, 2, 3, 4, 5]), false);
    }

    #[test]
    fn test_groups_of_two() {
        assert_eq!(only_two(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(only_two(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(only_two(&vec![0, 1, 2, 4, 4, 4]), false);
        assert_eq!(only_two(&vec![0, 1, 4, 4, 4, 4]), false);
        assert_eq!(only_two(&vec![0, 1, 2, 3, 4, 5]), false);
        assert_eq!(only_two(&vec![4, 4, 4, 4, 4, 4]), false);
    }

    #[test]
    fn test_non_decreasing() {
        assert_eq!(non_decreasing(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(non_decreasing(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(non_decreasing(&vec![0, 1, 2, 3, 4, 5]), true);
        assert_eq!(non_decreasing(&vec![6, 6, 6, 6, 6, 6]), true);
        assert_eq!(non_decreasing(&vec![6, 6, 6, 6, 6, 0]), false);
        assert_eq!(non_decreasing(&vec![6, 0, 6, 6, 6, 6]), false);
    }
}
<commit_msg>2019/day04: refactor filter closure/lambda<commit_after>fn get_digits(candidate: u32) -> Vec<u32> {
    fn inner(n: u32, digits: &mut Vec<u32>) {
        if n >= 10 {
            inner(n / 10, digits);
        }
        digits.push(n % 10);
    }
    let mut digits = Vec::new();
    inner(candidate, &mut digits);
    digits
}

fn two_adjacent(digits: &Vec<u32>) -> bool {
    digits.iter().zip(digits[1..].iter()).any(|(a,b)| {
        a == b
    })
}

fn non_decreasing(digits: &Vec<u32>) -> bool {
    digits.iter().zip(digits[1..].iter()).all(|(a,b)| {
        a <= b
    })
}

fn only_two(digits: &Vec<u32>) -> bool {
    let mut curr_digit = digits[0];
    let mut count = 1;
    for digit in digits[1..].iter() {
        if *digit == curr_digit {
            count += 1;
        } else if count == 2 {
            return true;
        } else {
            count = 1;
            curr_digit = *digit;
        }
    }
    return count == 2;
}

fn solve_part1(candidates: &Vec<u32>) -> u32{
    candidates.iter().filter(|candidate: u32| {
        let digits = get_digits(candidate);
        two_adjacent(&digits) && non_decreasing(&digits)
    }).count() as u32
}

fn solve_part2(candidates: &Vec<u32>) -> u32{
    let valid_numbers: Vec<&u32> = candidates.iter().filter(|candidate| {
        let digits = get_digits(**candidate);
        only_two(&digits) && non_decreasing(&digits)
    }).collect();
    valid_numbers.len() as u32
}

fn main() {
    let candidates: Vec<u32> = (134564..585160).collect();
    println!("Part 1: {}", solve_part1(&candidates));
    println!("Part 2: {}", solve_part2(&candidates));
}

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

    #[test]
    fn test_two_adjacent() {
        assert_eq!(two_adjacent(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(two_adjacent(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(two_adjacent(&vec![0, 1, 2, 3, 4, 5]), false);
    }

    #[test]
    fn test_groups_of_two() {
        assert_eq!(only_two(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(only_two(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(only_two(&vec![0, 1, 2, 4, 4, 4]), false);
        assert_eq!(only_two(&vec![0, 1, 4, 4, 4, 4]), false);
        assert_eq!(only_two(&vec![0, 1, 2, 3, 4, 5]), false);
        assert_eq!(only_two(&vec![4, 4, 4, 4, 4, 4]), false);
    }

    #[test]
    fn test_non_decreasing() {
        assert_eq!(non_decreasing(&vec![0, 1, 1, 2, 3, 4]), true);
        assert_eq!(non_decreasing(&vec![0, 1, 2, 3, 4, 4]), true);
        assert_eq!(non_decreasing(&vec![0, 1, 2, 3, 4, 5]), true);
        assert_eq!(non_decreasing(&vec![6, 6, 6, 6, 6, 6]), true);
        assert_eq!(non_decreasing(&vec![6, 6, 6, 6, 6, 0]), false);
        assert_eq!(non_decreasing(&vec![6, 0, 6, 6, 6, 6]), false);
    }
}
<|endoftext|>


<commit_before>/// Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien
/// Copyright (c) 1998 John D. Polstra.
/// Copyright (c) 2016 Nemanja Boric
/// All rights reserved
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
/// 1. Redistributions of source code must retain the above copyright
///    notice, this list of conditions and the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright
///    notice, this list of conditions and the following disclaimer in the
///    documentation and/or other materials provided with the distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
/// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
/// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
/// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
/// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
/// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
/// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
/// SUCH DAMAGE.
///
///	Source:
/// $FreeBSD: head/sys/sys/elf_common.h 294844 2016-01-26 18:20:25Z emaste $
///

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}

/// Elf32 relocation structure that doesn't need an addend
#[repr(C)]
pub struct Elf32_Rel {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
}

/// Elf32 relocation structure that needs an addend
#[repr(C)]
pub struct Elf32_Rela {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
    r_addent: Elf32_Sword
}

/// Magic number; byte 0
const EI_MAG0: usize = 0;
/// Magic number; byte 1
const EI_MAG1: usize = 1;
/// Magic number; byte 2
const EI_MAG2: usize = 2;
/// Magic number; byte 3
const EI_MAG3: usize = 3;
/// Class of machine
const EI_CLASS: usize = 4;
/// Data format
const EI_DATA: usize = 5;
/// ELF format version
const EI_VERSION: usize = 6;
/// Operating system / ABI ident
const EI_OSABI: usize = 7;
/// ABI version
const EI_ABIVERSION: usize = 8;
/// Start of architecture definition
const OLD_EI_BRAND: usize = 8;
/// Start of padding (per SV4 ABI)
const EI_PAD: usize = 9;
/// Size of e_ident array
const EI_NIDENT: usize = 16;

/// Values for the magic number bytes
const ELFMAG0: u8 = 0x7f;
const ELFMAG1: u8 = 'E' as u8;
const ELFMAG2: u8 = 'L' as u8;
const ELFMAG3: u8 = 'F' as u8;
const ELFMAG: &'static str = "\u{177}ELF";
const SELFMAG: usize = 4;
<commit_msg>Add EiType, EiMachine, EiAbi, EiData consts<commit_after>/// Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien
/// Copyright (c) 1998 John D. Polstra.
/// Copyright (c) 2016 Nemanja Boric
/// All rights reserved
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
/// 1. Redistributions of source code must retain the above copyright
///    notice, this list of conditions and the following disclaimer.
/// 2. Redistributions in binary form must reproduce the above copyright
///    notice, this list of conditions and the following disclaimer in the
///    documentation and/or other materials provided with the distribution.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
/// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
/// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
/// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
/// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
/// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
/// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
/// SUCH DAMAGE.
///
///	Source:
/// $FreeBSD: head/sys/sys/elf_common.h 294844 2016-01-26 18:20:25Z emaste $
///

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}

/// Elf32 symbol table
#[repr(C)]
pub struct Elf32_Sym {
    st_name: Elf32_Word,
    st_value: Elf32_Addr,
    st_size: Elf32_Word,
    st_info: u8,
    st_other: u8,
    st_shndx: Elf32_Half,
}

/// Elf32 relocation structure that doesn't need an addend
#[repr(C)]
pub struct Elf32_Rel {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
}

/// Elf32 relocation structure that needs an addend
#[repr(C)]
pub struct Elf32_Rela {
    r_offset: Elf32_Addr,
    r_info: Elf32_Word,
    r_addent: Elf32_Sword
}

/// Magic number; byte 0
const EI_MAG0: usize = 0;
/// Magic number; byte 1
const EI_MAG1: usize = 1;
/// Magic number; byte 2
const EI_MAG2: usize = 2;
/// Magic number; byte 3
const EI_MAG3: usize = 3;
/// Class of machine
const EI_CLASS: usize = 4;
/// Data format
const EI_DATA: usize = 5;
/// ELF format version
const EI_VERSION: usize = 6;
/// Operating system / ABI ident
const EI_OSABI: usize = 7;
/// ABI version
const EI_ABIVERSION: usize = 8;
/// Start of architecture definition
const OLD_EI_BRAND: usize = 8;
/// Start of padding (per SV4 ABI)
const EI_PAD: usize = 9;
/// Size of e_ident array
const EI_NIDENT: usize = 16;

/// Values for the magic number bytes
const ELFMAG0: u8 = 0x7f;
const ELFMAG1: u8 = 'E' as u8;
const ELFMAG2: u8 = 'L' as u8;
const ELFMAG3: u8 = 'F' as u8;
const ELFMAG: &'static str = "\u{177}ELF";

/// Magic string size
const SELFMAG: usize = 4;

/// Value for e_ident[EI_VERSION]
enum EiVersion {
    EV_NONE = 0,
    EV_CURRENT = 1
}

/// Values for  EI_DATA
enum EiData {
    /// Unknwon data format
    ELFDATANONE = 0,
    /// Little endian, 2's complement
    ELFDATA2LSB = 1,
    /// Big endian, 2's complement
    ELFDATA2MSB,
}

/// Values for EI_CLASS
enum EiClass {
    /// Unknown class
    ELFCLASSNONE = 0,
    /// 32 bit arhitecture
    ELFCLASS32 = 1,
    /// 64 bit architecture
    ELFCLASS64 = 2
}

/// Values for EI_OSABI
enum EiOsAbi {
	/// UNIX System V ABI
	ELFOSABI_NONE          =  0,
	/// HP-UX operating system
	ELFOSABI_HPUX          =  1,
	/// NetBSD
	ELFOSABI_NETBSD        =  2,
	/// GNU/Linux
	ELFOSABI_LINUX         =  3,
	/// GNU/Hurd
	ELFOSABI_HURD          =  4,
	///  86Open common IA32 ABI
	ELFOSABI_86OPEN        =  5,
	/// Solaris
	ELFOSABI_SOLARIS       =  6,
	/// AIX
	ELFOSABI_AIX           =  7,
	/// IRIX
	ELFOSABI_IRIX          =  8,
	/// FreeBSD
	ELFOSABI_FREEBSD       =  9,
	/// TRU64 UNIX
	ELFOSABI_TRU64         =  10,
	/// Novell Modesto
	ELFOSABI_MODESTO       =  11,
	/// OpenBSD
	ELFOSABI_OPENBSD       =  12,
	/// Open VMS
	ELFOSABI_OPENVMS       =  13,
	/// HP Non-Stop Kernel
	ELFOSABI_NSK           =  14,
	/// Amiga Research OS
	ELFOSABI_AROS          =  15,
	/// FenixOS
	ELFOSABI_FENIXOS       =  16,
	/// Nuxi CloudABI
	ELFOSABI_CLOUDABI      =  17,
	/// ARM
	ELFOSABI_ARM           =  97,
	/// Standalone (embedded) application
	ELFOSABI_STANDALONE    =  255,
}

enum EiMachine {
    /// Unknown machine.
    EM_NONE     = 0,
    /// AT&T W    E32100.
    EM_M32      = 1,
    /// Sun SPARC.
    EM_SPARC    = 2,
    /// Intel i386.
    EM_386      = 3,
    /// Motorola= 68000.
    EM_68K      = 4,
    /// Motorola= 88000.
    EM_88K      = 5,
    /// Intel MCU.
    EM_IAMCU    = 6,
    /// Intel i860.
    EM_860      = 7,
    /// MIPS R3000 Big-    Endian only.
    EM_MIPS     = 8,
    /// IBM System/370.
    EM_S370     = 9,
    /// MIPS R3000 Little-    Endian.
    EM_MIPS_RS3_LE = 10,
    /// HP PA-RISC.
    EM_PARISC   = 15,
    /// Fujitsu VPP500.
    EM_VPP500   = 17,
    /// SPARC v8plus.
    EM_SPARC32PLUS = 18,
    /// Intel= 80960.
    EM_960      = 19,
    /// PowerPC= 32-bit.
    EM_PPC      = 20,
    /// PowerPC= 64-bit.
    EM_PPC64    = 21,
    /// IBM System/390.
    EM_S390     = 22,
    /// N    EC V800.
    EM_V800     = 36,
    /// Fujitsu FR20.
    EM_FR20     = 37,
    /// TRW RH-32.
    EM_RH32     = 38,
    /// Motorola RCE.
    EM_RCE      = 39,
    /// ARM.
    EM_ARM      = 40,
    /// Hitachi SH.
    EM_SH       = 42,
    /// SPARC v9= 64-bit.
    EM_SPARCV9   = 43,
    /// Siemens TriCore embedded processor.
    EM_TRICORE   = 44,
    /// Argonaut RISC Core.
    EM_ARC      = 45,
    /// Hitachi H8/300.
    EM_H8_300   = 46,
    /// Hitachi H8/300H.
    EM_H8_300H   = 47,
    /// Hitachi H8S.
    EM_H8S      = 48,
    /// Hitachi H8/500.
    EM_H8_500   = 49,
    /// Intel IA-64 Processor.
    EM_IA_64    = 50,
    /// Stanford MIPS-X.
    EM_MIPS_X   = 51,
    /// Motorola ColdFire.
    EM_COLDFIRE   = 52,
    /// Motorola M68HC12.
    EM_68HC12   = 53,
    /// Fujitsu MMA.
    EM_MMA      = 54,
    /// Siemens PCP.
    EM_PCP      = 55,
    /// Sony nCPU.
    EM_NCPU     = 56,
    /// Denso NDR1 microprocessor.
    EM_NDR1     = 57,
    /// Motorola Star*Core processor.
    EM_STARCORE   = 58,
    /// Toyota M    E16 processor.
    EM_ME16     = 59,
    /// STMicroelectronics ST100 processor.
    EM_ST100    = 60,
    /// Advanced Logic Corp. TinyJ processor.
    EM_TINYJ    = 61,
    /// Advanced Micro Devices x86-64,
    EM_X86_64   = 62,
    /// Sony DSP Processor.
    EM_PDSP     = 63,
    /// Siemens FX66 microcontroller.
    EM_FX66     = 66,
    EM_ST9PLUS   = 67,
    EM_ST7      = 68,
    /// Motorola MC68HC16 microcontroller.
    EM_68HC16   = 69,
    /// Motorola MC68HC11 microcontroller.
    EM_68HC11   = 70,
    /// Motorola MC68HC08 microcontroller.
    EM_68HC08   = 71,
    /// Motorola MC68HC05 microcontroller.
    EM_68HC05   = 72,
    /// Silicon Graphics SVx.
    EM_SVX      = 73,
    /// STMicroelectronics ST19= 8-bit mc.
    EM_ST19     = 74,
    /// Digital VAX.
    EM_VAX      = 75,
    EM_CRIS     = 76,
    EM_JAVELIN   = 77,
    ///    Element= 14 64-bit DSP Processor.
    EM_FIREPATH   = 78,
    /// LSI Logic= 16-bit DSP Processor.
    EM_ZSP      = 79,
    /// Donald Knuth's educational= 64-bit proc.
    EM_MMIX     = 80,
    EM_HUANY    = 81,
    /// SiTera Prism.
    EM_PRISM    = 82,
    /// Atmel AVR= 8-bit microcontroller.
    EM_AVR      = 83,
    /// Fujitsu FR30.
    EM_FR30     = 84,
    /// Mitsubishi D10V.
    EM_D10V     = 85,
    /// Mitsubishi D30V.
    EM_D30V     = 86,
    /// N    EC v850.
    EM_V850     = 87,
    /// Mitsubishi M32R.
    EM_M32R     = 88,
    /// Matsushita MN10300.
    EM_MN10300   = 89,
    /// Matsushita MN10200.
    EM_MN10200   = 90,
    /// picoJava.
    EM_PJ       = 91,
    /// OpenRISC= 32-bit embedded processor.
    EM_OPENRISC   = 92,
    /// ARC Cores Tangent-A5.
    EM_ARC_A5   = 93,
    /// Tensilica Xtensa Architecture.
    EM_XTENSA   = 94,
    /// Alphamosaic VideoCore processor.
    EM_VIDEOCORE   = 95,
	/// Thompson Multimedia General Purpose
    /// Processor.
    EM_TMM_GPP   = 96,
    /// National Semiconductor= 32000 series.
    EM_NS32K    = 97,
    /// Tenor Network TPC processor.
    EM_TPC      = 98,
    /// Trebia SNP= 1000 processor.
    EM_SNP1K    = 99,
    /// STMicroelectronics ST200 microcontroller.
    EM_ST200    = 100,
    /// Ubicom IP2xxx microcontroller family.
    EM_IP2K     = 101,
    /// MAX Processor.
    EM_MAX      = 102,
	/// National Semiconductor CompactRISC
    /// microprocessor.
    EM_CR       = 103,
    /// Fujitsu F2MC16.
    EM_F2MC16   = 104,
	/// Texas Instruments embedded microcontroller
    /// msp430.
    EM_MSP430   = 105,
    /// Analog Devices Blackfin (DSP) processor.
    EM_BLACKFIN   = 106,
    /// S1C33 Family of Seiko     Epson processors.
    EM_SE_C33   = 107,
    /// Sharp embedded microprocessor.
    EM_SEP      = 108,
    /// Arca RISC Microprocessor.
    EM_ARCA     = 109,
	/// Microprocessor series from PKU-Unity Ltd.
    /// and MPRC of Peking University
    EM_UNICORE   = 110,
    /// AArch64 (64-bit ARM)
    EM_AARCH64   = 183,
    /// RISC-V
    EM_RISCV    = 243,
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::transmute;
use std::ops::Range;

use static_assertions::assert_eq_size;

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://wiki.osdev.org/ELF_Tutorial
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
// * https://unix.stackexchange.com/questions/132036/why-does-readelf-show-system-v-as-my-os-instead-of-linux
// * http://www.sco.com/developers/gabi/latest/ch4.eheader.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const EI_MAG: Range<usize> = 0..4;
const EI_CLASS: usize = 4;
const EI_DATA: usize = 5;
const EI_VERSION: usize = 6;
const EI_OSABI: usize = 7;

const ELFMAG: &[u8] = b"\x7fELF";
const ELFCLASS64: u8 = 2;
const ELFDATA2LSB: u8 = 1;
const ELFOSABI_SYSV: u8 = 0;

const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: [u8; 16],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn elf64_write(f: &mut impl Write, text: &[u8], bss_size: u64) -> io::Result<()> {
    let size = text.len() as u64;
    let hdr_size = (EHDR_SIZE + 2 * PHDR_SIZE) as u64;
    let hdr_size_padded = (hdr_size + 0x1000 - 1) & !(0x1000 - 1);

    let mut e_ident = [0u8; 16];
    e_ident[EI_MAG].copy_from_slice(ELFMAG);
    e_ident[EI_CLASS] = ELFCLASS64;
    e_ident[EI_DATA] = ELFDATA2LSB;
    e_ident[EI_VERSION] = 1;
    e_ident[EI_OSABI] = ELFOSABI_SYSV;

    let ehdr = Elf64_Ehdr {
        e_ident,
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: hdr_size_padded,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: hdr_size_padded + bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    unsafe {
        f.write(&transmute::<_, [u8; EHDR_SIZE]>(ehdr))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss))?;
    }
    for _ in 0..(hdr_size_padded - hdr_size) {
        f.write(b"0")?;
    }
    f.write(text)?;
    Ok(())
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(
        ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64,
    ))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(
    f: &mut (impl Read + Seek),
    name: &[u8],
) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<commit_msg>Create an Elf64_Ident struct<commit_after>#![allow(non_camel_case_types)]

use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::transmute;

use static_assertions::assert_eq_size;

// Minimal ELF support, sufficient for a very simple 64-bit static Linux
// executable.

// Sources:
// * /usr/include/elf.h
// * https://wiki.osdev.org/ELF_Tutorial
// * https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
// * https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
// * https://unix.stackexchange.com/questions/132036/why-does-readelf-show-system-v-as-my-os-instead-of-linux
// * http://www.sco.com/developers/gabi/latest/ch4.eheader.html

type Elf64_Half = u16;
type Elf64_Word = u32;
type Elf64_Xword = u64;
type Elf64_Addr = u64;
type Elf64_Off = u64;

const ELFMAG: [u8; 4] = *b"\x7fELF";
const ELFCLASS64: u8 = 2;
const ELFDATA2LSB: u8 = 1;
const ELFOSABI_SYSV: u8 = 0;

const ET_EXEC: u16 = 2;
const EM_X86_64: u16 = 62;
const PT_LOAD: u32 = 1;

const PF_X: u32 = 1 << 0;
const PF_W: u32 = 1 << 1;
const PF_R: u32 = 1 << 2;

const EHDR_SIZE: usize = 64;
const PHDR_SIZE: usize = 56;
const SHDR_SIZE: usize = 64;

assert_eq_size!(ident_size_assert; Elf64_Ident, [u8; 16]);
assert_eq_size!(ehdr_size_assert; Elf64_Ehdr, [u8; EHDR_SIZE]);
assert_eq_size!(phdr_size_assert; Elf64_Phdr, [u8; PHDR_SIZE]);
assert_eq_size!(shdr_size_assert; Elf64_Shdr, [u8; SHDR_SIZE]);

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ident {
    pub ei_mag: [u8; 4],
    pub ei_class: u8,
    pub ei_data: u8,
    pub ei_version: u8,
    pub ei_osabi: u8,
    pub ei_abiversion: u8,
    pub ei_pad: [u8; 7],
}

// ELF header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Ehdr {
    pub e_ident: Elf64_Ident,
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

// Program header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

// Symbol header
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

pub fn elf64_write(f: &mut impl Write, text: &[u8], bss_size: u64) -> io::Result<()> {
    let size = text.len() as u64;
    let hdr_size = (EHDR_SIZE + 2 * PHDR_SIZE) as u64;
    let hdr_size_padded = (hdr_size + 0x1000 - 1) & !(0x1000 - 1);

    let ehdr = Elf64_Ehdr {
        e_ident: Elf64_Ident {
            ei_mag: ELFMAG,
            ei_class: ELFCLASS64,
            ei_data: ELFDATA2LSB,
            ei_version: 1,
            ei_osabi: ELFOSABI_SYSV,
            ei_abiversion: 0,
            ei_pad: [0; 7]
        },
        e_type: ET_EXEC,
        e_machine: EM_X86_64,
        e_version: 1,
        e_entry: 0x401000,
        // Put program header immediately after ELF header
        e_phoff: EHDR_SIZE as u64,
        // Don't include a section header table
        e_shoff: 0,
        e_flags: 0,
        e_ehsize: EHDR_SIZE as u16,
        e_phentsize: PHDR_SIZE as u16,
        e_phnum: 2,
        e_shentsize: SHDR_SIZE as u16,
        e_shnum: 0,
        e_shstrndx: 0,
    };

    let phdr_text = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_X,
        p_offset: hdr_size_padded,
        p_vaddr: 0x401000,
        p_paddr: 0x401000,
        p_filesz: size,
        p_memsz: size,
        p_align: 0x1000,
    };

    let bss_offset = (size + 0x1000 - 1) & !(0x1000 - 1);

    let phdr_bss = Elf64_Phdr {
        p_type: PT_LOAD,
        p_flags: PF_R | PF_W,
        p_offset: hdr_size_padded + bss_offset,
        p_vaddr: 0x401000 + bss_offset,
        p_paddr: 0x401000 + bss_offset,
        p_filesz: 0,
        p_memsz: bss_size,
        p_align: 0x1000,
    };

    unsafe {
        f.write(&transmute::<_, [u8; EHDR_SIZE]>(ehdr))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_text))?;
        f.write(&transmute::<_, [u8; PHDR_SIZE]>(phdr_bss))?;
    }
    for _ in 0..(hdr_size_padded - hdr_size) {
        f.write(b"0")?;
    }
    f.write(text)?;
    Ok(())
}

fn elf64_read_strtab(f: &mut (impl Read + Seek), ehdr: &Elf64_Ehdr) -> io::Result<Vec<u8>> {
    // Read section header for the string table
    let mut shdr_buf = [0; SHDR_SIZE];
    f.seek(SeekFrom::Start(
        ehdr.e_shoff + ehdr.e_shstrndx as u64 * SHDR_SIZE as u64,
    ))?;
    f.read(&mut shdr_buf)?;
    let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

    // Read string table section
    let mut strtab = Vec::with_capacity(shdr.sh_size as usize);
    strtab.resize(shdr.sh_size as usize, 0);
    f.seek(SeekFrom::Start(shdr.sh_offset))?;
    f.read(&mut strtab)?;

    Ok(strtab)
}

pub fn elf64_get_section(
    f: &mut (impl Read + Seek),
    name: &[u8],
) -> io::Result<Option<Elf64_Shdr>> {
    let mut ehdr_buf = [0; EHDR_SIZE];
    f.seek(SeekFrom::Start(0))?;
    f.read(&mut ehdr_buf)?;
    let ehdr: Elf64_Ehdr = unsafe { transmute(ehdr_buf) };

    let strtab = elf64_read_strtab(f, &ehdr)?;

    f.seek(SeekFrom::Start(ehdr.e_shoff))?;
    for _ in 0..ehdr.e_shnum {
        let mut shdr_buf = [0; SHDR_SIZE];
        f.read(&mut shdr_buf)?;
        let shdr: Elf64_Shdr = unsafe { transmute(shdr_buf) };

        let mut cur_name = &strtab[shdr.sh_name as usize..];
        if let Some(idx) = cur_name.iter().position(|c| *c == b'\0') {
            cur_name = &cur_name[..idx];
        }
        if cur_name == name {
            return Ok(Some(shdr));
        }
    }

    Ok(None)
}
<|endoftext|>


<commit_before>extern crate portmidi;
extern crate rci;

#[test]
fn test_main() {
    let ci = rci::Ci::new();
    // Check if the test runs in a continous integration environment.
    // The test will fail in Travis CI because the test runner has no
    // permissions to access `/dev/snd/seq`:
    //
    // ```sh
    // running 1 test
    //
    // ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: Permission denied
    //
    // test test_main ... FAILED
    // ```
    if ci.is_none() {
        let context = portmidi::PortMidi::new().unwrap();
        assert!(context.device_count() > 0);
        assert!(context.default_input_device_id().is_ok());
        assert!(context.default_output_device_id().is_ok());
        assert!(context.devices().unwrap().len() > 0);
        let mut in_port = context.default_input_port(1024).unwrap();
        let mut out_port = context.default_output_port(1024).unwrap();
        match in_port.poll() {
            Ok(flag) => println!("test_main) midi events available: {}", flag),
            Err(err) => println!("test_main) poll error: {}", err),
        };
        match in_port.read() {
            Ok(Some(event)) => println!("received midi event: {:?}", event),
            Ok(None) => println!("test_main) no midi event available"),
            Err(err) => println!("test_main) read error: {}", err),
        };
        let msgs = vec![portmidi::MidiMessage {
                            status: 0x90,
                            data1: 60,
                            data2: 127,
                        },
                        portmidi::MidiMessage {
                            status: 0x80,
                            data1: 60,
                            data2: 0,
                        }];
        match out_port.write_events(msgs) {
            Ok(_) => println!("test_main) successfully wrote midi events"),
            Err(err) => println!("test_main) write error: {}", err),
        }
    }
}
<commit_msg>Add thread test.<commit_after>extern crate portmidi;
extern crate rci;

use std::thread;

#[test]
fn test_main() {
    let ci = rci::Ci::new();
    // Check if the test runs in a continous integration environment.
    // The test will fail in Travis CI because the test runner has no
    // permissions to access `/dev/snd/seq`:
    //
    // ```sh
    // running 1 test
    //
    // ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: Permission denied
    //
    // test test_main ... FAILED
    // ```
    if ci.is_none() {
        let context = portmidi::PortMidi::new().unwrap();
        assert!(context.device_count() > 0);
        assert!(context.default_input_device_id().is_ok());
        assert!(context.default_output_device_id().is_ok());
        assert!(context.devices().unwrap().len() > 0);
        let mut in_port = context.default_input_port(1024).unwrap();
        let mut out_port = context.default_output_port(1024).unwrap();
        match in_port.poll() {
            Ok(flag) => println!("test_main) midi events available: {}", flag),
            Err(err) => println!("test_main) poll error: {}", err),
        };
        match in_port.read() {
            Ok(Some(event)) => println!("received midi event: {:?}", event),
            Ok(None) => println!("test_main) no midi event available"),
            Err(err) => println!("test_main) read error: {}", err),
        };
        let msgs = vec![portmidi::MidiMessage {
                            status: 0x90,
                            data1: 60,
                            data2: 127,
                        },
                        portmidi::MidiMessage {
                            status: 0x80,
                            data1: 60,
                            data2: 0,
                        }];
        match out_port.write_events(msgs) {
            Ok(_) => println!("test_main) successfully wrote midi events"),
            Err(err) => println!("test_main) write error: {}", err),
        }
    }
}

#[test]
fn test_threads() {
    let ci = rci::Ci::new();
    const BUF_LEN: usize = 1024;
    if ci.is_none() && false {
        let context = portmidi::PortMidi::new().unwrap();
        let mut in_port = context.default_input_port(BUF_LEN).unwrap();
        let mut out_port = context.default_output_port(BUF_LEN).unwrap();
        let reader = thread::spawn(move || {
            match in_port.poll() {
                Ok(flag) => println!("test_threads) midi events available: {}", flag),
                Err(err) => println!("test_threads) poll error: {}", err),
            }
            match in_port.read() {
                Ok(Some(event)) => println!("test_threads) received midi event: {:?}", event),
                Ok(None) => println!("test_threads) no midi event available"),
                Err(err) => println!("test_threads) read error: {}", err),
            }
        });
        let writer = thread::spawn(move || {
            let msgs = vec![portmidi::MidiMessage {
                                status: 0x90,
                                data1: 60,
                                data2: 127,
                            },
                            portmidi::MidiMessage {
                                status: 0x80,
                                data1: 60,
                                data2: 0,
                            }];
            match out_port.write_events(msgs) {
                Ok(_) => println!("test_threads) successfully wrote midi events"),
                Err(err) => println!("test_threads) write error: {}", err),
            }
        });
        reader.join();
        writer.join();
    }
}
<|endoftext|>


<commit_before>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    table: Table<'lua>
}

impl <'lua> From<Table<'lua>> for Object<'lua> {
    fn from(table: Table<'lua>) -> Self {
        Object { table }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        let data = obj.table.get::<_, Table>("data")?.get::<_, AnyUserData>("data")?;
        if data.is::<S>() {
            Ok(Self::_wrap(obj.table))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Table<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        self.get_table().get::<_, Table>("data")?.get::<_, S>("data")
    }

    fn set_state(&self, data: S) -> rlua::Result<()> {
        self.get_table().get::<_, Table>("data")?.set("data", data)
    }

    /// Gets the internal table for the concrete object.
    /// Used internally by cast, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_table(&self) -> Table<'lua>;

    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = S::default();
        // TODO FIXME
        // we put a wrapper table here,
        // but in awesome they use lua_setuservalue.
        // I don't think this is equivilent...it just forces things to "work"
        let wrapper_table = lua.create_table();
        wrapper_table.set("data", object)?;
        let object_table = lua.create_table();
        object_table.set("data", wrapper_table)?;
        let meta = lua.create_table();
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table())?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal))?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal))?;
        meta.set("emit_signal", lua.create_function(emit_signal))?;
        meta.set("__index", lua.create_function(default_index))?;
        meta.set("__newindex", lua.create_function(default_newindex))?;
        meta.set("__tostring", lua.create_function(|_, object_table: Table| {
            Ok(format!("{}", object_table.get::<_, Table>("data")?.get::<_, S>("data")?))
        }))?;
        object_table.set_metatable(Some(meta));
        let object = Object { table: object_table };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::Table(self.table))
    }
}

impl <'lua> Object<'lua> {
    /// Coerces a concrete object into a generic object.
    ///
    /// This requires a check to ensure data integrity, and it's often useless.
    /// Please don't use this method unless you need to.
    #[allow(dead_code)]
    #[deprecated]
    pub fn to_object<T, S, O>(obj: O) -> Self
        where S: Default + Display + Clone + UserData,
              O: Objectable<'lua, T, S>
    {
        let table = obj.get_table();
        let has_data = table.contains_key("data")
            .expect("Could not get data field of object table");
        assert_eq!(has_data, true);
        Object { table }
    }

    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table.get::<_, Table>("signals")
    }

    pub fn table(self) -> rlua::Table<'lua> {
        self.table
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj_table, index): (Table<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, Table>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = String::from_lua(index, lua)?;
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, Table>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj_table.into()))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.get("data")
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, Table>("__class") {
                let props = class.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj_table)
                        }
                    }
                }
                match class.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj_table)?.call(index)
                    },
                    Err(_) => {}
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj_table, index, val):
                              (Table<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, Table>("__class")?;
        let props = class.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj_table)?.call(val)
                }
            }
        }
        match class.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj_table)?.call(index)
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj_table, signal, func): (Table, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj_table.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj_table, signal): (Table, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj_table.into(), signal)
}

fn emit_signal(lua: &Lua, (obj_table, signal, args): (Table, String, Value))
               -> rlua::Result<()> {
    signal::emit_signal(lua, obj_table.into(), signal, args)
}
<commit_msg>Fixed object layout for good this time.<commit_after>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    table: Table<'lua>
}

impl <'lua> From<Table<'lua>> for Object<'lua> {
    fn from(table: Table<'lua>) -> Self {
        Object { table }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        let data = obj.table.get::<_, AnyUserData>("userdata")?;
        if data.is::<S>() {
            Ok(Self::_wrap(obj.table))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Table<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        self.get_table().get::<_, S>("userdata")
    }

    fn set_state(&self, data: S) -> rlua::Result<()> {
        self.get_table().set("userdata", data)
    }

    /// Gets the internal table for the concrete object.
    /// Used internally by cast, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_table(&self) -> Table<'lua>;

    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        // This is the format of the lua objects in Way Cooler:
        /*
        -- This is the weird wrapper table, binding the user data and the object table together
        {
            -- Actual user data object, e.g the Rust object
            userdata = <user_data_here>,
            -- This is the object data table, e.g the thing that in Awesome
            -- is linked to the user data with lua_setuservalue
            data = {},
            -- That metatable that is allocated in the new macro for objects.
            -- It can access both the userdata and the lua data fields
            __metatable = {}
        }
        */
        let object = S::default();
        // TODO Increment the instance count
        let wrapper_table = lua.create_table();
        wrapper_table.set("userdata", object)?;
        let data_table = lua.create_table();
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table();
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table())?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal))?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal))?;
        meta.set("emit_signal", lua.create_function(emit_signal))?;
        meta.set("__index", lua.create_function(default_index))?;
        meta.set("__newindex", lua.create_function(default_newindex))?;
        meta.set("__tostring", lua.create_function(|_, wrapper_table: Table| {
            Ok(format!("{}", wrapper_table.get::<_, S>("userdata")?))
        }))?;
        wrapper_table.set_metatable(Some(meta));
        // TODO Emit new signal event
        let object = Object { table: wrapper_table };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::Table(self.table))
    }
}

impl <'lua> Object<'lua> {
    /// Coerces a concrete object into a generic object.
    ///
    /// This requires a check to ensure data integrity, and it's often useless.
    /// Please don't use this method unless you need to.
    #[allow(dead_code)]
    #[deprecated]
    pub fn to_object<T, S, O>(obj: O) -> Self
        where S: Default + Display + Clone + UserData,
              O: Objectable<'lua, T, S>
    {
        let table = obj.get_table();
        assert!(table.contains_key("userdata")
                .expect("Could not get userdata field of object wrapper table"),
                "Table did not have special \"userdata\" field");
        assert!(table.contains_key("data")
                .expect("Could not get data field of object wrapper table"),
                "Table did not have special \"data\" field"
        );
        Object { table }
    }

    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table.get::<_, Table>("signals")
    }

    pub fn table(self) -> rlua::Table<'lua> {
        self.table
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj_table, index): (Table<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, Table>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = String::from_lua(index, lua)?;
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, Table>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj_table.into()))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.to_lua(lua)
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, Table>("__class") {
                let props = class.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj_table)
                        }
                    }
                }
                match class.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj_table)?.call(index)
                    },
                    Err(_) => {}
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj_table, index, val):
                              (Table<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, Table>("__class")?;
        let props = class.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj_table)?.call(val)
                }
            }
        }
        match class.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj_table)?.call(index)
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj_table, signal, func): (Table, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj_table.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj_table, signal): (Table, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj_table.into(), signal)
}

fn emit_signal(lua: &Lua, (obj_table, signal, args): (Table, String, Value))
               -> rlua::Result<()> {
    signal::emit_signal(lua, obj_table.into(), signal, args)
}
<|endoftext|>


<commit_before>#![allow(missing_copy_implementations)]

use libc::{c_char, c_int, c_uint, c_void};

pub enum QrsEngine {}
pub enum QrsMetaObject {}
pub enum QObject {}
pub enum QVariant {}
pub enum QVariantList {}

#[repr(C)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum QrsVariantType {
    Invalid = 0,
    Int64,
    Bool,
    String
}

pub type SlotFunction = extern "C" fn(data: *mut c_void, id: c_int, args: *const *const QVariant);

extern "C" {
    pub fn qmlrs_create_engine() -> *mut QrsEngine;
    pub fn qmlrs_create_engine_headless() -> *mut QrsEngine;
    pub fn qmlrs_destroy_engine(engine: *mut QrsEngine);
    pub fn qmlrs_engine_load_url(engine: *mut QrsEngine, path: *const c_char, len: c_uint);
    pub fn qmlrs_engine_load_from_data(engine: *mut QrsEngine, data: *const c_char, len: c_uint);
    pub fn qmlrs_engine_invoke(engine: *mut QrsEngine, method: *const c_char, result: *mut QVariant,
                               args: *const QVariantList);
    pub fn qmlrs_engine_set_property(engine: *mut QrsEngine, name: *const c_char, len: c_uint,
                                     object: *mut QObject);

    pub fn qmlrs_variant_create() -> *mut QVariant;
    pub fn qmlrs_variant_destroy(v: *mut QVariant);
    pub fn qmlrs_variant_set_int64(var: *mut QVariant, x: i64);
    pub fn qmlrs_variant_set_bool(var: *mut QVariant, x: bool);
    pub fn qmlrs_variant_set_invalid(var: *mut QVariant);
    pub fn qmlrs_variant_set_string(var: *mut QVariant, len: c_uint, data: *const c_char);
    pub fn qmlrs_variant_get_type(var: *const QVariant) -> QrsVariantType;
    pub fn qmlrs_variant_get_int64(var: *const QVariant, x: *mut i64);
    pub fn qmlrs_variant_get_bool(var: *const QVariant, x: *mut bool);
    pub fn qmlrs_variant_get_string_length(var: *const QVariant, out: *mut c_uint);
    pub fn qmlrs_variant_get_string_data(var: *const QVariant, out: *mut c_char);

    pub fn qmlrs_varlist_create() -> *mut QVariantList;
    pub fn qmlrs_varlist_destroy(list: *mut QVariantList);
    pub fn qmlrs_varlist_push(list: *mut QVariantList) -> *mut QVariant;
    pub fn qmlrs_varlist_length(list: *const QVariantList) -> c_uint;
    pub fn qmlrs_varlist_get(list: *const QVariantList, i: c_uint) -> *mut QVariant;

    pub fn qmlrs_app_exec();

    pub fn qmlrs_metaobject_create() -> *mut QrsMetaObject;
    pub fn qmlrs_metaobject_destroy(mo: *mut QrsMetaObject);
    pub fn qmlrs_metaobject_add_slot(mo: *mut QrsMetaObject, name: *const c_char, name_len: c_uint,
                                     argc: c_uint);
    pub fn qmlrs_metaobject_add_signal(mo: *mut QrsMetaObject, name: *const c_char,
                                       name_len: c_uint, argc: c_uint);
    pub fn qmlrs_metaobject_instantiate(mo: *mut QrsMetaObject/*, fun: SlotFunction,
                                        data: *mut c_void*/) -> *mut QObject;

    pub fn qmlrs_object_set_property(obj: *mut QObject, name: *const c_char, len: c_uint,
                                     val: *mut QVariant);
    pub fn qmlrs_object_emit_signal(obj: *mut QObject, id: c_uint);
    pub fn qmlrs_object_destroy(obj: *mut QObject);
}
<commit_msg>extend/fix ffi<commit_after>#![allow(missing_copy_implementations)]

use libc::{c_char, c_int, c_uint};

pub enum QrsEngine {}
pub enum QrsMetaObject {}
pub enum QObject {}
pub enum QVariant {}
pub enum QVariantList {}

#[repr(C)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum QrsVariantType {
    Invalid = 0,
    Int64,
    Bool,
    String
}

pub type SlotFunction = extern "C" fn(this: *mut QObject, id: c_int, args: *const QVariantList, ret: *mut QVariant);

extern "C" {
    pub fn qmlrs_create_engine() -> *mut QrsEngine;
    pub fn qmlrs_create_engine_headless() -> *mut QrsEngine;
    pub fn qmlrs_destroy_engine(engine: *mut QrsEngine);
    pub fn qmlrs_engine_load_url(engine: *mut QrsEngine, path: *const c_char, len: c_uint);
    pub fn qmlrs_engine_load_from_data(engine: *mut QrsEngine, data: *const c_char, len: c_uint);
    pub fn qmlrs_engine_invoke(engine: *mut QrsEngine, method: *const c_char, result: *mut QVariant,
                               args: *const QVariantList);
    pub fn qmlrs_engine_set_property(engine: *mut QrsEngine, name: *const c_char, len: c_uint,
                                     object: *mut QObject);

    pub fn qmlrs_variant_create() -> *mut QVariant;
    pub fn qmlrs_variant_destroy(v: *mut QVariant);
    pub fn qmlrs_variant_set_int64(var: *mut QVariant, x: i64);
    pub fn qmlrs_variant_set_bool(var: *mut QVariant, x: bool);
    pub fn qmlrs_variant_set_invalid(var: *mut QVariant);
    pub fn qmlrs_variant_set_string(var: *mut QVariant, len: c_uint, data: *const c_char);
    pub fn qmlrs_variant_get_type(var: *const QVariant) -> QrsVariantType;
    pub fn qmlrs_variant_get_int64(var: *const QVariant, x: *mut i64);
    pub fn qmlrs_variant_get_bool(var: *const QVariant, x: *mut bool);
    pub fn qmlrs_variant_get_string_length(var: *const QVariant, out: *mut c_uint);
    pub fn qmlrs_variant_get_string_data(var: *const QVariant, out: *mut c_char);

    pub fn qmlrs_varlist_create() -> *mut QVariantList;
    pub fn qmlrs_varlist_destroy(list: *mut QVariantList);
    pub fn qmlrs_varlist_push(list: *mut QVariantList) -> *mut QVariant;
    pub fn qmlrs_varlist_length(list: *const QVariantList) -> c_uint;
    pub fn qmlrs_varlist_get(list: *const QVariantList, i: c_uint) -> *mut QVariant;

    pub fn qmlrs_app_exec();

    pub fn qmlrs_metaobject_create(name: *const c_char, name_len: c_uint, slot_func: SlotFunction) -> *mut QrsMetaObject;
    pub fn qmlrs_metaobject_destroy(mo: *mut QrsMetaObject);
    pub fn qmlrs_metaobject_add_slot(mo: *mut QrsMetaObject, sig: *const c_char, sig_len: c_uint) -> c_int;
    pub fn qmlrs_metaobject_add_method(mo: *mut QrsMetaObject, sig: *const c_char, sig_len: c_uint) -> c_int;
    pub fn qmlrs_metaobject_add_signal(mo: *mut QrsMetaObject, sig: *const c_char, sig_len: c_uint) -> c_int;
    pub fn qmlrs_metaobject_add_property(obj: *mut QrsMetaObject, name: *const c_char, name_len: c_uint, typ: *const c_char,
                                         typ_len: c_uint, typ: *const c_char, typ_len: c_uint);
    pub fn qmlrs_metaobject_instantiate(mo: *mut QrsMetaObject) -> *mut QObject;

    pub fn qmlrs_object_call(obj: *mut QObject, id: c_int, argv: *const QVariantList, ret: *mut QVariant);
    pub fn qmlrs_object_emit(obj: *mut QObject, id: c_int, argv: *const QVariantList);
    pub fn qmlrs_object_set_property(obj: *mut QObject, name: *const c_char, name_len: c_uint, value: *const QVariant);
    pub fn qmlrs_object_get_property(obj: *mut QObject, name: *const c_char, name_len: c_uint, value: *const QVariant);

    pub fn qmlrs_object_delete_later(obj: *mut QObject);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::Store;

#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /**
     * Gets the CLI spec for the program and retreives the config file path (or uses the default on
     * in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
     * and builds the Runtime object with it.
     *
     * The cli_spec object should be initially build with the ::get_default_cli_builder() function.
     *
     */
    pub fn new(cli_spec: App<'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        use std::env;

        use libimagstore::hook::position::HookPosition;
        use libimagstore::error::StoreErrorKind;
        use libimagstorestdhook::debug::DebugHook;
        use libimagerror::trace::trace_error;
        use libimagerror::trace::trace_error_dbg;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_spec.get_matches();

        let is_debugging = matches.is_present("debugging");
        let is_verbose   = matches.is_present("verbosity");

        Runtime::init_logger(is_debugging, is_verbose);

        let rtp : PathBuf = matches.value_of("runtimepath")
            .map_or_else(|| {
                env::var("HOME")
                    .map(PathBuf::from)
                    .map(|mut p| { p.push(".imag"); p})
                    .unwrap_or_else(|_| {
                        panic!("You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways.");
                    })
            }, PathBuf::from);
        let storepath = matches.value_of("storepath")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let configpath = matches.value_of("config")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let cfg = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(cfg) => Some(cfg),
        };

        let store_config = match cfg {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", cfg).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        Store::new(storepath, store_config).map(|mut store| {
            // If we are debugging, generate hooks for all positions
            if is_debugging {
                let hooks = vec![
                    (DebugHook::new(HookPosition::PreCreate), HookPosition::PreCreate),
                    (DebugHook::new(HookPosition::PostCreate), HookPosition::PostCreate),
                    (DebugHook::new(HookPosition::PreRetrieve), HookPosition::PreRetrieve),
                    (DebugHook::new(HookPosition::PostRetrieve), HookPosition::PostRetrieve),
                    (DebugHook::new(HookPosition::PreUpdate), HookPosition::PreUpdate),
                    (DebugHook::new(HookPosition::PostUpdate), HookPosition::PostUpdate),
                    (DebugHook::new(HookPosition::PreDelete), HookPosition::PreDelete),
                    (DebugHook::new(HookPosition::PostDelete), HookPosition::PostDelete),
                ];

                // Put all debug hooks into the aspect "debug".
                // If it fails, trace the error and warn, but continue.
                for (hook, position) in hooks {
                    if let Err(e) = store.register_hook(position, &String::from("debug"), Box::new(hook)) {
                        if e.err_type() == StoreErrorKind::HookRegisterError {
                            trace_error_dbg(&e);
                            warn!("Registering debug hook with store failed");
                        } else {
                            trace_error(&e);
                        };
                    }
                }
            }

            Runtime {
                cli_matches: matches,
                configuration: cfg,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    /**
     * Get a commandline-interface builder object from `clap`
     *
     * This commandline interface builder object already contains some predefined interface flags:
     *   * -v | --verbose for verbosity
     *   * --debug for debugging
     *   * -c <file> | --config <file> for alternative configuration file
     *   * -r <path> | --rtp <path> for alternative runtimepath
     *   * --store <path> for alternative store path
     * Each has the appropriate help text included.
     *
     * The `appname` shall be "imag-<command>".
     */
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name("verbosity")
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("debugging")
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("config")
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("runtimepath")
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("storepath")
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("editor")
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))
    }

    /**
     * Initialize the internal logger
     */
    fn init_logger(is_debugging: bool, is_verbose: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Error
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
            })
            .map_err(|_| {
                panic!("Could not setup logger");
            })
            .ok();
        }
    }

    /**
     * Get the verbosity flag value
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /**
     * Get the debugging flag value
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /**
     * Get the runtimepath
     */
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /**
     * Get the commandline interface matches
     */
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /**
     * Get the configuration object
     */
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or({
                match self.configuration {
                    Some(ref c) => c.editor().cloned(),
                    _ => None,
                }
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

<commit_msg>Fix: hook registering should be hook-type agnostic<commit_after>use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::Store;

#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /**
     * Gets the CLI spec for the program and retreives the config file path (or uses the default on
     * in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
     * and builds the Runtime object with it.
     *
     * The cli_spec object should be initially build with the ::get_default_cli_builder() function.
     *
     */
    pub fn new(cli_spec: App<'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        use std::env;

        use libimagstore::hook::position::HookPosition as HP;
        use libimagstore::hook::Hook;
        use libimagstore::error::StoreErrorKind;
        use libimagstorestdhook::debug::DebugHook;
        use libimagerror::trace::trace_error;
        use libimagerror::trace::trace_error_dbg;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_spec.get_matches();

        let is_debugging = matches.is_present("debugging");
        let is_verbose   = matches.is_present("verbosity");

        Runtime::init_logger(is_debugging, is_verbose);

        let rtp : PathBuf = matches.value_of("runtimepath")
            .map_or_else(|| {
                env::var("HOME")
                    .map(PathBuf::from)
                    .map(|mut p| { p.push(".imag"); p})
                    .unwrap_or_else(|_| {
                        panic!("You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways.");
                    })
            }, PathBuf::from);
        let storepath = matches.value_of("storepath")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let configpath = matches.value_of("config")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let cfg = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(cfg) => Some(cfg),
        };

        let store_config = match cfg {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", cfg).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        Store::new(storepath, store_config).map(|mut store| {
            // If we are debugging, generate hooks for all positions
            if is_debugging {
                let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
                    (Box::new(DebugHook::new(HP::PreCreate))          , "debug", HP::PreCreate),
                    (Box::new(DebugHook::new(HP::PostCreate))         , "debug", HP::PostCreate),
                    (Box::new(DebugHook::new(HP::PreRetrieve))        , "debug", HP::PreRetrieve),
                    (Box::new(DebugHook::new(HP::PostRetrieve))       , "debug", HP::PostRetrieve),
                    (Box::new(DebugHook::new(HP::PreUpdate))          , "debug", HP::PreUpdate),
                    (Box::new(DebugHook::new(HP::PostUpdate))         , "debug", HP::PostUpdate),
                    (Box::new(DebugHook::new(HP::PreDelete))          , "debug", HP::PreDelete),
                    (Box::new(DebugHook::new(HP::PostDelete))         , "debug", HP::PostDelete),
                ];

                // If hook registration fails, trace the error and warn, but continue.
                for (hook, aspectname, position) in hooks {
                    if let Err(e) = store.register_hook(position, &String::from(aspectname), hook) {
                        if e.err_type() == StoreErrorKind::HookRegisterError {
                            trace_error_dbg(&e);
                            warn!("Registering debug hook with store failed");
                        } else {
                            trace_error(&e);
                        };
                    }
                }
            }

            Runtime {
                cli_matches: matches,
                configuration: cfg,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    /**
     * Get a commandline-interface builder object from `clap`
     *
     * This commandline interface builder object already contains some predefined interface flags:
     *   * -v | --verbose for verbosity
     *   * --debug for debugging
     *   * -c <file> | --config <file> for alternative configuration file
     *   * -r <path> | --rtp <path> for alternative runtimepath
     *   * --store <path> for alternative store path
     * Each has the appropriate help text included.
     *
     * The `appname` shall be "imag-<command>".
     */
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name("verbosity")
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("debugging")
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name("config")
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("runtimepath")
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("storepath")
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name("editor")
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))
    }

    /**
     * Initialize the internal logger
     */
    fn init_logger(is_debugging: bool, is_verbose: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Error
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
            })
            .map_err(|_| {
                panic!("Could not setup logger");
            })
            .ok();
        }
    }

    /**
     * Get the verbosity flag value
     */
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /**
     * Get the debugging flag value
     */
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /**
     * Get the runtimepath
     */
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /**
     * Get the commandline interface matches
     */
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /**
     * Get the configuration object
     */
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /**
     * Get the store object
     */
    pub fn store(&self) -> &Store {
        &self.store
    }

    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or({
                match self.configuration {
                    Some(ref c) => c.editor().cloned(),
                    _ => None,
                }
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

<|endoftext|>