<commit_before>extern crate anagram;

#[test]
fn test_no_matches() {
    let inputs = ["hello", "world", "zombies", "pants"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("diaper", &inputs), outputs);
}

#[test]
#[ignore]
fn test_detect_simple_anagram() {
    let inputs = ["tan", "stand", "at"];
    let outputs: Vec<&str> = vec!["tan"];
    assert_eq!(anagram::anagrams_for("ant", &inputs), outputs);
}

#[test]
#[ignore]
fn test_does_not_confuse_different_duplicates() {
    let inputs = ["eagle"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("galea", &inputs), outputs);
}

#[test]
#[ignore]
fn test_eliminate_anagram_subsets() {
    let inputs = ["dog", "goody"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("good", &inputs), outputs);
}

#[test]
#[ignore]
fn test_detect_anagram() {
    let inputs = ["enlists", "google", "inlets", "banana"];
    let outputs: Vec<&str> = vec!["inlets"];
    assert_eq!(anagram::anagrams_for("listen", &inputs), outputs);
}

#[test]
#[ignore]
fn test_multiple_anagrams() {
    let inputs = ["gallery", "ballerina", "regally", "clergy", "largely", "leading"];
    let outputs: Vec<&str> = vec!["gallery", "regally", "largely"];
    assert_eq!(anagram::anagrams_for("allergy", &inputs), outputs);
}

#[test]
#[ignore]
fn test_case_insensitive_anagrams() {
    let inputs = ["cashregister", "Carthorse", "radishes"];
    let outputs: Vec<&str> = vec!["Carthorse"];
    assert_eq!(anagram::anagrams_for("Orchestra", &inputs), outputs);
}

#[test]
#[ignore]
fn test_unicode_anagrams() {
    // These words don't make sense, they're just greek letters cobbled together.
    let inputs = ["ΒΓΑ", "ΒΓΔ", "γβα"];
    let outputs: Vec<&str> = vec!["ΒΓΑ", "γβα"];
    assert_eq!(anagram::anagrams_for("ΑΒΓ", &inputs), outputs);
}

#[test]
#[ignore]
fn test_misleading_unicode_anagrams() {
    // Despite what a human might think these words different letters, the input uses Greek A and B
    // while the list of potential anagrams uses Latin A and B.
    let inputs = ["ABΓ"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("ΑΒΓ", &inputs), outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_word_as_its_own_anagram() {
    let inputs = ["banana"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("banana", &inputs), outputs);
}
<commit_msg>add test in anagram, that bAnana is not an anagram of banana<commit_after>extern crate anagram;

#[test]
fn test_no_matches() {
    let inputs = ["hello", "world", "zombies", "pants"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("diaper", &inputs), outputs);
}

#[test]
#[ignore]
fn test_detect_simple_anagram() {
    let inputs = ["tan", "stand", "at"];
    let outputs: Vec<&str> = vec!["tan"];
    assert_eq!(anagram::anagrams_for("ant", &inputs), outputs);
}

#[test]
#[ignore]
fn test_does_not_confuse_different_duplicates() {
    let inputs = ["eagle"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("galea", &inputs), outputs);
}

#[test]
#[ignore]
fn test_eliminate_anagram_subsets() {
    let inputs = ["dog", "goody"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("good", &inputs), outputs);
}

#[test]
#[ignore]
fn test_detect_anagram() {
    let inputs = ["enlists", "google", "inlets", "banana"];
    let outputs: Vec<&str> = vec!["inlets"];
    assert_eq!(anagram::anagrams_for("listen", &inputs), outputs);
}

#[test]
#[ignore]
fn test_multiple_anagrams() {
    let inputs = ["gallery", "ballerina", "regally", "clergy", "largely", "leading"];
    let outputs: Vec<&str> = vec!["gallery", "regally", "largely"];
    assert_eq!(anagram::anagrams_for("allergy", &inputs), outputs);
}

#[test]
#[ignore]
fn test_case_insensitive_anagrams() {
    let inputs = ["cashregister", "Carthorse", "radishes"];
    let outputs: Vec<&str> = vec!["Carthorse"];
    assert_eq!(anagram::anagrams_for("Orchestra", &inputs), outputs);
}

#[test]
#[ignore]
fn test_unicode_anagrams() {
    // These words don't make sense, they're just greek letters cobbled together.
    let inputs = ["ΒΓΑ", "ΒΓΔ", "γβα"];
    let outputs: Vec<&str> = vec!["ΒΓΑ", "γβα"];
    assert_eq!(anagram::anagrams_for("ΑΒΓ", &inputs), outputs);
}

#[test]
#[ignore]
fn test_misleading_unicode_anagrams() {
    // Despite what a human might think these words different letters, the input uses Greek A and B
    // while the list of potential anagrams uses Latin A and B.
    let inputs = ["ABΓ"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("ΑΒΓ", &inputs), outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_word_as_its_own_anagram() {
    let inputs = ["banana"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("banana", &inputs), outputs);
}

#[test]
fn test_does_not_detect_a_differently_cased_word_as_its_own_anagram() {
    let inputs = ["bAnana"];
    let outputs: Vec<&str> = vec![];
    assert_eq!(anagram::anagrams_for("banana", &inputs), outputs);
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::io::Write;
use std::io::stderr;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    write!(stderr(), "{}/{} Levels of errors will be printed", (if max > n { n } else { max }), n);
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        print_trace_maxdepth(idx - 1, e.cause().unwrap(), max);
        write!(stderr(), " -- caused:");
    }
    write!(stderr(), "Error {:>4} : {}", idx, e.description());
    e.cause()
}

/// Count errors in Error::cause() recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("Error {:>4} : {}", idx, e.description());
    if e.cause().is_some() {
        debug!(" -- caused by:");
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<commit_msg>trace: Add missing newline<commit_after>use std::error::Error;
use std::io::Write;
use std::io::stderr;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    write!(stderr(), "{}/{} Levels of errors will be printed\n", (if max > n { n } else { max }), n);
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        print_trace_maxdepth(idx - 1, e.cause().unwrap(), max);
        write!(stderr(), " -- caused:\n");
    }
    write!(stderr(), "Error {:>4} : {}", idx, e.description());
    e.cause()
}

/// Count errors in Error::cause() recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("Error {:>4} : {}", idx, e.description());
    if e.cause().is_some() {
        debug!(" -- caused by:");
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<|endoftext|>


<commit_before>#[repr(C)]
pub struct sockaddr_un {
    pub sun_family: ::sys::socket::sa_family_t,
    pub sun_path: [::char_t, ..108u],
}
<commit_msg>sys/un.h<commit_after>#[repr(C)]
pub struct sockaddr_un {
    pub sun_family: ::sys::socket::sa_family_t,
    pub sun_path: [::char_t, ..108u],
}

impl ::AsSlice for sockaddr_un { }
impl ::AsMutSlice for sockaddr_un { }

new!(sockaddr_un)
<|endoftext|>


<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction hinting to the processor that it is running in busy-wait
/// spin-loop ("spin lock").
///
/// For a discussion of different locking strategies and their trade-offs, see
/// [`core::sync::atomic::spin_loop_hint`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<commit_msg>Hint doc use convert::identity relative link<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction hinting to the processor that it is running in busy-wait
/// spin-loop ("spin lock").
///
/// For a discussion of different locking strategies and their trade-offs, see
/// [`core::sync::atomic::spin_loop_hint`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: ../convert/fn.identity.html
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "test", issue = "50297")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::ptr;
//
// #[lang = "panic_fmt"]
// #[cold]
// unsafe extern fn panic_fmt() -> ! {
//     boot_write(b"boot panic occurred!");
//     die();
// }

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               , data: u64
               , _pad: u16
               , pub ptr: GdtPointer
        //    , ptr: GdtPointer
           }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the descriptor table
                     pub limit: u16
                   , /// pointer to the region in memory
                     /// containing the descriptor table.
                     pub base: &'static Gdt
                   }

// TODO: this sucks please fix
#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , #[export_name = "gdt64.code"] #[no_mangle]
            code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          , data: (1 << 44) | (1 << 47) | (1 << 41)
          , _pad: 0
          , ptr:
                #[no_mangle]
                GdtPointer { limit: 23
                            , base: &GDT
                            }
          };

// #[no_mangle]
// static mut GDT_PTR: GdtPointer
//     = GdtPointer { limit: 15
//                  , base: &GDT
//                  };

#[inline(always)]
#[naked]
fn boot_write(s: &[u8]) {
	// use core::ptr;
    let mut offset = 0;
    unsafe {
        let vga_buf: *mut u16 = 0xb8000 as *mut u16;
    	for c in s {
    		ptr::write_volatile( vga_buf.offset(offset)
                               , 0x0200 + *c as u16);
    		offset += 1;
    	}

    }

}
macro_rules! write_char {
    ($c:expr) => {
        ptr::write_volatile(0xb8000 as *mut u16, 0x0200 + $c as u16)
    }
}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;    // static mut page_table: Table;
    fn arch_init(mboot: u64);
}

// #[naked]
// #[inline(always)]
// unsafe fn set_cs(cs: u16) {
//     asm!("ljmpl $0, $$fake_label
//           fake_label: \n\t"
//         :
//         : "i"(cs)
//         : "ax"
//         : "volatile"
//         );
// }

#[naked]
#[inline(always)]
pub unsafe fn create_page_tables() {
    // 3. if everything is okay, create the page tables and start long mode
    const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB

    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table[0] as *const _ as u64) | 3;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table[0] as *const _ as u64) | 3;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table[0] as *const _ as u64) | 3;

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (number, entry) in pd_table.iter_mut().enumerate() {
        // set each PD entry equal to the start address of the page (the page
        // number times the page's size)
        let addr = number as u64 * HUGE_PAGE_SIZE;
        // with the appropriate flags (present + writable + huge)
        // TODO: do we want to do this using bitflags, or is that too
        //       heavyweight for the boot module?
        //          - eliza, 1/23/2017
        *entry = addr | 0b10000011;
    }
}

#[naked]
#[inline(always)]
pub unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    asm!( "mov  eax, pml4_table
           mov   cr3, eax"
        :::: "intel");
    // boot_write(b"3.2");
    // enable PAE flag in cr4
    asm!( "mov   eax, cr4
           or    eax, 1 << 5
           mov   cr4, eax"
        :::: "intel");
    // boot_write(b"3.3");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.4");

    // enable paging in cr0
    asm!( "mov  eax, cr0
           or   eax, 1 << 31
           or   eax, 1 << 16
           mov  cr0, eax"
        :::: "intel");
    boot_write(b"3.5");
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    // 0. Move the stack pointer to the top of the stack.
    asm!( "mov esp, stack_top"
        :::: "intel");
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    let multiboot: usize;
    asm!("mov edi, $0" : "=r"(multiboot) ::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    boot_write(b"2");

    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    asm!(  "lgdt ($0)"
        :: "r"(&GDT.ptr)
        :  "memory"
        );
    boot_write(b"4");

    // 5. update selectors
    asm!("mov ax, 16" :::: "intel");
    boot_write(b"5.1");
    // stack selector
    asm!("mov ss, ax" :::: "intel");
    boot_write(b"5.2");
    // data selector
    asm!("mov ds, ax" :::: "intel");
    boot_write(b"5.3");
    // extra selector
    asm!("mov es, ax" :::: "intel");
    boot_write(b"5.4");

    // 6. jump to the 64-bit boot subroutine.
    // asm!("jmp $0:$1" :: "X"(&GDT.descriptors[1]), "X"(arch_init as unsafe extern "C" fn() -> !) :: "intel");
    // asm!("jmp $0:arch_init" :: "r"(&GDT.descriptors[1] as *const u64) :: "intel");
    // arch_init();
    // asm!(  "jmp $0:arch_init"
    //     :: "r"(&GDT.code as *const _ as usize -
    //            &GDT as *const _ as usize)
    //     :: "intel");
    // asm!( "ljmp $0:$1" :: "X"(8), "X"("arch_init"):: "volatile", "intel");

    // asm!("ljmpw $$0x0008, $$arch_init"
    //     :: // "i"(arch_init)
    //     :: "volatile");
    asm!(  "ljmpl $$8, $$arch_init"
        :: //"I"((&GDT.code as *const _ as usize) - &GDT as *const _ as usize)
        :: "volatile"
       );
    // asm!("jmp far 0x0008:arch_init" :::: "intel", "volatile");
    // set_cs(0x0008);
    // loop { boot_write(b"hey i set the code segment selector"); }
    // asm!("calll $$arch_init");
    // arch_init(multiboot as u64);
    // asm!("ljmpl $$0x0008, $$0x106000");
    // asm!("ljmpl *(arch_init)");
    // asm!("ljmpl [arch_init]" );

}
<commit_msg>[boot] slightly prettier code for setting long mode?<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::ptr;
//
// #[lang = "panic_fmt"]
// #[cold]
// unsafe extern fn panic_fmt() -> ! {
//     boot_write(b"boot panic occurred!");
//     die();
// }

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               , data: u64
               , _pad: u16
               , pub ptr: GdtPointer
        //    , ptr: GdtPointer
           }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the descriptor table
                     pub limit: u16
                   , /// pointer to the region in memory
                     /// containing the descriptor table.
                     pub base: &'static Gdt
                   }

// TODO: this sucks please fix
#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , #[export_name = "gdt64.code"] #[no_mangle]
            code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          , data: (1 << 44) | (1 << 47) | (1 << 41)
          , _pad: 0
          , ptr:
                #[no_mangle]
                GdtPointer { limit: 23
                            , base: &GDT
                            }
          };

// #[no_mangle]
// static mut GDT_PTR: GdtPointer
//     = GdtPointer { limit: 15
//                  , base: &GDT
//                  };

#[inline(always)]
#[naked]
fn boot_write(s: &[u8]) {
	// use core::ptr;
    let mut offset = 0;
    unsafe {
        let vga_buf: *mut u16 = 0xb8000 as *mut u16;
    	for c in s {
    		ptr::write_volatile( vga_buf.offset(offset)
                               , 0x0200 + *c as u16);
    		offset += 1;
    	}

    }

}
macro_rules! write_char {
    ($c:expr) => {
        ptr::write_volatile(0xb8000 as *mut u16, 0x0200 + $c as u16)
    }
}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;    // static mut page_table: Table;
    fn arch_init(mboot: u64);
    static mut stack_top: *mut u8;
}

// #[naked]
// #[inline(always)]
// unsafe fn set_cs(cs: u16) {
//     asm!("ljmpl $0, $$fake_label
//           fake_label: \n\t"
//         :
//         : "i"(cs)
//         : "ax"
//         : "volatile"
//         );
// }

#[naked]
#[inline(always)]
pub unsafe fn create_page_tables() {
    // 3. if everything is okay, create the page tables and start long mode
    const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB

    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table[0] as *const _ as u64) | 3;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table[0] as *const _ as u64) | 3;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table[0] as *const _ as u64) | 3;

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (number, entry) in pd_table.iter_mut().enumerate() {
        // set each PD entry equal to the start address of the page (the page
        // number times the page's size)
        let addr = number as u64 * HUGE_PAGE_SIZE;
        // with the appropriate flags (present + writable + huge)
        // TODO: do we want to do this using bitflags, or is that too
        //       heavyweight for the boot module?
        //          - eliza, 1/23/2017
        *entry = addr | 0b10000011;
    }
}

#[naked]
pub unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    asm!( "mov   cr3, $0" :: "r"(&pml4_table) :: "intel");
    boot_write(b"3.2");

    // enable PAE flag in cr4
    let mut cr4: usize;
    asm!("mov $0, cr4" : "=r"(cr4) ::: "intel");
    cr4 |= 1 << 5;
    asm!("mov cr4, $0" :: "r"(cr4) :: "intel");
    boot_write(b"3.3");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.4");

    // enable paging in cr0
    let mut cr0: usize;
    asm!( "mov $0, cr0" : "=r"(cr0) ::: "intel");
    cr0 |= 1 << 31;
    cr0 |= 1 << 16;
    asm!( "mov cr0, $0" :: "r"(cr0) ::: "intel");
    boot_write(b"3.5");
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    // boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    // let multiboot: usize;
    asm!("mov edi, edx"
         : //"=r"(multiboot)
         ::: "intel"
    );
    // boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    // boot_write(b"2");

    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    asm!(  "lgdt ($0)"
        :: "r"(&GDT.ptr)
        :  "memory"
        );
    // boot_write(b"4");

    // 5. update selectors
    asm!("mov ax, 16" :::: "intel");
    // boot_write(b"5.1");
    // stack selector
    asm!("mov ss, ax" :::: "intel");
    // boot_write(b"5.2");
    // data selector
    asm!("mov ds, ax" :::: "intel");
    // boot_write(b"5.3");
    // extra selector
    asm!("mov es, ax" :::: "intel");
    // boot_write(b"5.4");

    // 6. jump to the 64-bit boot subroutine.
    // asm!("jmp $0:$1" :: "X"(&GDT.descriptors[1]), "X"(arch_init as unsafe extern "C" fn() -> !) :: "intel");
    // asm!("jmp $0:arch_init" :: "r"(&GDT.descriptors[1] as *const u64) :: "intel");
    // arch_init();
    // asm!(  "jmp $0:arch_init"
    //     :: "r"(&GDT.code as *const _ as usize -
    //            &GDT as *const _ as usize)
    //     :: "intel");
    // asm!( "ljmp $0:$1" :: "X"(8), "X"("arch_init"):: "volatile", "intel");

    // asm!("ljmpw $$0x0008, $$arch_init"
    //     :: // "i"(arch_init)
    //     :: "volatile");
    asm!(  "ljmpl $$8, $$arch_init"
        :: //"I"((&GDT.code as *const _ as usize) - &GDT as *const _ as usize)
        :: "volatile"
       );
    // asm!("jmp far 0x0008:arch_init" :::: "intel", "volatile");
    // set_cs(0x0008);
    // loop { boot_write(b"hey i set the code segment selector"); }
    // asm!("calll $$arch_init");
    // arch_init(multiboot as u64);
    // asm!("ljmpl $$0x0008, $$0x106000");
    // asm!("ljmpl *(arch_init)");
    // asm!("ljmpl [arch_init]" );

}
<|endoftext|>


<commit_before>use pin_project::pin_project;
use rustls::{ClientConfig as TlsClientConfig,
             ServerConfig as TlsServerConfig};
use std::{pin::Pin,
          sync::Arc,
          task::{Context,
                 Poll}};
use tokio::{io::{self,
                 AsyncRead,
                 AsyncWrite},
            net::TcpStream};
use tokio_rustls::{webpki::DNSNameRef,
                   TlsAcceptor,
                   TlsConnector,
                   TlsStream};

/// A wrapper type that can either be a raw TCP stream or a TCP stream with TLS.
#[pin_project(project = TcpOrTlsStreamProj)]
#[allow(clippy::large_enum_variant)]
pub enum TcpOrTlsStream {
    TcpStream(#[pin] TcpStream),
    TlsStream(#[pin] TlsStream<TcpStream>),
}

impl TcpOrTlsStream {
    /// Create a new `TcpStream`
    pub fn new(stream: TcpStream) -> Self { Self::TcpStream(stream) }

    /// Create a new `TlsStream` using server configuration
    pub async fn new_tls_server(stream: TcpStream,
                                tls_config: Arc<TlsServerConfig>)
                                -> io::Result<Self> {
        let tcp_stream = Self::new(stream);
        tcp_stream.upgrade_to_tls_server(tls_config).await
    }

    /// Create a new `TlsStream` using client configuration
    pub async fn new_tls_client(stream: TcpStream,
                                tls_config: Arc<TlsClientConfig>,
                                domain: &str)
                                -> io::Result<Self> {
        let tcp_stream = Self::new(stream);
        tcp_stream.upgrade_to_tls_client(tls_config, domain).await
    }

    /// Upgrade a `TcpStream` into a `TlsStream` using server configuration
    pub async fn upgrade_to_tls_server(self, tls_config: Arc<TlsServerConfig>) -> io::Result<Self> {
        Ok(match self {
            Self::TcpStream(stream) => {
                let tls_connector = TlsAcceptor::from(tls_config);
                let tls_stream = tls_connector.accept(stream)
                                              .into_failable()
                                              .await
                                              .map_err(|e| e.0)?;
                Self::TlsStream(TlsStream::Server(tls_stream))
            }
            Self::TlsStream(stream) => Self::TlsStream(stream),
        })
    }

    /// Upgrade a `TcpStream` to a `TlsStream` using client configuration
    pub async fn upgrade_to_tls_client(self,
                                       tls_config: Arc<TlsClientConfig>,
                                       domain: &str)
                                       -> io::Result<Self> {
        Ok(match self {
            Self::TcpStream(stream) => {
                let tls_connector = TlsConnector::from(tls_config);
                let domain = DNSNameRef::try_from_ascii_str(domain).map_err(|_| {
                                 io::Error::new(io::ErrorKind::InvalidInput,
                                                format!("invalid DNS name '{}'", domain))
                             })?;
                let tls_stream = tls_connector.connect(domain, stream)
                                              .into_failable()
                                              .await
                                              .map_err(|e| e.0)?;
                Self::TlsStream(TlsStream::Client(tls_stream))
            }
            Self::TlsStream(stream) => Self::TlsStream(stream),
        })
    }
}

impl AsyncRead for TcpOrTlsStream {
    fn poll_read(self: Pin<&mut Self>,
                 cx: &mut Context,
                 buf: &mut [u8])
                 -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_read(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for TcpOrTlsStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_write(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_flush(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_shutdown(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_shutdown(cx),
        }
    }
}
<commit_msg>[Refactor] PR feedback<commit_after>use pin_project::pin_project;
use rustls::{ClientConfig as TlsClientConfig,
             ServerConfig as TlsServerConfig};
use std::{pin::Pin,
          sync::Arc,
          task::{Context,
                 Poll}};
use tokio::{io::{self,
                 AsyncRead,
                 AsyncWrite},
            net::TcpStream};
use tokio_rustls::{webpki::DNSNameRef,
                   TlsAcceptor,
                   TlsConnector,
                   TlsStream};

/// A wrapper type that can either be a raw TCP stream or a TCP stream with TLS.
#[pin_project(project = TcpOrTlsStreamProj)]
#[allow(clippy::large_enum_variant)]
pub enum TcpOrTlsStream {
    TcpStream(#[pin] TcpStream),
    TlsStream(#[pin] TlsStream<TcpStream>),
}

impl TcpOrTlsStream {
    /// Create a new `TcpStream`
    pub fn new(stream: TcpStream) -> Self { Self::TcpStream(stream) }

    /// Create a new `TlsStream` using server configuration
    pub async fn new_tls_server(stream: TcpStream,
                                tls_config: Arc<TlsServerConfig>)
                                -> io::Result<Self> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_server(tls_config).await
    }

    /// Create a new `TlsStream` using client configuration
    pub async fn new_tls_client(stream: TcpStream,
                                tls_config: Arc<TlsClientConfig>,
                                domain: &str)
                                -> io::Result<Self> {
        let tcp_stream = Self::new(stream);
        tcp_stream.maybe_upgrade_to_tls_client(tls_config, domain)
                  .await
    }

    /// Upgrade a `TcpStream` into a `TlsStream` using server configuration
    async fn maybe_upgrade_to_tls_server(self,
                                         tls_config: Arc<TlsServerConfig>)
                                         -> io::Result<Self> {
        let tls_server_stream = match self {
            Self::TcpStream(stream) => {
                let tls_acceptor = TlsAcceptor::from(tls_config);
                let tls_stream = tls_acceptor.accept(stream)
                                             .into_failable()
                                             .await
                                             .map_err(|e| e.0)?;
                Self::TlsStream(TlsStream::Server(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_server_stream)
    }

    /// Upgrade a `TcpStream` to a `TlsStream` using client configuration
    async fn maybe_upgrade_to_tls_client(self,
                                         tls_config: Arc<TlsClientConfig>,
                                         domain: &str)
                                         -> io::Result<Self> {
        let tls_client_stream = match self {
            Self::TcpStream(stream) => {
                let tls_connector = TlsConnector::from(tls_config);
                let domain = DNSNameRef::try_from_ascii_str(domain).map_err(|_| {
                                 io::Error::new(io::ErrorKind::InvalidInput,
                                                format!("invalid DNS name '{}'", domain))
                             })?;
                let tls_stream = tls_connector.connect(domain, stream)
                                              .into_failable()
                                              .await
                                              .map_err(|e| e.0)?;
                Self::TlsStream(TlsStream::Client(tls_stream))
            }
            stream @ Self::TlsStream(_) => stream,
        };
        Ok(tls_client_stream)
    }
}

impl AsyncRead for TcpOrTlsStream {
    fn poll_read(self: Pin<&mut Self>,
                 cx: &mut Context,
                 buf: &mut [u8])
                 -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_read(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for TcpOrTlsStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_write(cx, buf),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_flush(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        match self.project() {
            TcpOrTlsStreamProj::TcpStream(stream) => stream.poll_shutdown(cx),
            TcpOrTlsStreamProj::TlsStream(stream) => stream.poll_shutdown(cx),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;

extern crate gstreamer as gst;
use gst::prelude::*;

use std::sync::{Arc, Mutex};

extern crate gstthreadshare;

fn init() {
    use std::sync::{Once, ONCE_INIT};
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        gst::init().unwrap();
        gstthreadshare::plugin_register_static();
    });
}

#[test]
fn test_push() {
    init();

    let pipeline = gst::Pipeline::new(None);
    let appsrc = gst::ElementFactory::make("ts-appsrc", None).unwrap();
    let appsink = gst::ElementFactory::make("appsink", None).unwrap();
    pipeline.add_many(&[&appsrc, &appsink]).unwrap();
    appsrc.link(&appsink).unwrap();

    let caps = gst::Caps::new_simple("foo/bar", &[]);
    appsrc.set_property("caps", &caps).unwrap();
    appsrc.set_property("do-timestamp", &true).unwrap();

    appsink.set_property("emit-signals", &true).unwrap();

    let samples = Arc::new(Mutex::new(Vec::new()));

    let samples_clone = samples.clone();
    appsink
        .connect("new-sample", true, move |args| {
            let appsink = args[0].get::<gst::Element>().unwrap();

            let sample = appsink
                .emit("pull-sample", &[])
                .unwrap()
                .unwrap()
                .get::<gst::Sample>()
                .unwrap();

            samples_clone.lock().unwrap().push(sample);

            Some(gst::FlowReturn::Ok.to_value())
        })
        .unwrap();

    pipeline
        .set_state(gst::State::Playing)
        .into_result()
        .unwrap();

    for _ in 0..3 {
        assert!(appsrc
            .emit("push-buffer", &[&gst::Buffer::new()])
            .unwrap()
            .unwrap()
            .get::<bool>()
            .unwrap());
    }

    assert!(appsrc
        .emit("end-of-stream", &[])
        .unwrap()
        .unwrap()
        .get::<bool>()
        .unwrap());

    let mut eos = false;
    let bus = pipeline.get_bus().unwrap();
    while let Some(msg) = bus.timed_pop(5 * gst::SECOND) {
        use gst::MessageView;
        match msg.view() {
            MessageView::Eos(..) => {
                eos = true;
                break;
            }
            MessageView::Error(..) => unreachable!(),
            _ => (),
        }
    }

    assert!(eos);
    let samples = samples.lock().unwrap();
    assert_eq!(samples.len(), 3);

    for sample in samples.iter() {
        assert!(sample.get_buffer().is_some());
        assert_eq!(Some(&caps), sample.get_caps().as_ref());
    }

    pipeline.set_state(gst::State::Null).into_result().unwrap();
}
<commit_msg>ts-appsrc: Rewrite test around Harness<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;

extern crate gstreamer as gst;
extern crate gstreamer_check as gst_check;

extern crate gstthreadshare;

fn init() {
    use std::sync::{Once, ONCE_INIT};
    static INIT: Once = ONCE_INIT;

    INIT.call_once(|| {
        gst::init().unwrap();
        gstthreadshare::plugin_register_static();
    });
}

#[test]
fn test_push() {
    init();

    let mut h = gst_check::Harness::new("ts-appsrc");

    let caps = gst::Caps::new_simple("foo/bar", &[]);
    {
        let appsrc = h.get_element().unwrap();
        appsrc.set_property("caps", &caps).unwrap();
        appsrc.set_property("do-timestamp", &true).unwrap();
        appsrc.set_property("context", &"test-push").unwrap();
    }

    h.play();

    {
        let appsrc = h.get_element().unwrap();
        for _ in 0..3 {
            assert!(appsrc
                .emit("push-buffer", &[&gst::Buffer::new()])
                .unwrap()
                .unwrap()
                .get::<bool>()
                .unwrap());
        }

        assert!(appsrc
            .emit("end-of-stream", &[])
            .unwrap()
            .unwrap()
            .get::<bool>()
            .unwrap());
    }

    for _ in 0..3 {
        let _buffer = h.pull().unwrap();
    }

    let mut n_events = 0;
    loop {
        use gst::EventView;

        let event = h.pull_event().unwrap();
        match event.view() {
            EventView::StreamStart(..) => {
                assert_eq!(n_events, 0);
            }
            EventView::Caps(ev) => {
                assert_eq!(n_events, 1);
                let event_caps = ev.get_caps();
                assert_eq!(caps.as_ref(), event_caps);
            }
            EventView::Segment(..) => {
                assert_eq!(n_events, 2);
            }
            EventView::Eos(..) => {
                break;
            }
            _ => (),
        }
        n_events += 1;
    }
    assert!(n_events >= 3);
}
<|endoftext|>


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

use std::cell::{Cell, RefCell};
use std::slice;
use std::u64;

use private::units::*;
use message;
use message::{Allocator, ReaderSegments};
use {Error, OutputSegments, Result, Word};

pub type SegmentId = u32;

pub struct ReadLimiter {
    pub limit: Cell<u64>,
}

impl ReadLimiter {
    pub fn new(limit: u64) -> ReadLimiter {
        ReadLimiter { limit: Cell::new(limit) }
    }

    #[inline]
    pub fn can_read(&self, amount: u64) -> Result<()> {
        let current = self.limit.get();
        if amount > current {
            Err(Error::failed(format!("read limit exceeded")))
        } else {
            self.limit.set(current - amount);
            Ok(())
        }
    }
}

pub trait ReaderArena {
    fn get_segment(&self, id: u32) -> Result<(*const Word, u32)>;
    fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>;
    fn contains_interval(&self, segment_id: u32, start: *const Word, size: usize) -> Result<()>;
    fn amplified_read(&self, virtual_amount: u64) -> Result<()>;

    // TODO(version 0.9): Consider putting extract_cap(), inject_cap(), drop_cap() here
    //   and on message::Reader. Then we could get rid of Imbue and ImbueMut, and
    //   layout::StructReader, layout::ListReader, etc. could drop their `cap_table` fields.
}

pub struct ReaderArenaImpl<S> {
    segments: S,
    read_limiter: ReadLimiter,
}

impl <S> ReaderArenaImpl <S> where S: ReaderSegments {
    pub fn new(segments: S,
               options: message::ReaderOptions)
               -> Self
    {
        let limiter = ReadLimiter::new(options.traversal_limit_in_words);
        ReaderArenaImpl {
            segments: segments,
            read_limiter: limiter,
        }
    }

    pub fn into_segments(self) -> S {
        self.segments
    }
}

impl <S> ReaderArena for ReaderArenaImpl<S> where S: ReaderSegments {
    fn get_segment<'a>(&'a self, id: u32) -> Result<(*const Word, u32)> {
        match self.segments.get_segment(id) {
            Some(seg) => Ok((seg.as_ptr(), seg.len() as u32)),
            None => Err(Error::failed(format!("Invalid segment id: {}", id))),
        }
    }

    fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        let (segment_start, segment_len) = try!(self.get_segment(segment_id));
        let this_start: usize = segment_start as usize;
        let this_size: usize = segment_len as usize * BYTES_PER_WORD;
        let offset: i64 = offset_in_words as i64 * BYTES_PER_WORD as i64;
        let start_idx = start as usize;
        if start_idx < this_start || ((start_idx - this_start) as i64 + offset) as usize > this_size {
            Err(Error::failed(format!("message contained out-of-bounds pointer")))
        } else {
            unsafe { Ok(start.offset(offset_in_words as isize)) }
        }
    }

    fn contains_interval(&self, id: u32, start: *const Word, size_in_words: usize) -> Result<()> {
        let (segment_start, segment_len) = try!(self.get_segment(id));
        let this_start: usize = segment_start as usize;
        let this_size: usize = segment_len as usize * BYTES_PER_WORD;
        let start = start as usize;
        let size = size_in_words * BYTES_PER_WORD;

        if !(start >= this_start && start - this_start + size <= this_size) {
            Err(Error::failed(format!("message contained out-of-bounds pointer")))
        } else {
            self.read_limiter.can_read(size_in_words as u64)
        }
    }

    fn amplified_read(&self, virtual_amount: u64) -> Result<()> {
        self.read_limiter.can_read(virtual_amount)
    }
}

pub trait BuilderArena: ReaderArena {
    // These methods all take an immutable &self because otherwise a StructBuilder<'a>
    // would need a `&'a mut BuilderArena` and `StructBuilder::borrow()` would
    // have lifetime issues. (If `'a: 'b`, then a `&'a (BuilderArena + 'a)` can be
    // converted to a `&'b (BuilderArena + 'b)`, but a `&'a mut (BuilderArena + 'a)`
    // *cannot* be converted to a `&'b (BuilderArena + 'b)`. See some discussion here:
    // https://botbot.me/mozilla/rust/2017-01-31/?msg=80228117&page=19 .)
    fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32>;
    fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32);
    fn get_segment_mut(&self, id: u32) -> (*mut Word, u32);
    fn as_reader<'a>(&'a self) -> &'a ReaderArena;
}

pub struct BuilderArenaImplInner<A> where A: Allocator {
    allocator: A,

    // TODO(perf): Try using smallvec to avoid heap allocations in the single-segment case?
    segments: Vec<(*mut Word, u32)>,
    allocated: Vec<u32>, // number of words allocated for each segment.
}

pub struct BuilderArenaImpl<A> where A: Allocator {
    inner: RefCell<BuilderArenaImplInner<A>>
}

impl <A> BuilderArenaImpl<A> where A: Allocator {
    pub fn new(allocator: A) -> Self {
        BuilderArenaImpl {
            inner: RefCell::new(BuilderArenaImplInner {
                allocator: allocator,
                segments: Vec::new(),
                allocated: Vec::new(),
            }),
        }
    }

    pub fn allocate_segment(&self, minimum_size: u32) -> Result<()> {
        self.inner.borrow_mut().allocate_segment(minimum_size)
    }

    pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> {
        let reff = self.inner.borrow();
        if reff.allocated.len() == 1 {
            let seg = reff.segments[0];

            // The user must mutably borrow the `message::Builder` to be able to modify segment memory.
            // No such borrow will be possible while `self` is still immutably borrowed from this method,
            // so returning this slice is safe.
            let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[0] as usize) };
            OutputSegments::SingleSegment([slice])
        } else {
            let mut v = Vec::with_capacity(reff.allocated.len());
            for idx in 0..reff.allocated.len() {
                let seg = reff.segments[idx];

                // See safety argument in above branch.
                let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[idx] as usize) };
                v.push(slice);
            }
            OutputSegments::MultiSegment(v)
        }
    }

    pub fn len(&self) -> usize {
        self.inner.borrow().allocated.len()
    }
}

impl <A> ReaderArena for BuilderArenaImpl<A> where A: Allocator {
    fn get_segment(&self, id: u32) -> Result<(*const Word, u32)> {
        let borrow = self.inner.borrow();
        let seg = borrow.segments[id as usize];
        Ok((seg.0 as *const _, seg.1))
    }

    fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        unsafe { Ok(start.offset(offset_in_words as isize)) }
    }

    fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> {
        Ok(())
    }

    fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
        Ok(())
    }
}

impl <A> BuilderArenaImplInner<A> where A: Allocator {
    fn allocate_segment(&mut self, minimum_size: WordCount32) -> Result<()> {
        let seg = self.allocator.allocate_segment(minimum_size);
        self.segments.push(seg);
        self.allocated.push(0);
        Ok(())
    }

    fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32> {
        if amount > self.get_segment_mut(segment_id).1 as u32 - self.allocated[segment_id as usize] {
            None
        } else {
            let result = self.allocated[segment_id as usize];
            self.allocated[segment_id as usize] += amount;
            Some(result)
        }
    }

    fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32) {
        // first try the existing segments, then try allocating a new segment.
        let allocated_len = self.allocated.len() as u32;
        for segment_id in 0.. allocated_len {
            match self.allocate(segment_id, amount) {
                Some(idx) => return (segment_id, idx),
                None => (),
            }
        }

        // Need to allocate a new segment.

        self.allocate_segment(amount).expect("allocate new segment");
        (allocated_len,
         self.allocate(allocated_len, amount).expect("use freshly-allocated segment"))
    }

    fn get_segment_mut(&mut self, id: u32) -> (*mut Word, u32) {
        self.segments[id as usize]
    }

}

impl <A> BuilderArena for BuilderArenaImpl<A> where A: Allocator {
    fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32> {
        self.inner.borrow_mut().allocate(segment_id, amount)
    }

    fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32) {
        self.inner.borrow_mut().allocate_anywhere(amount)
    }

    fn get_segment_mut(&self, id: u32) -> (*mut Word, u32) {
        self.inner.borrow_mut().get_segment_mut(id)
    }

    fn as_reader<'a>(&'a self) -> &'a ReaderArena {
        self
    }
}

impl <A> Drop for BuilderArenaImplInner<A> where A: Allocator {
    fn drop(&mut self) {
        if self.allocated.len() > 0 {
            self.allocator.pre_drop(self.allocated[0]);
        }
    }
}

pub struct NullArena;

impl ReaderArena for NullArena {
    fn get_segment(&self, _id: u32) -> Result<(*const Word, u32)> {
        Err(Error::failed(format!("tried to read from null arena")))
    }

    fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        unsafe { Ok(start.offset(offset_in_words as isize)) }
    }

    fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> {
        Ok(())
    }

    fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
        Ok(())
    }
}

impl BuilderArena for NullArena {
    fn allocate(&self, _segment_id: u32, _amount: WordCount32) -> Option<u32> {
        None
    }

    fn allocate_anywhere(&self, _amount: u32) -> (SegmentId, u32) {
        panic!("tried to allocate from a null arena")
    }

    fn get_segment_mut(&self, _id: u32) -> (*mut Word, u32) {
        (::std::ptr::null_mut(), 0)
    }

    fn as_reader<'a>(&'a self) -> &'a ReaderArena {
        self
    }
}

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

use std::cell::{Cell, RefCell};
use std::slice;
use std::u64;

use private::units::*;
use message;
use message::{Allocator, ReaderSegments};
use {Error, OutputSegments, Result, Word};

pub type SegmentId = u32;

pub struct ReadLimiter {
    pub limit: Cell<u64>,
}

impl ReadLimiter {
    pub fn new(limit: u64) -> ReadLimiter {
        ReadLimiter { limit: Cell::new(limit) }
    }

    #[inline]
    pub fn can_read(&self, amount: u64) -> Result<()> {
        let current = self.limit.get();
        if amount > current {
            Err(Error::failed(format!("read limit exceeded")))
        } else {
            self.limit.set(current - amount);
            Ok(())
        }
    }
}

pub trait ReaderArena {
    fn get_segment(&self, id: u32) -> Result<(*const Word, u32)>;
    fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word>;
    fn contains_interval(&self, segment_id: u32, start: *const Word, size: usize) -> Result<()>;
    fn amplified_read(&self, virtual_amount: u64) -> Result<()>;

    // TODO(version 0.9): Consider putting extract_cap(), inject_cap(), drop_cap() here
    //   and on message::Reader. Then we could get rid of Imbue and ImbueMut, and
    //   layout::StructReader, layout::ListReader, etc. could drop their `cap_table` fields.
}

pub struct ReaderArenaImpl<S> {
    segments: S,
    read_limiter: ReadLimiter,
}

impl <S> ReaderArenaImpl <S> where S: ReaderSegments {
    pub fn new(segments: S,
               options: message::ReaderOptions)
               -> Self
    {
        let limiter = ReadLimiter::new(options.traversal_limit_in_words);
        ReaderArenaImpl {
            segments: segments,
            read_limiter: limiter,
        }
    }

    pub fn into_segments(self) -> S {
        self.segments
    }
}

impl <S> ReaderArena for ReaderArenaImpl<S> where S: ReaderSegments {
    fn get_segment<'a>(&'a self, id: u32) -> Result<(*const Word, u32)> {
        match self.segments.get_segment(id) {
            Some(seg) => Ok((seg.as_ptr(), seg.len() as u32)),
            None => Err(Error::failed(format!("Invalid segment id: {}", id))),
        }
    }

    fn check_offset(&self, segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        let (segment_start, segment_len) = try!(self.get_segment(segment_id));
        let this_start: usize = segment_start as usize;
        let this_size: usize = segment_len as usize * BYTES_PER_WORD;
        let offset: i64 = offset_in_words as i64 * BYTES_PER_WORD as i64;
        let start_idx = start as usize;
        if start_idx < this_start || ((start_idx - this_start) as i64 + offset) as usize > this_size {
            Err(Error::failed(format!("message contained out-of-bounds pointer")))
        } else {
            unsafe { Ok(start.offset(offset_in_words as isize)) }
        }
    }

    fn contains_interval(&self, id: u32, start: *const Word, size_in_words: usize) -> Result<()> {
        let (segment_start, segment_len) = try!(self.get_segment(id));
        let this_start: usize = segment_start as usize;
        let this_size: usize = segment_len as usize * BYTES_PER_WORD;
        let start = start as usize;
        let size = size_in_words * BYTES_PER_WORD;

        if !(start >= this_start && start - this_start + size <= this_size) {
            Err(Error::failed(format!("message contained out-of-bounds pointer")))
        } else {
            self.read_limiter.can_read(size_in_words as u64)
        }
    }

    fn amplified_read(&self, virtual_amount: u64) -> Result<()> {
        self.read_limiter.can_read(virtual_amount)
    }
}

pub trait BuilderArena: ReaderArena {
    // These methods all take an immutable &self because otherwise a StructBuilder<'a>
    // would need a `&'a mut BuilderArena` and `StructBuilder::borrow()` would
    // have lifetime issues. (If `'a: 'b`, then a `&'a (BuilderArena + 'a)` can be
    // converted to a `&'b (BuilderArena + 'b)`, but a `&'a mut (BuilderArena + 'a)`
    // *cannot* be converted to a `&'b mut (BuilderArena + 'b)`. See some discussion here:
    // https://botbot.me/mozilla/rust/2017-01-31/?msg=80228117&page=19 .)
    fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32>;
    fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32);
    fn get_segment_mut(&self, id: u32) -> (*mut Word, u32);
    fn as_reader<'a>(&'a self) -> &'a ReaderArena;
}

pub struct BuilderArenaImplInner<A> where A: Allocator {
    allocator: A,

    // TODO(perf): Try using smallvec to avoid heap allocations in the single-segment case?
    segments: Vec<(*mut Word, u32)>,
    allocated: Vec<u32>, // number of words allocated for each segment.
}

pub struct BuilderArenaImpl<A> where A: Allocator {
    inner: RefCell<BuilderArenaImplInner<A>>
}

impl <A> BuilderArenaImpl<A> where A: Allocator {
    pub fn new(allocator: A) -> Self {
        BuilderArenaImpl {
            inner: RefCell::new(BuilderArenaImplInner {
                allocator: allocator,
                segments: Vec::new(),
                allocated: Vec::new(),
            }),
        }
    }

    pub fn allocate_segment(&self, minimum_size: u32) -> Result<()> {
        self.inner.borrow_mut().allocate_segment(minimum_size)
    }

    pub fn get_segments_for_output<'a>(&'a self) -> OutputSegments<'a> {
        let reff = self.inner.borrow();
        if reff.allocated.len() == 1 {
            let seg = reff.segments[0];

            // The user must mutably borrow the `message::Builder` to be able to modify segment memory.
            // No such borrow will be possible while `self` is still immutably borrowed from this method,
            // so returning this slice is safe.
            let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[0] as usize) };
            OutputSegments::SingleSegment([slice])
        } else {
            let mut v = Vec::with_capacity(reff.allocated.len());
            for idx in 0..reff.allocated.len() {
                let seg = reff.segments[idx];

                // See safety argument in above branch.
                let slice = unsafe { slice::from_raw_parts(seg.0 as *const _, reff.allocated[idx] as usize) };
                v.push(slice);
            }
            OutputSegments::MultiSegment(v)
        }
    }

    pub fn len(&self) -> usize {
        self.inner.borrow().allocated.len()
    }
}

impl <A> ReaderArena for BuilderArenaImpl<A> where A: Allocator {
    fn get_segment(&self, id: u32) -> Result<(*const Word, u32)> {
        let borrow = self.inner.borrow();
        let seg = borrow.segments[id as usize];
        Ok((seg.0 as *const _, seg.1))
    }

    fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        unsafe { Ok(start.offset(offset_in_words as isize)) }
    }

    fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> {
        Ok(())
    }

    fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
        Ok(())
    }
}

impl <A> BuilderArenaImplInner<A> where A: Allocator {
    fn allocate_segment(&mut self, minimum_size: WordCount32) -> Result<()> {
        let seg = self.allocator.allocate_segment(minimum_size);
        self.segments.push(seg);
        self.allocated.push(0);
        Ok(())
    }

    fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32> {
        if amount > self.get_segment_mut(segment_id).1 as u32 - self.allocated[segment_id as usize] {
            None
        } else {
            let result = self.allocated[segment_id as usize];
            self.allocated[segment_id as usize] += amount;
            Some(result)
        }
    }

    fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32) {
        // first try the existing segments, then try allocating a new segment.
        let allocated_len = self.allocated.len() as u32;
        for segment_id in 0.. allocated_len {
            match self.allocate(segment_id, amount) {
                Some(idx) => return (segment_id, idx),
                None => (),
            }
        }

        // Need to allocate a new segment.

        self.allocate_segment(amount).expect("allocate new segment");
        (allocated_len,
         self.allocate(allocated_len, amount).expect("use freshly-allocated segment"))
    }

    fn get_segment_mut(&mut self, id: u32) -> (*mut Word, u32) {
        self.segments[id as usize]
    }

}

impl <A> BuilderArena for BuilderArenaImpl<A> where A: Allocator {
    fn allocate(&self, segment_id: u32, amount: WordCount32) -> Option<u32> {
        self.inner.borrow_mut().allocate(segment_id, amount)
    }

    fn allocate_anywhere(&self, amount: u32) -> (SegmentId, u32) {
        self.inner.borrow_mut().allocate_anywhere(amount)
    }

    fn get_segment_mut(&self, id: u32) -> (*mut Word, u32) {
        self.inner.borrow_mut().get_segment_mut(id)
    }

    fn as_reader<'a>(&'a self) -> &'a ReaderArena {
        self
    }
}

impl <A> Drop for BuilderArenaImplInner<A> where A: Allocator {
    fn drop(&mut self) {
        if self.allocated.len() > 0 {
            self.allocator.pre_drop(self.allocated[0]);
        }
    }
}

pub struct NullArena;

impl ReaderArena for NullArena {
    fn get_segment(&self, _id: u32) -> Result<(*const Word, u32)> {
        Err(Error::failed(format!("tried to read from null arena")))
    }

    fn check_offset(&self, _segment_id: u32, start: *const Word, offset_in_words: i32) -> Result<*const Word> {
        unsafe { Ok(start.offset(offset_in_words as isize)) }
    }

    fn contains_interval(&self, _id: u32, _start: *const Word, _size: usize) -> Result<()> {
        Ok(())
    }

    fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
        Ok(())
    }
}

impl BuilderArena for NullArena {
    fn allocate(&self, _segment_id: u32, _amount: WordCount32) -> Option<u32> {
        None
    }

    fn allocate_anywhere(&self, _amount: u32) -> (SegmentId, u32) {
        panic!("tried to allocate from a null arena")
    }

    fn get_segment_mut(&self, _id: u32) -> (*mut Word, u32) {
        (::std::ptr::null_mut(), 0)
    }

    fn as_reader<'a>(&'a self) -> &'a ReaderArena {
        self
    }
}

<|endoftext|>


<commit_before>pub mod array;

#[macro_use]
pub mod biteq;

pub trait DefaultStrategy {
    type Strategy: proptest::strategy::Strategy<Value = Self>;
    fn default_strategy() -> Self::Strategy;
}

macro_rules! impl_num {
    { $type:tt } => {
        impl DefaultStrategy for $type {
            type Strategy = proptest::num::$type::Any;
            fn default_strategy() -> Self::Strategy {
                proptest::num::$type::ANY
            }
        }
    }
}

impl_num! { i8 }
impl_num! { i16 }
impl_num! { i32 }
impl_num! { i64 }
impl_num! { i128 }
impl_num! { isize }
impl_num! { u8 }
impl_num! { u16 }
impl_num! { u32 }
impl_num! { u64 }
impl_num! { u128 }
impl_num! { usize }
impl_num! { f32 }
impl_num! { f64 }

impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy for [T; LANES] {
    type Strategy = crate::array::UniformArrayStrategy<T::Strategy, Self>;
    fn default_strategy() -> Self::Strategy {
        Self::Strategy::new(T::default_strategy())
    }
}

pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
    f: impl Fn(A) -> proptest::test_runner::TestCaseResult,
) {
    let mut runner = proptest::test_runner::TestRunner::default();
    runner.run(&A::default_strategy(), f).unwrap();
}

pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
    f: impl Fn(A, B) -> proptest::test_runner::TestCaseResult,
) {
    let mut runner = proptest::test_runner::TestRunner::default();
    runner
        .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
            f(a, b)
        })
        .unwrap();
}

pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>(
    fv: impl Fn(Vector) -> VectorResult,
    fs: impl Fn(Scalar) -> ScalarResult,
    check: impl Fn([Scalar; LANES]) -> bool,
) where
    Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_1(|x: [Scalar; LANES]| {
        proptest::prop_assume!(check(x));
        let result_1: [ScalarResult; LANES] = fv(x.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in x.iter().zip(result.iter_mut()) {
                *o = fs(*i);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector1,
    Vector2,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Vector1, Vector2) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
    Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: [Scalar1; LANES], y: [Scalar2; LANES]| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for ((i1, i2), o) in x.iter().zip(y.iter()).zip(result.iter_mut()) {
                *o = fs(*i1, *i2);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_scalar_rhs_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Vector, Scalar2) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn([Scalar1; LANES], Scalar2) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: [Scalar1; LANES], y: Scalar2| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x.into(), y).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in x.iter().zip(result.iter_mut()) {
                *o = fs(*i, y);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_scalar_lhs_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Scalar1, Vector) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn(Scalar1, [Scalar2; LANES]) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: Scalar1, y: [Scalar2; LANES]| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x, y.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in y.iter().zip(result.iter_mut()) {
                *o = fs(x, *i);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

#[macro_export]
#[doc(hidden)]
macro_rules! test_lanes_impl {
    {
        fn $test:ident<const $lanes:ident: usize>() $body:tt

        $($name:ident => $lanes_lit:literal,)*
    } => {
        mod $test {
            use super::*;
            $(
                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn $name() {
                    const $lanes: usize = $lanes_lit;
                    $body
                }
            )*
        }
    }
}

#[macro_export]
macro_rules! test_lanes {
    {
        $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
    } => {
        $(
        $crate::test_lanes_impl! {
            fn $test<const $lanes: usize>() $body

            lanes_1 => 1,
            lanes_2 => 2,
            lanes_4 => 4,
            lanes_8 => 8,
            lanes_16 => 16,
            lanes_32 => 32,
            lanes_64 => 64,
        }
        )*
    }
}
<commit_msg>Simplify test creation<commit_after>pub mod array;

#[macro_use]
pub mod biteq;

pub trait DefaultStrategy {
    type Strategy: proptest::strategy::Strategy<Value = Self>;
    fn default_strategy() -> Self::Strategy;
}

macro_rules! impl_num {
    { $type:tt } => {
        impl DefaultStrategy for $type {
            type Strategy = proptest::num::$type::Any;
            fn default_strategy() -> Self::Strategy {
                proptest::num::$type::ANY
            }
        }
    }
}

impl_num! { i8 }
impl_num! { i16 }
impl_num! { i32 }
impl_num! { i64 }
impl_num! { i128 }
impl_num! { isize }
impl_num! { u8 }
impl_num! { u16 }
impl_num! { u32 }
impl_num! { u64 }
impl_num! { u128 }
impl_num! { usize }
impl_num! { f32 }
impl_num! { f64 }

impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy for [T; LANES] {
    type Strategy = crate::array::UniformArrayStrategy<T::Strategy, Self>;
    fn default_strategy() -> Self::Strategy {
        Self::Strategy::new(T::default_strategy())
    }
}

pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
    f: impl Fn(A) -> proptest::test_runner::TestCaseResult,
) {
    let mut runner = proptest::test_runner::TestRunner::default();
    runner.run(&A::default_strategy(), f).unwrap();
}

pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
    f: impl Fn(A, B) -> proptest::test_runner::TestCaseResult,
) {
    let mut runner = proptest::test_runner::TestRunner::default();
    runner
        .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
            f(a, b)
        })
        .unwrap();
}

pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>(
    fv: impl Fn(Vector) -> VectorResult,
    fs: impl Fn(Scalar) -> ScalarResult,
    check: impl Fn([Scalar; LANES]) -> bool,
) where
    Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_1(|x: [Scalar; LANES]| {
        proptest::prop_assume!(check(x));
        let result_1: [ScalarResult; LANES] = fv(x.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in x.iter().zip(result.iter_mut()) {
                *o = fs(*i);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector1,
    Vector2,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Vector1, Vector2) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
    Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: [Scalar1; LANES], y: [Scalar2; LANES]| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for ((i1, i2), o) in x.iter().zip(y.iter()).zip(result.iter_mut()) {
                *o = fs(*i1, *i2);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_scalar_rhs_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Vector, Scalar2) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn([Scalar1; LANES], Scalar2) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: [Scalar1; LANES], y: Scalar2| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x.into(), y).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in x.iter().zip(result.iter_mut()) {
                *o = fs(*i, y);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

pub fn test_binary_scalar_lhs_elementwise<
    Scalar1,
    Scalar2,
    ScalarResult,
    Vector,
    VectorResult,
    const LANES: usize,
>(
    fv: impl Fn(Scalar1, Vector) -> VectorResult,
    fs: impl Fn(Scalar1, Scalar2) -> ScalarResult,
    check: impl Fn(Scalar1, [Scalar2; LANES]) -> bool,
) where
    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
    Vector: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
{
    test_2(|x: Scalar1, y: [Scalar2; LANES]| {
        proptest::prop_assume!(check(x, y));
        let result_1: [ScalarResult; LANES] = fv(x, y.into()).into();
        let result_2: [ScalarResult; LANES] = {
            let mut result = [ScalarResult::default(); LANES];
            for (i, o) in y.iter().zip(result.iter_mut()) {
                *o = fs(x, *i);
            }
            result
        };
        crate::prop_assert_biteq!(result_1, result_2);
        Ok(())
    });
}

#[macro_export]
macro_rules! test_lanes {
    {
        $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
    } => {
        $(
            mod $test {
                use super::*;

                fn implementation<const $lanes: usize>() $body

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_1() {
                    implementation::<1>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_2() {
                    implementation::<2>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_4() {
                    implementation::<4>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_8() {
                    implementation::<8>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_16() {
                    implementation::<16>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_32() {
                    implementation::<32>();
                }

                #[test]
                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
                fn lanes_64() {
                    implementation::<64>();
                }
            }
        )*
    }
}
<|endoftext|>