<commit_before>extern crate fallible_iterator;
extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use fallible_iterator::FallibleIterator;
use object::Object;
use std::env;
use std::fs;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optopt("e",
                "exe",
                "Set the input file name (default is a.out)",
                "<executable>");

    let matches = opts.parse(&args[1..]).unwrap();

    let file_path = matches.opt_str("e").unwrap_or("a.out".to_string());
    let file = fs::File::open(&file_path).expect("Should open file");
    let file = memmap::Mmap::open(&file, memmap::Protection::Read)
        .expect("Should create a mmap for file");
    let file = object::File::parse(unsafe { file.as_slice() });

    let addrs = matches.free.iter().map(|x| parse_uint_from_hex_string(x)).collect();

    if file.is_little_endian() {
        symbolicate::<gimli::LittleEndian>(&file, addrs);
    } else {
        symbolicate::<gimli::BigEndian>(&file, addrs);
    }
}

fn parse_uint_from_hex_string(string: &str) -> u64 {
    if string.len() > 2 && string.starts_with("0x") {
        u64::from_str_radix(&string[2..], 16).expect("Failed to parse address")
    } else {
        u64::from_str_radix(string, 16).expect("Failed to parse address")
    }
}

fn display_file<Endian>(header: &gimli::LineNumberProgramHeader<Endian>,
                        row: &gimli::LineNumberRow)
    where Endian: gimli::Endianity
{
    let file = row.file(header).unwrap();
    if let Some(directory) = file.directory(header) {
        println!("{}/{}:{}",
                 directory.to_string_lossy(),
                 file.path_name().to_string_lossy(),
                 row.line().unwrap());
    } else {
        println!("{}:{}",
                 file.path_name().to_string_lossy(),
                 row.line().unwrap());
    }
}

fn symbolicate<Endian>(file: &object::File, addrs: Vec<u64>)
    where Endian: gimli::Endianity
{
    let debug_info = file.get_section(".debug_info")
        .expect("Can't addr2line without .debug_info");
    let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);
    let debug_abbrev = file.get_section(".debug_abbrev")
        .expect("Can't addr2line without .debug_abbrev");
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_line = file.get_section(".debug_line")
        .expect("Can't addr2line without .debug_line");
    let debug_line = gimli::DebugLine::<Endian>::new(debug_line);
    let debug_ranges = file.get_section(".debug_ranges").unwrap_or(&[]);
    let debug_ranges = gimli::DebugRanges::<Endian>::new(debug_ranges);

    let mut units = Vec::new();
    let mut headers = debug_info.units();
    while let Some(header) = headers.next().expect("Couldn't get DIE header") {
        if let Some(unit) = Unit::parse(&debug_abbrev, &debug_ranges, &header) {
            units.push(unit);
        }
    }

    for addr in addrs {
        find_address(debug_line, &units, addr);
    }
}

fn find_address<Endian>(debug_line: gimli::DebugLine<Endian>, units: &[Unit], addr: u64)
    where Endian: gimli::Endianity
{
    for unit in units {
        if unit.contains_address(addr) {
            if let Ok(mut lines) = unit.lines(debug_line) {
                if let Ok(Some((header, row))) = lines.run_to_address(&addr) {
                    display_file(header, row);
                    return;
                };
            }
        }
    }
    println!("Failed to find matching line for {}", addr);
}

// TODO: most of this should be moved to the main library.
struct Unit {
    address_size: u8,
    ranges: Vec<gimli::Range>,
    line_offset: gimli::DebugLineOffset,
}

impl Unit {
    fn parse<Endian>(debug_abbrev: &gimli::DebugAbbrev<Endian>,
                     debug_ranges: &gimli::DebugRanges<Endian>,
                     header: &gimli::UnitHeader<Endian>)
                     -> Option<Unit>
        where Endian: gimli::Endianity
    {
        let abbrev = debug_abbrev.abbreviations(header.debug_abbrev_offset()).expect("Fail");
        let mut entries = header.entries(&abbrev);
        let (_, entry) = entries.next_dfs()
            .expect("Should parse first entry OK")
            .expect("And first entry should exist!");
        assert_eq!(entry.tag(), gimli::DW_TAG_compile_unit);

        let ranges = if let Some(ranges) =
                            Self::parse_noncontiguous_ranges(entry,
                                                             debug_ranges,
                                                             header.address_size()) {
            ranges
        } else if let Some(range) = Self::parse_contiguous_range(entry) {
            vec![range]
        } else {
            return None;
        };

        let line_offset = match entry.attr_value(gimli::DW_AT_stmt_list) {
            Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
            _ => return None,
        };

        Some(Unit {
            address_size: header.address_size(),
            ranges: ranges,
            line_offset: line_offset,
        })
    }

    // This must be checked before `parse_contiguous_range`.
    fn parse_noncontiguous_ranges<Endian>(entry: &gimli::DebuggingInformationEntry<Endian>,
                                          debug_ranges: &gimli::DebugRanges<Endian>,
                                          address_size: u8)
                                          -> Option<Vec<gimli::Range>>
        where Endian: gimli::Endianity
    {
        let offset = match entry.attr_value(gimli::DW_AT_ranges) {
            Some(gimli::AttributeValue::DebugRangesRef(offset)) => offset,
            _ => return None,
        };
        let base_address = match entry.attr_value(gimli::DW_AT_low_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            _ => 0,
        };
        let ranges = debug_ranges.ranges(offset, address_size, base_address)
            .expect("Range offset should be valid");
        Some(ranges.collect().expect("Should parse ranges"))
    }

    fn parse_contiguous_range<Endian>(entry: &gimli::DebuggingInformationEntry<Endian>)
                                      -> Option<gimli::Range>
        where Endian: gimli::Endianity
    {
        debug_assert!(entry.attr_value(gimli::DW_AT_ranges).is_none());

        let low_pc = match entry.attr_value(gimli::DW_AT_low_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            _ => return None,
        };

        let high_pc = match entry.attr_value(gimli::DW_AT_high_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            Some(gimli::AttributeValue::Udata(size)) => low_pc.wrapping_add(size),
            None => low_pc.wrapping_add(1),
            _ => return None,
        };

        // TODO: convert to error
        assert!(low_pc < high_pc);
        Some(gimli::Range {
            begin: low_pc,
            end: high_pc,
        })
    }

    fn contains_address(&self, address: u64) -> bool {
        self.ranges.iter().any(|range| address >= range.begin && address < range.end)
    }

    fn lines<'a, Endian>(&self,
                         debug_line: gimli::DebugLine<'a, Endian>)
                         -> gimli::Result<gimli::StateMachine<'a, Endian>>
        where Endian: gimli::Endianity
    {
        let header = try!(gimli::LineNumberProgramHeader::new(debug_line,
                                                              self.line_offset,
                                                              self.address_size));
        Ok(gimli::StateMachine::new(header))
    }
}
<commit_msg>addr2line: handle addresses within line number rows<commit_after>extern crate fallible_iterator;
extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use fallible_iterator::FallibleIterator;
use object::Object;
use std::env;
use std::fs;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optopt("e",
                "exe",
                "Set the input file name (default is a.out)",
                "<executable>");

    let matches = opts.parse(&args[1..]).unwrap();

    let file_path = matches.opt_str("e").unwrap_or("a.out".to_string());
    let file = fs::File::open(&file_path).expect("Should open file");
    let file = memmap::Mmap::open(&file, memmap::Protection::Read)
        .expect("Should create a mmap for file");
    let file = object::File::parse(unsafe { file.as_slice() });

    let addrs = matches.free.iter().map(|x| parse_uint_from_hex_string(x)).collect();

    if file.is_little_endian() {
        symbolicate::<gimli::LittleEndian>(&file, addrs);
    } else {
        symbolicate::<gimli::BigEndian>(&file, addrs);
    }
}

fn parse_uint_from_hex_string(string: &str) -> u64 {
    if string.len() > 2 && string.starts_with("0x") {
        u64::from_str_radix(&string[2..], 16).expect("Failed to parse address")
    } else {
        u64::from_str_radix(string, 16).expect("Failed to parse address")
    }
}

fn display_file<Endian>(header: &gimli::LineNumberProgramHeader<Endian>,
                        row: &gimli::LineNumberRow)
    where Endian: gimli::Endianity
{
    let file = row.file(header).unwrap();
    if let Some(directory) = file.directory(header) {
        println!("{}/{}:{}",
                 directory.to_string_lossy(),
                 file.path_name().to_string_lossy(),
                 row.line().unwrap());
    } else {
        println!("{}:{}",
                 file.path_name().to_string_lossy(),
                 row.line().unwrap());
    }
}

fn symbolicate<Endian>(file: &object::File, addrs: Vec<u64>)
    where Endian: gimli::Endianity
{
    let debug_info = file.get_section(".debug_info")
        .expect("Can't addr2line without .debug_info");
    let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);
    let debug_abbrev = file.get_section(".debug_abbrev")
        .expect("Can't addr2line without .debug_abbrev");
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_line = file.get_section(".debug_line")
        .expect("Can't addr2line without .debug_line");
    let debug_line = gimli::DebugLine::<Endian>::new(debug_line);
    let debug_ranges = file.get_section(".debug_ranges").unwrap_or(&[]);
    let debug_ranges = gimli::DebugRanges::<Endian>::new(debug_ranges);

    let mut units = Vec::new();
    let mut headers = debug_info.units();
    while let Some(header) = headers.next().expect("Couldn't get DIE header") {
        if let Some(unit) = Unit::parse(&debug_abbrev, &debug_ranges, &header) {
            units.push(unit);
        }
    }

    for addr in addrs {
        find_address(debug_line, &units, addr);
    }
}

fn find_address<Endian>(debug_line: gimli::DebugLine<Endian>, units: &[Unit], addr: u64)
    where Endian: gimli::Endianity
{
    let mut current = None;
    for unit in units {
        if unit.contains_address(addr) {
            if let Ok(mut lines) = unit.lines(debug_line) {
                while let Ok(Some((header, row))) = lines.next_row() {
                    if row.address() > addr {
                        if let Some(ref row) = current {
                            display_file(header, row);
                            return;
                        }
                        break;
                    }
                    if row.end_sequence() {
                        current = None;
                    } else {
                        current = Some(row.clone());
                    }
                }
            }
        }
    }
    println!("Failed to find matching line for {}", addr);
}

// TODO: most of this should be moved to the main library.
struct Unit {
    address_size: u8,
    ranges: Vec<gimli::Range>,
    line_offset: gimli::DebugLineOffset,
}

impl Unit {
    fn parse<Endian>(debug_abbrev: &gimli::DebugAbbrev<Endian>,
                     debug_ranges: &gimli::DebugRanges<Endian>,
                     header: &gimli::UnitHeader<Endian>)
                     -> Option<Unit>
        where Endian: gimli::Endianity
    {
        let abbrev = debug_abbrev.abbreviations(header.debug_abbrev_offset()).expect("Fail");
        let mut entries = header.entries(&abbrev);
        let (_, entry) = entries.next_dfs()
            .expect("Should parse first entry OK")
            .expect("And first entry should exist!");
        assert_eq!(entry.tag(), gimli::DW_TAG_compile_unit);

        let ranges = if let Some(ranges) =
                            Self::parse_noncontiguous_ranges(entry,
                                                             debug_ranges,
                                                             header.address_size()) {
            ranges
        } else if let Some(range) = Self::parse_contiguous_range(entry) {
            vec![range]
        } else {
            return None;
        };

        let line_offset = match entry.attr_value(gimli::DW_AT_stmt_list) {
            Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
            _ => return None,
        };

        Some(Unit {
            address_size: header.address_size(),
            ranges: ranges,
            line_offset: line_offset,
        })
    }

    // This must be checked before `parse_contiguous_range`.
    fn parse_noncontiguous_ranges<Endian>(entry: &gimli::DebuggingInformationEntry<Endian>,
                                          debug_ranges: &gimli::DebugRanges<Endian>,
                                          address_size: u8)
                                          -> Option<Vec<gimli::Range>>
        where Endian: gimli::Endianity
    {
        let offset = match entry.attr_value(gimli::DW_AT_ranges) {
            Some(gimli::AttributeValue::DebugRangesRef(offset)) => offset,
            _ => return None,
        };
        let base_address = match entry.attr_value(gimli::DW_AT_low_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            _ => 0,
        };
        let ranges = debug_ranges.ranges(offset, address_size, base_address)
            .expect("Range offset should be valid");
        Some(ranges.collect().expect("Should parse ranges"))
    }

    fn parse_contiguous_range<Endian>(entry: &gimli::DebuggingInformationEntry<Endian>)
                                      -> Option<gimli::Range>
        where Endian: gimli::Endianity
    {
        debug_assert!(entry.attr_value(gimli::DW_AT_ranges).is_none());

        let low_pc = match entry.attr_value(gimli::DW_AT_low_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            _ => return None,
        };

        let high_pc = match entry.attr_value(gimli::DW_AT_high_pc) {
            Some(gimli::AttributeValue::Addr(addr)) => addr,
            Some(gimli::AttributeValue::Udata(size)) => low_pc.wrapping_add(size),
            None => low_pc.wrapping_add(1),
            _ => return None,
        };

        // TODO: convert to error
        assert!(low_pc < high_pc);
        Some(gimli::Range {
            begin: low_pc,
            end: high_pc,
        })
    }

    fn contains_address(&self, address: u64) -> bool {
        self.ranges.iter().any(|range| address >= range.begin && address < range.end)
    }

    fn lines<'a, Endian>(&self,
                         debug_line: gimli::DebugLine<'a, Endian>)
                         -> gimli::Result<gimli::StateMachine<'a, Endian>>
        where Endian: gimli::Endianity
    {
        let header = try!(gimli::LineNumberProgramHeader::new(debug_line,
                                                              self.line_offset,
                                                              self.address_size));
        Ok(gimli::StateMachine::new(header))
    }
}
<|endoftext|>


<commit_before>// In this example we execute a contract funciton exported as "_call"

extern crate parity_wasm;

use std::env::args;

use parity_wasm::{interpreter, ModuleInstanceInterface};

fn main() {
    let args: Vec<_> = args().collect();
    if args.len() != 3 {
        println!("Usage: {} <wasm file> <arg>", args[0]);
        println!("    wasm file should contain exported `_call` function with single I32 argument");
        return;
    }
    // Intrepreter initialization.
    // parity_wasm::ProgramInstance can be parameterized with a custom User error to be returned from native modules
    // parity_wasm::DefaultProgramInstance parametrize ProgramInstance with a pre-defined "DummyUserError"
    // Initializes a default "env" module also.
    let program = parity_wasm::DefaultProgramInstance::with_env_params(
        interpreter::EnvParams {
            total_stack: 128*1024,
            total_memory: 2*1024*1024,
            allow_memory_growth: false,
        }
    ).expect("Failed to load program");

    // Here we load module using dedicated for this purpose
    // `deserialize_file` function (which works only with modules)
    let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
    // Intialize deserialized module. It adds module into It expects 3 parameters:
    // - a name for the module
    // - a module declaration
    // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
    // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
    let module = program.add_module("main", module, None).expect("Failed to initialize module");

    // The argument should be parsable as a valid integer
    let argument: i32 = args[2].parse().expect("Integer argument required");

    // "_call" export of function to be executed with an i32 argument and prints the result of execution
    println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
}
<commit_msg>line sep added<commit_after>// In this example we execute a contract funciton exported as "_call"

extern crate parity_wasm;

use std::env::args;

use parity_wasm::{interpreter, ModuleInstanceInterface};

fn main() {
    let args: Vec<_> = args().collect();
    if args.len() != 3 {
        println!("Usage: {} <wasm file> <arg>", args[0]);
        println!("    wasm file should contain exported `_call` function with single I32 argument");
        return;
    }

    // Intrepreter initialization.
    // parity_wasm::ProgramInstance can be parameterized with a custom User error to be returned from native modules
    // parity_wasm::DefaultProgramInstance parametrize ProgramInstance with a pre-defined "DummyUserError"
    // Initializes a default "env" module also.
    let program = parity_wasm::DefaultProgramInstance::with_env_params(
        interpreter::EnvParams {
            total_stack: 128*1024,
            total_memory: 2*1024*1024,
            allow_memory_growth: false,
        }
    ).expect("Failed to load program");

    // Here we load module using dedicated for this purpose
    // `deserialize_file` function (which works only with modules)
    let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");

    // Intialize deserialized module. It adds module into It expects 3 parameters:
    // - a name for the module
    // - a module declaration
    // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
    // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
    let module = program.add_module("main", module, None).expect("Failed to initialize module");

    // The argument should be parsable as a valid integer
    let argument: i32 = args[2].parse().expect("Integer argument required");

    // "_call" export of function to be executed with an i32 argument and prints the result of execution
    println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
}
<|endoftext|>


<commit_before>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;

use std::mem;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
fn test_ptrace_setoptions() {
    use nix::sys::ptrace::ptrace::PTRACE_O_TRACESYSGOOD;
    let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
fn test_ptrace_getevent() {
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
fn test_ptrace_getsiginfo() {
    match ptrace::getsiginfo(getpid()) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
fn test_ptrace_setsiginfo() {
    let siginfo = unsafe { mem::uninitialized() };
    match ptrace::setsiginfo(getpid(), &siginfo) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    // FIXME: qemu-user doesn't implement ptrace on all arches and gives ENOSYS then.
    // use it to filter out the affected platforms
    // on valid platforms it will return Errno::EPERM
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match fork() {
        Ok(Child) => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Ok(Parent { child }) => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Signal::SIGKILL).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {}
                _ => panic!("The process should have been killed"),
            }
        },
        Err(_) => panic!("Error: Fork Failed")
    }
}
<commit_msg>Reword the comment.<commit_after>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;

use std::mem;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
fn test_ptrace_setoptions() {
    use nix::sys::ptrace::ptrace::PTRACE_O_TRACESYSGOOD;
    let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
fn test_ptrace_getevent() {
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
fn test_ptrace_getsiginfo() {
    match ptrace::getsiginfo(getpid()) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
fn test_ptrace_setsiginfo() {
    let siginfo = unsafe { mem::uninitialized() };
    match ptrace::setsiginfo(getpid(), &siginfo) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    // FIXME: qemu-user doesn't implement ptrace on all architectures
    // and retunrs ENOSYS in this case.
    // We (ab)use this behavior to detect the affected platforms
    // and skip the test then.
    // On valid platforms the ptrace call should return Errno::EPERM, this
    // is already tested by `test_ptrace`.
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match fork() {
        Ok(Child) => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Ok(Parent { child }) => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Signal::SIGKILL).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {}
                _ => panic!("The process should have been killed"),
            }
        },
        Err(_) => panic!("Error: Fork Failed")
    }
}
<|endoftext|>


<commit_before>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters.
//! * No files with over 3000 lines.
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.

use std::path::Path;

const COLS: usize = 100;

const LINES: usize = 3000;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(line: &str) -> bool {
    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;
    let is_url = |w: &str| w.starts_with("http://") || w.starts_with("https://");

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") |
            (EXP_COMMENT_START, "///") |
            (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:")
                => state = EXP_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if is_url(w)
                => state = EXP_END,

            (EXP_URL, w)
                if is_url(w) || w.starts_with("../")
                => state = EXP_END,

            (_, w)
                if w.len() > COLS && is_url(w)
                => state = EXP_END,

            (_, _) => {}
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(line: &str) -> bool {
    if line_is_url(line) {
        return true;
    }

    false
}

enum Directive {
    /// By default, tidy always warns against style issues.
    Deny,

    /// `Ignore(false)` means that an `ignore-tidy-*` directive
    /// has been provided, but is unnecessary. `Ignore(true)`
    /// means that it is necessary (i.e. a warning would be
    /// produced if `ignore-tidy-*` was not present).
    Ignore(bool),
}

fn contains_ignore_directive(contents: &str, check: &str) -> Directive {
    if contents.contains(&format!("// ignore-tidy-{}", check)) ||
        contents.contains(&format!("# ignore-tidy-{}", check)) {
        Directive::Ignore(false)
    } else {
        Directive::Deny
    }
}

macro_rules! suppressible_tidy_err {
    ($err:ident, $skip:ident, $msg:expr) => {
        if let Directive::Deny = $skip {
            $err($msg);
        } else {
            $skip = Directive::Ignore(true);
        }
    };
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
        if extensions.iter().all(|e| !filename.ends_with(e)) ||
           filename.starts_with(".#") {
            return
        }

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let mut skip_cr = contains_ignore_directive(&contents, "cr");
        let mut skip_tab = contains_ignore_directive(&contents, "tab");
        let mut skip_line_length = contains_ignore_directive(&contents, "linelength");
        let mut skip_file_length = contains_ignore_directive(&contents, "filelength");
        let mut skip_end_whitespace = contains_ignore_directive(&contents, "end-whitespace");
        let mut skip_copyright = contains_ignore_directive(&contents, "copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        let mut lines = 0;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if line.chars().count() > COLS && !long_line_is_ok(line) {
                suppressible_tidy_err!(
                    err,
                    skip_line_length,
                    &format!("line longer than {} chars", COLS)
                );
            }
            if line.contains('\t') {
                suppressible_tidy_err!(err, skip_tab, "tab character");
            }
            if line.ends_with(' ') || line.ends_with('\t') {
                suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace");
            }
            if line.contains('\r') {
                suppressible_tidy_err!(err, skip_cr, "CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            if (line.starts_with("// Copyright") ||
                line.starts_with("# Copyright") ||
                line.starts_with("Copyright"))
                && (line.contains("Rust Developers") ||
                    line.contains("Rust Project Developers")) {
                suppressible_tidy_err!(
                    err,
                    skip_copyright,
                    "copyright notices attributed to the Rust Project Developers are deprecated"
                );
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
            lines = i;
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        match trailing_new_lines {
            0 => tidy_error!(bad, "{}: missing trailing newline", file.display()),
            1 => {}
            n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n),
        };
        if lines > LINES {
            let mut err = |_| {
                tidy_error!(
                    bad,
                    "{}: too many lines ({}) (add `// \
                     ignore-tidy-filelength` to the file to suppress this error)",
                    file.display(),
                    lines
                );
            };
            suppressible_tidy_err!(err, skip_file_length, "");
        }

        if let Directive::Ignore(false) = skip_cr {
            tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_tab {
            tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_line_length {
            tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_file_length {
            tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_end_whitespace {
            tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_copyright {
            tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
        }
    })
}
<commit_msg>Skip querying each ignore directive if none in file<commit_after>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters.
//! * No files with over 3000 lines.
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! A number of these checks can be opted-out of with various directives of the form:
//! `// ignore-tidy-CHECK-NAME`.

use std::path::Path;

const COLS: usize = 100;

const LINES: usize = 3000;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(line: &str) -> bool {
    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;
    let is_url = |w: &str| w.starts_with("http://") || w.starts_with("https://");

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") |
            (EXP_COMMENT_START, "///") |
            (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:")
                => state = EXP_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if is_url(w)
                => state = EXP_END,

            (EXP_URL, w)
                if is_url(w) || w.starts_with("../")
                => state = EXP_END,

            (_, w)
                if w.len() > COLS && is_url(w)
                => state = EXP_END,

            (_, _) => {}
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(line: &str) -> bool {
    if line_is_url(line) {
        return true;
    }

    false
}

enum Directive {
    /// By default, tidy always warns against style issues.
    Deny,

    /// `Ignore(false)` means that an `ignore-tidy-*` directive
    /// has been provided, but is unnecessary. `Ignore(true)`
    /// means that it is necessary (i.e. a warning would be
    /// produced if `ignore-tidy-*` was not present).
    Ignore(bool),
}

fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
    if !can_contain {
        return Directive::Deny;
    }
    // Update `can_contain` when changing this
    if contents.contains(&format!("// ignore-tidy-{}", check)) ||
        contents.contains(&format!("# ignore-tidy-{}", check)) {
        Directive::Ignore(false)
    } else {
        Directive::Deny
    }
}

macro_rules! suppressible_tidy_err {
    ($err:ident, $skip:ident, $msg:expr) => {
        if let Directive::Deny = $skip {
            $err($msg);
        } else {
            $skip = Directive::Ignore(true);
        }
    };
}

pub fn check(path: &Path, bad: &mut bool) {
    super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
        let file = entry.path();
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
        if extensions.iter().all(|e| !filename.ends_with(e)) ||
           filename.starts_with(".#") {
            return
        }

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let can_contain = contents.contains("// ignore-tidy-") ||
            contents.contains("# ignore-tidy-");
        let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
        let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
        let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
        let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
        let mut skip_end_whitespace =
            contains_ignore_directive(can_contain, &contents, "end-whitespace");
        let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        let mut lines = 0;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if line.chars().count() > COLS && !long_line_is_ok(line) {
                suppressible_tidy_err!(
                    err,
                    skip_line_length,
                    &format!("line longer than {} chars", COLS)
                );
            }
            if line.contains('\t') {
                suppressible_tidy_err!(err, skip_tab, "tab character");
            }
            if line.ends_with(' ') || line.ends_with('\t') {
                suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace");
            }
            if line.contains('\r') {
                suppressible_tidy_err!(err, skip_cr, "CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            if (line.starts_with("// Copyright") ||
                line.starts_with("# Copyright") ||
                line.starts_with("Copyright"))
                && (line.contains("Rust Developers") ||
                    line.contains("Rust Project Developers")) {
                suppressible_tidy_err!(
                    err,
                    skip_copyright,
                    "copyright notices attributed to the Rust Project Developers are deprecated"
                );
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
            lines = i;
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        match trailing_new_lines {
            0 => tidy_error!(bad, "{}: missing trailing newline", file.display()),
            1 => {}
            n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n),
        };
        if lines > LINES {
            let mut err = |_| {
                tidy_error!(
                    bad,
                    "{}: too many lines ({}) (add `// \
                     ignore-tidy-filelength` to the file to suppress this error)",
                    file.display(),
                    lines
                );
            };
            suppressible_tidy_err!(err, skip_file_length, "");
        }

        if let Directive::Ignore(false) = skip_cr {
            tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_tab {
            tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_line_length {
            tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_file_length {
            tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_end_whitespace {
            tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
        }
        if let Directive::Ignore(false) = skip_copyright {
            tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
        }
    })
}
<|endoftext|>


<commit_before>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-disable-isolation

use std::thread::{spawn, sleep};
use std::ptr::null_mut;
use std::sync::atomic::{Ordering, AtomicPtr};
use std::time::Duration;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

pub fn main() {
    // Shared atomic pointer
    let pointer = AtomicPtr::new(null_mut::<usize>());
    let ptr = EvilSend(&pointer as *const AtomicPtr<usize>);

    // Note: this is scheduler-dependent
    // the operations need to occur in
    // order, otherwise the allocation is
    // not visible to the other-thread to
    // detect the race:
    //  1. stack-allocate
    //  2. read
    //  3. stack-deallocate
    unsafe {
        let j1 = spawn(move || {
            // Concurrent allocate the memory.
            // Uses relaxed semantics to not generate
            // a release sequence.
            let pointer = &*ptr.0;

            let mut stack_var = 0usize;

            pointer.store(&mut stack_var as *mut _, Ordering::Release);

            sleep(Duration::from_millis(1000));

            // FIXME: find cause of implicit read event
            drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2)
        });

        let j2 = spawn(move || {
            let pointer = &*ptr.0;
            *pointer.load(Ordering::Acquire) = 3;
        });

        j1.join().unwrap();
        j2.join().unwrap();
    }
}
<commit_msg>Update note<commit_after>// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-disable-isolation

use std::thread::{spawn, sleep};
use std::ptr::null_mut;
use std::sync::atomic::{Ordering, AtomicPtr};
use std::time::Duration;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

pub fn main() {
    // Shared atomic pointer
    let pointer = AtomicPtr::new(null_mut::<usize>());
    let ptr = EvilSend(&pointer as *const AtomicPtr<usize>);

    // Note: this is scheduler-dependent
    // the operations need to occur in
    // order, otherwise the allocation is
    // not visible to the other-thread to
    // detect the race:
    //  1. stack-allocate
    //  2. read
    //  3. stack-deallocate
    unsafe {
        let j1 = spawn(move || {
            // Concurrent allocate the memory.
            // Uses relaxed semantics to not generate
            // a release sequence.
            let pointer = &*ptr.0;

            let mut stack_var = 0usize;

            pointer.store(&mut stack_var as *mut _, Ordering::Release);

            sleep(Duration::from_millis(1000));

            // Note: Implicit read for drop(_) races with write, would detect race with deallocate after.
            drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2)
        });

        let j2 = spawn(move || {
            let pointer = &*ptr.0;
            *pointer.load(Ordering::Acquire) = 3;
        });

        j1.join().unwrap();
        j2.join().unwrap();
    }
}
<|endoftext|>


<commit_before>//! Some microbenchmarks that stress test a pure `join` path.

use rayon;
use rayon::prelude::*;
use test::Bencher;

#[bench]
fn increment_all(b: &mut Bencher) {
    let mut big_vec = vec![0_usize; 100*1024];
    b.iter(|| {
        big_vec.par_iter_mut()
               .for_each(|p| *p = p.wrapping_add(1));
    });
}

#[bench]
fn join_recursively(b: &mut Bencher) {
    fn join_recursively(n: usize) {
        if n == 0 {
            return;
        }
        rayon::join(|| join_recursively(n - 1), || join_recursively(n - 1));
    }

    b.iter(|| {
        join_recursively(16);
    });
}

<commit_msg>Add quick benchmarks of min/max len<commit_after>//! Some microbenchmarks that stress test a pure `join` path.

use rayon;
use rayon::prelude::*;
use test::Bencher;

#[bench]
fn increment_all(b: &mut Bencher) {
    let mut big_vec = vec![0_usize; 100*1024];
    b.iter(|| {
        big_vec.par_iter_mut()
               .for_each(|p| *p = p.wrapping_add(1));
    });
}

#[bench]
fn increment_all_min(b: &mut Bencher) {
    let mut big_vec = vec![0_usize; 100*1024];
    b.iter(|| {
        big_vec.par_iter_mut()
               .set_min_len(1024)
               .for_each(|p| *p = p.wrapping_add(1));
    });
}

#[bench]
fn increment_all_max(b: &mut Bencher) {
    let mut big_vec = vec![0_usize; 100*1024];
    b.iter(|| {
        big_vec.par_iter_mut()
               .set_max_len(100)
               .for_each(|p| *p = p.wrapping_add(1));
    });
}

#[bench]
fn join_recursively(b: &mut Bencher) {
    fn join_recursively(n: usize) {
        if n == 0 {
            return;
        }
        rayon::join(|| join_recursively(n - 1), || join_recursively(n - 1));
    }

    b.iter(|| {
        join_recursively(16);
    });
}

<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use ::model::{MessageId, UserId};

/// An indicator of the type of sorting mode to use when searching for
/// [`Message`]s via the [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingMode {
    /// Search by messages' relevance to parameters.
    Relevance,
    /// Search by messages' timestamp, where results will match according to
    /// parameters. This is used in conjunction in the [`Search::sort_order`]
    /// method, and is used in conjunction with [`SortingOrder`].
    ///
    /// [`Search::sort_order`]: struct.Search.html#method.sort_order
    /// [`SortingOrder`]: enum.SortingOrder.html
    Timestamp,
}

impl SortingMode {
    /// Retrieves the name of the sorting mode. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingMode::Relevance => "relevance",
            SortingMode::Timestamp => "timestamp",
        }
    }
}

/// An indicator of how to sort results when searching for [`Message`]s via the
/// [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingOrder {
    /// Search message results in ascending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// least relevant to the most relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will indicate to search
    /// from the least recent to the most recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Ascending,
    /// Search message results in descending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// most relevant to least relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will search from the
    /// most recent to least recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Descending,
}

impl SortingOrder {
    /// Retrieves the name of the sorting order. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingOrder::Ascending => "asc",
            SortingOrder::Descending => "desc",
        }
    }
}

/// A builder used to query a [`Channel`] or [`Guild`] for its [`Message`]s,
/// specifying certain parameters to narrow down the returned messages.
///
/// Many methods are provided to narrow down the results, such as [`sort_by`] -
/// which is used with the [`SortingMode`] enum to sort the results - or
/// [`limit`], which can be used in conjunction with [`offset`] to paginate
/// results.
///
/// # Examples
///
/// Provided are multiple in-depth examples for searching through different
/// means. Also see [example 08] for a fully runnable bot.
///
/// ### Searching a Channel
///
/// Search for messages via [`Context::search_channel`] with the content
/// `"rust"`, which have no embed, no attachment, searching by relevance in
/// ascending order, and limiting to 5 results:
///
/// ```rust,ignore
/// // assuming you are in a context
///
/// let res = context.search_channel(message.channel_id, |s| s
///     .content("rust")
///     .has_embed(false)
///     .has_attachment(false)
///     .limit(5)
///     .sort_by(SortingMode::Relevance)
///     .sort_order(SortingOrder::Ascending));
/// ```
///
/// ### Searching a Guild's Channels
///
/// Search for messages with a query provided by a user, which have an
/// embed, have no attachment, searching by timestamp in descending order,
/// limiting to 2 results, and only searching channels that have a name
/// prefixed with `"search-"`:
///
/// ```rust,no_run
/// use serenity::client::{Client, Context};
/// use serenity::model::Message;
/// use serenity::utils::builder::{SortingMode, SortingOrder};
/// use std::env;
///
/// let client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
///
/// client.with_framework(|f| f
///     .configure(|c| c.prefix("~").on_mention(true))
///     .on("search", search));
///
/// fn search(context: Context, message: Message, args: Vec<String>) {
///     let query = args.join(" ");
///
///     if query.is_empty() {
///         let _ = context.say("You must provide a query");
///
///         return;
///     }
///
///     let guild = match message.guild().unwrap();
///
///     let channel_ids = guild.iter()
///         .channels
///         .values()
///         .filter(|c| c.name.starts_with("search-"))
///         .map(|c| c.id)
///         .collect();
///
///     let search = context.search_guild(guild.id, channel_ids, |s| s
///         .content(&query)
///         .context_size(0)
///         .has_attachment(true)
///         .has_embed(true)
///         .max_id(message.id.0 - 1)
///         .sort_by(SortingMode::Timestamp)
///         .sort_order(SortingOrder::Descending));
///
///     let messages = match search {
///         Ok(messages) => messages,
///         Err(why) => {
///             println!("Error performing search '{}': {:?}", query, why);
///
///             let _ = context.say("Error occurred while searching");
///
///             return;
///         },
///     };
///
///     let _ = context.send_message(message.channel_id, |m| m
///         .content(&format!("Found {} total results", messages.total))
///         .embed(|e| {
///             for (i, messages) in messages.results.iter().enumerate() {
///                 let mut message = messages[0];
///                 message.content.truncate(1000);
///
///                 e.field(|f| f
///                     .name(&format!("Result {}", i))
///                     .value(&message.content));
///              }
///
///              e
///         }));
/// }
/// ```
///
/// [`Channel`]: ../../model/enum.Channel.html
/// [`Context::search_channel`]: ../../client/struct.Context.html#method.search_channel
/// [`Guild`]: ../../model/struct.Guild.html
/// [`Message`]: ../../model/struct.Message.html
/// [`SortingMode`]: enum.SortingMode.html
/// [`limit`]: #method.limit
/// [`offset`]: #method.offset
/// [`sort_by`]: #method.sort_by
/// [example 08]: https://github.com/zeyla/serenity.rs/tree/master/examples/08_search
pub struct Search<'a>(pub BTreeMap<&'a str, String>);

impl<'a> Search<'a> {
    /// Sets the list of attachment extensions to search by.
    ///
    /// When providing a vector of extensions, do _not_ include the period (`.`)
    /// character as part of the search.
    ///
    /// This is sent to Discord as a comma-separated value list of extension
    /// names.
    pub fn attachment_extensions(mut self, attachment_extensions: &[&str]) -> Self {
        let list = attachment_extensions.join(" ");

        self.0.insert("attachment_extensions", list);

        self
    }

    /// Sets the filename of the attachments to search for.
    pub fn attachment_filename(mut self, attachment_filename: &str) -> Self {
        self.0.insert("attachment_filename", attachment_filename.to_owned());

        self
    }

    /// Sets the Id of the author of [`Message`]s to search for. This excludes
    /// all messages by other [`User`]s.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`User`]: ../../model/struct.User.html
    pub fn author_id<U: Into<UserId>>(mut self, author_id: U) -> Self {
        self.0.insert("author_id", author_id.into().0.to_string());

        self
    }

    /// Sets the content of the [`Message`] to search for. This is a fuzzy
    /// search, and can partially match the given query content.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn content(mut self, content: &str) -> Self {
        self.0.insert("content", content.to_owned());

        self
    }

    /// Sets the amount of "context" [`Message`]s to provide, at maximum. This
    /// is the number of messages to provide around each side
    /// (ascending+descending) of the "hit" (aka found) message.
    ///
    /// The default value is `2`. The minimum value is `0`. The maximum value is
    /// `2`.
    pub fn context_size(mut self, context_size: u8) -> Self {
        self.0.insert("context_size", context_size.to_string());

        self
    }

    /// Sets the embed providers to search by.
    ///
    /// This is a list of the providers' names.
    ///
    /// This is sent to Discord as a comma-separated value list of provider
    /// names.
    pub fn embed_providers(mut self, embed_providers: &[&str]) -> Self {
        self.0.insert("embed_providers", embed_providers.join(" "));

        self
    }

    /// Sets the type of [`Embed`]s to search by.
    ///
    /// An example of an [embed type][`Embed::kind`] is `"rich"`.
    ///
    /// [`Embed`]: ../../model/struct.Embed.html
    /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind
    pub fn embed_types(mut self, embed_types: &[&str]) -> Self {
        self.0.insert("embed_types", embed_types.join(" "));

        self
    }

    /// Sets whether to search for methods that do - or do not - have an
    /// attachment.
    ///
    /// Do not specify to search for both.
    pub fn has_attachment(mut self, has_attachment: bool) -> Self {
        self.0.insert("has_attachment", has_attachment.to_string());

        self
    }

    /// Sets whether to search for methods that do - or do not - have an embed.
    ///
    /// Do not specify to search for both.
    pub fn has_embed(mut self, has_embed: bool) -> Self {
        self.0.insert("has_embed", has_embed.to_string());

        self
    }

    /// Sets the number of messages to retrieve _at maximum_. This can be used
    /// in conjunction with [`offset`].
    ///
    /// The minimum value is `1`. The maximum value is `25`.
    ///
    /// [`offset`]: #method.offset
    pub fn limit(mut self, limit: u8) -> Self {
        self.0.insert("limit", limit.to_string());

        self
    }

    /// Set the maximum [`Message`] Id to search up to. All messages with an Id
    /// greater than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn max_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("max_id", message_id.into().0.to_string());

        self
    }

    /// Set the minimum [`Message`]s Id to search down to. All messages with an
    /// Id less than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn min_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("min_id", message_id.into().0.to_string());

        self
    }

    /// Set the offset of [`Message`]s to return. This can be used in
    /// conjunction with [`limit`].
    ///
    /// The minimum value is `0`. The maximum value is `5000`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`limit`]: fn.limit.html
    pub fn offset(mut self, offset: u16) -> Self {
        self.0.insert("offset", offset.to_string());

        self
    }

    /// The sorting mode to use.
    ///
    /// Refer to [`SortingMode`] for more information.
    ///
    /// [`SortingMode`]: enum.SortingMode.html
    pub fn sort_by(mut self, sorting_mode: SortingMode) -> Self {
        self.0.insert("sort_by", sorting_mode.name().to_string());

        self
    }

    /// The order to sort results by.
    ///
    /// Refer to the documentation for [`SortingOrder`] for more information.
    ///
    /// [`SortingOrder`]: enum.SortingOrder.html
    pub fn sort_order(mut self, sorting_order: SortingOrder) -> Self {
        self.0.insert("sort_order", sorting_order.name().to_string());

        self
    }
}

impl<'a> Default for Search<'a> {
    /// Creates a new builder for searching for [`Message`]s. Refer to each
    /// method to learn what minimum and maximum values are available for each
    /// field, as well as restrictions and other useful information.
    ///
    /// The library does not provide defaults differently than what Discord
    /// itself defaults to.
    ///
    /// This list of defaults is:
    ///
    /// - [`context_size`]: 2
    /// - [`limit`]: 25
    /// - [`offset`]: 0
    /// - [`sort_by`]: [`SortingMode::Timestamp`]
    ///
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    /// [`context_size`]: #method.context_size
    /// [`limit`]: #method.limit
    /// [`offset`]: #method.offset
    /// [`sort_by`]: #method.sort_by
    fn default<'b>() -> Search<'b> {
        Search(BTreeMap::default())
    }
}
<commit_msg>Fix doctest<commit_after>use std::collections::BTreeMap;
use ::model::{MessageId, UserId};

/// An indicator of the type of sorting mode to use when searching for
/// [`Message`]s via the [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingMode {
    /// Search by messages' relevance to parameters.
    Relevance,
    /// Search by messages' timestamp, where results will match according to
    /// parameters. This is used in conjunction in the [`Search::sort_order`]
    /// method, and is used in conjunction with [`SortingOrder`].
    ///
    /// [`Search::sort_order`]: struct.Search.html#method.sort_order
    /// [`SortingOrder`]: enum.SortingOrder.html
    Timestamp,
}

impl SortingMode {
    /// Retrieves the name of the sorting mode. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingMode::Relevance => "relevance",
            SortingMode::Timestamp => "timestamp",
        }
    }
}

/// An indicator of how to sort results when searching for [`Message`]s via the
/// [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingOrder {
    /// Search message results in ascending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// least relevant to the most relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will indicate to search
    /// from the least recent to the most recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Ascending,
    /// Search message results in descending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// most relevant to least relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will search from the
    /// most recent to least recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Descending,
}

impl SortingOrder {
    /// Retrieves the name of the sorting order. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingOrder::Ascending => "asc",
            SortingOrder::Descending => "desc",
        }
    }
}

/// A builder used to query a [`Channel`] or [`Guild`] for its [`Message`]s,
/// specifying certain parameters to narrow down the returned messages.
///
/// Many methods are provided to narrow down the results, such as [`sort_by`] -
/// which is used with the [`SortingMode`] enum to sort the results - or
/// [`limit`], which can be used in conjunction with [`offset`] to paginate
/// results.
///
/// # Examples
///
/// Provided are multiple in-depth examples for searching through different
/// means. Also see [example 08] for a fully runnable bot.
///
/// ### Searching a Channel
///
/// Search for messages via [`Context::search_channel`] with the content
/// `"rust"`, which have no embed, no attachment, searching by relevance in
/// ascending order, and limiting to 5 results:
///
/// ```rust,ignore
/// // assuming you are in a context
///
/// let res = context.search_channel(message.channel_id, |s| s
///     .content("rust")
///     .has_embed(false)
///     .has_attachment(false)
///     .limit(5)
///     .sort_by(SortingMode::Relevance)
///     .sort_order(SortingOrder::Ascending));
/// ```
///
/// ### Searching a Guild's Channels
///
/// Search for messages with a query provided by a user, which have an
/// embed, have no attachment, searching by timestamp in descending order,
/// limiting to 2 results, and only searching channels that have a name
/// prefixed with `"search-"`:
///
/// ```rust,no_run
/// use serenity::client::{Client, Context};
/// use serenity::model::Message;
/// use serenity::utils::builder::{SortingMode, SortingOrder};
/// use std::env;
///
/// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
///
/// client.with_framework(|f| f
///     .configure(|c| c.prefix("~").on_mention(true))
///     .on("search", search));
///
/// fn search(context: &Context, message: &Message, args: Vec<String>) -> Result<(), String> {
///     let query = args.join(" ");
///
///     if query.is_empty() {
///         let _ = context.say("You must provide a query");
///
///         return Ok(());
///     }
///
///     let guild = message.guild().unwrap();
///
///     let channel_ids = guild.channels
///         .values()
///         .filter(|c| c.name.starts_with("search-"))
///         .map(|c| c.id)
///         .collect();
///
///     let search = context.search_guild(guild.id, channel_ids, |s| s
///         .content(&query)
///         .context_size(0)
///         .has_attachment(true)
///         .has_embed(true)
///         .max_id(message.id.0 - 1)
///         .sort_by(SortingMode::Timestamp)
///         .sort_order(SortingOrder::Descending));
///
///     let mut messages = match search {
///         Ok(messages) => messages,
///         Err(why) => {
///             println!("Error performing search '{}': {:?}", query, why);
///
///             let _ = context.say("Error occurred while searching");
///
///             return Ok(());
///         },
///     };
///
///     let _ = context.send_message(message.channel_id, |m| m
///         .content(&format!("Found {} total results", messages.total))
///         .embed(|mut e| {
///             for (i, messages) in messages.results.iter_mut().enumerate() {
///                 let mut message = match messages.get_mut(i) {
///                     Some(message) => message,
///                     None => break,
///                 };
///
///                 message.content.truncate(1000);
///
///                 e = e.field(|f| f
///                     .name(&format!("Result {}", i))
///                     .value(&message.content));
///              }
///
///              e
///         }));
///
///     Ok(())
/// }
/// ```
///
/// [`Channel`]: ../../model/enum.Channel.html
/// [`Context::search_channel`]: ../../client/struct.Context.html#method.search_channel
/// [`Guild`]: ../../model/struct.Guild.html
/// [`Message`]: ../../model/struct.Message.html
/// [`SortingMode`]: enum.SortingMode.html
/// [`limit`]: #method.limit
/// [`offset`]: #method.offset
/// [`sort_by`]: #method.sort_by
/// [example 08]: https://github.com/zeyla/serenity.rs/tree/master/examples/08_search
pub struct Search<'a>(pub BTreeMap<&'a str, String>);

impl<'a> Search<'a> {
    /// Sets the list of attachment extensions to search by.
    ///
    /// When providing a vector of extensions, do _not_ include the period (`.`)
    /// character as part of the search.
    ///
    /// This is sent to Discord as a comma-separated value list of extension
    /// names.
    pub fn attachment_extensions(mut self, attachment_extensions: &[&str]) -> Self {
        let list = attachment_extensions.join(" ");

        self.0.insert("attachment_extensions", list);

        self
    }

    /// Sets the filename of the attachments to search for.
    pub fn attachment_filename(mut self, attachment_filename: &str) -> Self {
        self.0.insert("attachment_filename", attachment_filename.to_owned());

        self
    }

    /// Sets the Id of the author of [`Message`]s to search for. This excludes
    /// all messages by other [`User`]s.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`User`]: ../../model/struct.User.html
    pub fn author_id<U: Into<UserId>>(mut self, author_id: U) -> Self {
        self.0.insert("author_id", author_id.into().0.to_string());

        self
    }

    /// Sets the content of the [`Message`] to search for. This is a fuzzy
    /// search, and can partially match the given query content.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn content(mut self, content: &str) -> Self {
        self.0.insert("content", content.to_owned());

        self
    }

    /// Sets the amount of "context" [`Message`]s to provide, at maximum. This
    /// is the number of messages to provide around each side
    /// (ascending+descending) of the "hit" (aka found) message.
    ///
    /// The default value is `2`. The minimum value is `0`. The maximum value is
    /// `2`.
    pub fn context_size(mut self, context_size: u8) -> Self {
        self.0.insert("context_size", context_size.to_string());

        self
    }

    /// Sets the embed providers to search by.
    ///
    /// This is a list of the providers' names.
    ///
    /// This is sent to Discord as a comma-separated value list of provider
    /// names.
    pub fn embed_providers(mut self, embed_providers: &[&str]) -> Self {
        self.0.insert("embed_providers", embed_providers.join(" "));

        self
    }

    /// Sets the type of [`Embed`]s to search by.
    ///
    /// An example of an [embed type][`Embed::kind`] is `"rich"`.
    ///
    /// [`Embed`]: ../../model/struct.Embed.html
    /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind
    pub fn embed_types(mut self, embed_types: &[&str]) -> Self {
        self.0.insert("embed_types", embed_types.join(" "));

        self
    }

    /// Sets whether to search for methods that do - or do not - have an
    /// attachment.
    ///
    /// Do not specify to search for both.
    pub fn has_attachment(mut self, has_attachment: bool) -> Self {
        self.0.insert("has_attachment", has_attachment.to_string());

        self
    }

    /// Sets whether to search for methods that do - or do not - have an embed.
    ///
    /// Do not specify to search for both.
    pub fn has_embed(mut self, has_embed: bool) -> Self {
        self.0.insert("has_embed", has_embed.to_string());

        self
    }

    /// Sets the number of messages to retrieve _at maximum_. This can be used
    /// in conjunction with [`offset`].
    ///
    /// The minimum value is `1`. The maximum value is `25`.
    ///
    /// [`offset`]: #method.offset
    pub fn limit(mut self, limit: u8) -> Self {
        self.0.insert("limit", limit.to_string());

        self
    }

    /// Set the maximum [`Message`] Id to search up to. All messages with an Id
    /// greater than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn max_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("max_id", message_id.into().0.to_string());

        self
    }

    /// Set the minimum [`Message`]s Id to search down to. All messages with an
    /// Id less than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn min_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("min_id", message_id.into().0.to_string());

        self
    }

    /// Set the offset of [`Message`]s to return. This can be used in
    /// conjunction with [`limit`].
    ///
    /// The minimum value is `0`. The maximum value is `5000`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`limit`]: fn.limit.html
    pub fn offset(mut self, offset: u16) -> Self {
        self.0.insert("offset", offset.to_string());

        self
    }

    /// The sorting mode to use.
    ///
    /// Refer to [`SortingMode`] for more information.
    ///
    /// [`SortingMode`]: enum.SortingMode.html
    pub fn sort_by(mut self, sorting_mode: SortingMode) -> Self {
        self.0.insert("sort_by", sorting_mode.name().to_string());

        self
    }

    /// The order to sort results by.
    ///
    /// Refer to the documentation for [`SortingOrder`] for more information.
    ///
    /// [`SortingOrder`]: enum.SortingOrder.html
    pub fn sort_order(mut self, sorting_order: SortingOrder) -> Self {
        self.0.insert("sort_order", sorting_order.name().to_string());

        self
    }
}

impl<'a> Default for Search<'a> {
    /// Creates a new builder for searching for [`Message`]s. Refer to each
    /// method to learn what minimum and maximum values are available for each
    /// field, as well as restrictions and other useful information.
    ///
    /// The library does not provide defaults differently than what Discord
    /// itself defaults to.
    ///
    /// This list of defaults is:
    ///
    /// - [`context_size`]: 2
    /// - [`limit`]: 25
    /// - [`offset`]: 0
    /// - [`sort_by`]: [`SortingMode::Timestamp`]
    ///
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    /// [`context_size`]: #method.context_size
    /// [`limit`]: #method.limit
    /// [`offset`]: #method.offset
    /// [`sort_by`]: #method.sort_by
    fn default<'b>() -> Search<'b> {
        Search(BTreeMap::default())
    }
}
<|endoftext|>


<commit_before>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component_result = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => Ok(component),
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            match component_result {
                Ok(component) => {
                    au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit); // TODO: Check error code
                    // Initialise the audio unit!
                    au::AudioUnitInitialize(instance); // TODO: Check error code
                    Ok(AudioUnit {
                        instance: instance,
                        callback: None
                    })
                },
                Err(err) => Err(err),
            }
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { mem::transmute(callback) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, callback: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        // TODO: Double-check naming etc in here; could probably be better.
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can transmute back to a
            // Box<RenderCallback> within our AudioUnit's Drop implementation (otherwise it
            // would leak).
            let callback_ptr: *mut libc::c_void = match callback {
                Some(x) => mem::transmute(Box::new(x)),
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            match Error::from_os_status(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32)) {
                Ok(()) => {
                    self.free_render_callback();
                    self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
                    Ok(())
                },
                Err(err) => Err(err),
            }
        }
    }

    /// Start the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already started.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStart(self.instance))); }
        Ok(())
    }

    /// Stop the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already stopped.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStop(self.instance))); }
        Ok(())
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.instance,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<commit_msg>Added more error checking and refactored<commit_after>//!
//! This module is an attempt to provide a friendly, rust-esque interface to
//! Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API here:
//! https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2
//!

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// Represents the input and output scope.
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the input and output elements .
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different types of Audio Units.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => return Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => component,
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            try!(Error::from_os_status(au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit)));
            // Initialise the audio unit!
            try!(Error::from_os_status(au::AudioUnitInitialize(instance)));
            Ok(AudioUnit {
                instance: instance,
                callback: None
            })
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { mem::transmute(callback) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, callback: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        // TODO: Double-check naming etc in here; could probably be better.
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can transmute back to a
            // Box<RenderCallback> within our AudioUnit's Drop implementation (otherwise it
            // would leak).
            let callback_ptr: *mut libc::c_void = match callback {
                Some(x) => mem::transmute(Box::new(x)),
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            try!(Error::from_os_status(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32)));

            self.free_render_callback();
            self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
            Ok(())
        }
    }

    /// Start the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already started.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStart(self.instance))); }
        Ok(())
    }

    /// Stop the audio unit.
    // TOOD: Test and see what happens when this is called and the audio unit is already stopped.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try!(Error::from_os_status(au::AudioOutputUnitStop(self.instance))); }
        Ok(())
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> StreamFormat {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            if let Err(err) = Error::from_os_status(au::AudioUnitGetProperty(
                                                        self.instance,
                                                        au::kAudioUnitProperty_StreamFormat,
                                                        Scope::Output as libc::c_uint,
                                                        Element::Output as libc::c_uint,
                                                        &mut asbd as *mut _ as *mut libc::c_void,
                                                        &mut size as *mut au::UInt32)) {
                panic!("{:?}", err);
            }
            StreamFormat::from_asbd(asbd)
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<|endoftext|>