<commit_before>use crate::kind::Trivial;
use crate::string::CxxString;
use crate::ExternType;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::Deref;

/// BInding to C++ `std::shared_ptr<T>`.
#[repr(C)]
pub struct SharedPtr<T>
where
    T: SharedPtrTarget,
{
    repr: [*mut c_void; 2],
    ty: PhantomData<T>,
}

impl<T> SharedPtr<T>
where
    T: SharedPtrTarget,
{
    /// Makes a new SharedPtr wrapping a null pointer.
    ///
    /// Matches the behavior of default-constructing a std::shared\_ptr.
    pub fn null() -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__null(new);
            shared_ptr.assume_init()
        }
    }

    /// Allocates memory on the heap and makes a SharedPtr owner for it.
    pub fn new(value: T) -> Self
    where
        T: ExternType<Kind = Trivial>,
    {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__new(value, new);
            shared_ptr.assume_init()
        }
    }

    /// Chacks whether the SharedPtr does not own an object.
    ///
    /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
    pub fn is_null(&self) -> bool {
        let this = self as *const Self as *const c_void;
        let ptr = unsafe { T::__get(this) };
        ptr.is_null()
    }

    /// Returns a reference to the object owned by this SharedPtr if any,
    /// otherwise None.
    pub fn as_ref(&self) -> Option<&T> {
        let this = self as *const Self as *const c_void;
        unsafe { T::__get(this).as_ref() }
    }
}

unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}

impl<T> Clone for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn clone(&self) -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        let this = self as *const Self as *mut c_void;
        unsafe {
            T::__clone(this, new);
            shared_ptr.assume_init()
        }
    }
}

impl<T> Drop for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn drop(&mut self) {
        let this = self as *mut Self as *mut c_void;
        unsafe { T::__drop(this) }
    }
}

impl<T> Deref for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self.as_ref() {
            Some(target) => target,
            None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

impl<T> Debug for SharedPtr<T>
where
    T: Debug + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Debug::fmt(value, formatter),
        }
    }
}

impl<T> Display for SharedPtr<T>
where
    T: Display + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Display::fmt(value, formatter),
        }
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
pub unsafe trait SharedPtrTarget {
    #[doc(hidden)]
    const __NAME: &'static dyn Display;
    #[doc(hidden)]
    unsafe fn __null(new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __new(value: Self, new: *mut c_void)
    where
        Self: Sized,
    {
        // Opoaque C types do not get this method because they can never exist
        // by value on the Rust side of the bridge.
        let _ = value;
        let _ = new;
        unreachable!()
    }
    #[doc(hidden)]
    unsafe fn __clone(this: *const c_void, new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __get(this: *const c_void) -> *const Self;
    #[doc(hidden)]
    unsafe fn __drop(this: *mut c_void);
}

macro_rules! impl_shared_ptr_target {
    ($segment:expr, $name:expr, $ty:ty) => {
        unsafe impl SharedPtrTarget for $ty {
            const __NAME: &'static dyn Display = &$name;
            unsafe fn __null(new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
                        fn __null(new: *mut c_void);
                    }
                }
                __null(new);
            }
            unsafe fn __new(value: Self, new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
                        fn __uninit(new: *mut c_void) -> *mut c_void;
                    }
                }
                __uninit(new).cast::<$ty>().write(value);
            }
            unsafe fn __clone(this: *const c_void, new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
                        fn __clone(this: *const c_void, new: *mut c_void);
                    }
                }
                __clone(this, new);
            }
            unsafe fn __get(this: *const c_void) -> *const Self {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
                        fn __get(this: *const c_void) -> *const c_void;
                    }
                }
                __get(this).cast()
            }
            unsafe fn __drop(this: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
                        fn __drop(this: *mut c_void);
                    }
                }
                __drop(this);
            }
        }
    };
}

macro_rules! impl_shared_ptr_target_for_primitive {
    ($ty:ident) => {
        impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_shared_ptr_target_for_primitive!(u8);
impl_shared_ptr_target_for_primitive!(u16);
impl_shared_ptr_target_for_primitive!(u32);
impl_shared_ptr_target_for_primitive!(u64);
impl_shared_ptr_target_for_primitive!(usize);
impl_shared_ptr_target_for_primitive!(i8);
impl_shared_ptr_target_for_primitive!(i16);
impl_shared_ptr_target_for_primitive!(i32);
impl_shared_ptr_target_for_primitive!(i64);
impl_shared_ptr_target_for_primitive!(isize);
impl_shared_ptr_target_for_primitive!(f32);
impl_shared_ptr_target_for_primitive!(f64);

impl_shared_ptr_target!("string", "CxxString", CxxString);
<commit_msg>Fix capitalization typo in SharedPtr rustdoc<commit_after>use crate::kind::Trivial;
use crate::string::CxxString;
use crate::ExternType;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::Deref;

/// Binding to C++ `std::shared_ptr<T>`.
#[repr(C)]
pub struct SharedPtr<T>
where
    T: SharedPtrTarget,
{
    repr: [*mut c_void; 2],
    ty: PhantomData<T>,
}

impl<T> SharedPtr<T>
where
    T: SharedPtrTarget,
{
    /// Makes a new SharedPtr wrapping a null pointer.
    ///
    /// Matches the behavior of default-constructing a std::shared\_ptr.
    pub fn null() -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__null(new);
            shared_ptr.assume_init()
        }
    }

    /// Allocates memory on the heap and makes a SharedPtr owner for it.
    pub fn new(value: T) -> Self
    where
        T: ExternType<Kind = Trivial>,
    {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__new(value, new);
            shared_ptr.assume_init()
        }
    }

    /// Chacks whether the SharedPtr does not own an object.
    ///
    /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
    pub fn is_null(&self) -> bool {
        let this = self as *const Self as *const c_void;
        let ptr = unsafe { T::__get(this) };
        ptr.is_null()
    }

    /// Returns a reference to the object owned by this SharedPtr if any,
    /// otherwise None.
    pub fn as_ref(&self) -> Option<&T> {
        let this = self as *const Self as *const c_void;
        unsafe { T::__get(this).as_ref() }
    }
}

unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}

impl<T> Clone for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn clone(&self) -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        let this = self as *const Self as *mut c_void;
        unsafe {
            T::__clone(this, new);
            shared_ptr.assume_init()
        }
    }
}

impl<T> Drop for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn drop(&mut self) {
        let this = self as *mut Self as *mut c_void;
        unsafe { T::__drop(this) }
    }
}

impl<T> Deref for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self.as_ref() {
            Some(target) => target,
            None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

impl<T> Debug for SharedPtr<T>
where
    T: Debug + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Debug::fmt(value, formatter),
        }
    }
}

impl<T> Display for SharedPtr<T>
where
    T: Display + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Display::fmt(value, formatter),
        }
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
pub unsafe trait SharedPtrTarget {
    #[doc(hidden)]
    const __NAME: &'static dyn Display;
    #[doc(hidden)]
    unsafe fn __null(new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __new(value: Self, new: *mut c_void)
    where
        Self: Sized,
    {
        // Opoaque C types do not get this method because they can never exist
        // by value on the Rust side of the bridge.
        let _ = value;
        let _ = new;
        unreachable!()
    }
    #[doc(hidden)]
    unsafe fn __clone(this: *const c_void, new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __get(this: *const c_void) -> *const Self;
    #[doc(hidden)]
    unsafe fn __drop(this: *mut c_void);
}

macro_rules! impl_shared_ptr_target {
    ($segment:expr, $name:expr, $ty:ty) => {
        unsafe impl SharedPtrTarget for $ty {
            const __NAME: &'static dyn Display = &$name;
            unsafe fn __null(new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
                        fn __null(new: *mut c_void);
                    }
                }
                __null(new);
            }
            unsafe fn __new(value: Self, new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
                        fn __uninit(new: *mut c_void) -> *mut c_void;
                    }
                }
                __uninit(new).cast::<$ty>().write(value);
            }
            unsafe fn __clone(this: *const c_void, new: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
                        fn __clone(this: *const c_void, new: *mut c_void);
                    }
                }
                __clone(this, new);
            }
            unsafe fn __get(this: *const c_void) -> *const Self {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
                        fn __get(this: *const c_void) -> *const c_void;
                    }
                }
                __get(this).cast()
            }
            unsafe fn __drop(this: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
                        fn __drop(this: *mut c_void);
                    }
                }
                __drop(this);
            }
        }
    };
}

macro_rules! impl_shared_ptr_target_for_primitive {
    ($ty:ident) => {
        impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_shared_ptr_target_for_primitive!(u8);
impl_shared_ptr_target_for_primitive!(u16);
impl_shared_ptr_target_for_primitive!(u32);
impl_shared_ptr_target_for_primitive!(u64);
impl_shared_ptr_target_for_primitive!(usize);
impl_shared_ptr_target_for_primitive!(i8);
impl_shared_ptr_target_for_primitive!(i16);
impl_shared_ptr_target_for_primitive!(i32);
impl_shared_ptr_target_for_primitive!(i64);
impl_shared_ptr_target_for_primitive!(isize);
impl_shared_ptr_target_for_primitive!(f32);
impl_shared_ptr_target_for_primitive!(f64);

impl_shared_ptr_target!("string", "CxxString", CxxString);
<|endoftext|>


<commit_before>extern crate human_name;
extern crate unicode_normalization;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::hash::{Hash, Hasher, SipHasher};
use unicode_normalization::UnicodeNormalization;

fn none_if_empty(s: &str) -> Option<&str> {
    if s.is_empty() {
        None
    } else {
        Some(s)
    }
}

fn stderr_newline() {
    writeln!(&mut std::io::stderr(), "").ok().unwrap();
}

fn hash<T: Hash>(t: &T) -> u64 {
    let mut s = SipHasher::new();
    t.hash(&mut s);
    s.finish()
}

#[test]
fn parsing() {
    let f = File::open("tests/parseable-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    stderr_newline();

    for line in reader.lines() {
        let line: String = line.ok().unwrap().nfkd().collect();

        if line.starts_with("#") || !line.contains("|") {
            continue;
        }

        let parts: Vec<&str> = line.split("|").collect();
        let input = parts[0];
        let surname = parts[1];
        let given_name = parts[2];
        let middle_names = parts[3];
        let first_initial = parts[4].chars().nth(0).unwrap();
        let middle_initials = parts[5];
        let suffix = parts[6];

        let name = human_name::Name::parse(input);
        assert!(!name.is_none(), "[{}] Could not parse!", input);

        let given_name = none_if_empty(&given_name);
        let middle_names = none_if_empty(&middle_names);
        let middle_initials = none_if_empty(&middle_initials);
        let suffix = none_if_empty(&suffix);

        let name = name.unwrap();
        assert!(name.surname() == surname,
                "[{}] Expected surname {}, got {}",
                input,
                surname,
                name.surname());
        assert!(name.first_initial() == first_initial,
                "[{}] Expected first initial {}, got {}",
                input,
                first_initial,
                name.first_initial());
        assert!(name.given_name() == given_name,
                "[{}] Expected given_name {:?}, got {:?}",
                input,
                given_name,
                name.given_name());
        assert!(name.middle_name().map(|w| w.to_string()) == middle_names.map(|w| w.to_string()),
                "[{}] Expected middle names {:?}, got {:?}",
                input,
                middle_names,
                name.middle_name());
        assert!(name.middle_initials() == middle_initials,
                "[{}] Expected middle initials {:?}, got {:?}",
                input,
                middle_initials,
                name.middle_initials());
        assert!(name.suffix() == suffix,
                "[{}] Expected suffix {:?}, got {:?}",
                input,
                suffix,
                name.suffix());

        writeln!(&mut std::io::stderr(),
                 "Parsed '{}' as '{}', {:?} {:?} ({:?}), {:?}",
                 input,
                 surname,
                 given_name,
                 middle_names,
                 middle_initials,
                 suffix)
            .ok()
            .unwrap();
    }

    stderr_newline();
}

#[test]
fn unparseable() {
    let f = File::open("tests/unparseable-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    stderr_newline();

    for line in reader.lines() {
        let line = line.ok().unwrap();

        if line.starts_with("#") {
            continue;
        }

        let result = human_name::Name::parse(&line);
        assert!(result.is_none(),
                "'Parsed' junk name: '{}' as '{}'",
                line,
                result.unwrap().display_first_last());

        writeln!(&mut std::io::stderr(), "Correctly discarded '{}'", line).ok().unwrap();
    }

    stderr_newline();
}

#[test]
fn equality() {
    let f = File::open("tests/equal-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    stderr_newline();

    for line in reader.lines() {
        let line = line.ok().unwrap();

        if line.starts_with("#") {
            continue;
        }

        let parts: Vec<&str> = line.split('|').collect();
        let a = parts[0];
        let b = parts[1];
        let expect = parts[2];

        let parsed_a = human_name::Name::parse(&a);
        let parsed_b = human_name::Name::parse(&b);

        assert!(parsed_a.is_some(), "{} was not parsed", a);
        assert!(parsed_b.is_some(), "{} was not parsed", b);

        if expect == "==" {
            assert!(parsed_a == parsed_b,
                    "{} should be equal to {} but was not!",
                    a,
                    b);
            assert!(parsed_b == parsed_a,
                    "{} should be equal to {} but was not!",
                    b,
                    a);
            assert!(hash(&parsed_a) == hash(&parsed_b),
                    "{} should have the same hash as {} but did not!",
                    a,
                    b);
        } else {
            assert!(parsed_a != parsed_b,
                    "{} should not be equal to {} but was!",
                    a,
                    b);
            assert!(parsed_b != parsed_a,
                    "{} should not be equal to {} but was!",
                    b,
                    a);
        }

        writeln!(&mut std::io::stderr(), "{} {} {}", a, expect, b).ok().unwrap();
    }

    stderr_newline();
}
<commit_msg>Remove unnecessary output from tests<commit_after>extern crate human_name;
extern crate unicode_normalization;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use unicode_normalization::UnicodeNormalization;

fn none_if_empty(s: &str) -> Option<&str> {
    if s.is_empty() {
        None
    } else {
        Some(s)
    }
}

#[test]
fn parsing() {
    let f = File::open("tests/parseable-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    for line in reader.lines() {
        let line: String = line.ok().unwrap().nfkd().collect();

        if line.starts_with("#") || !line.contains("|") {
            continue;
        }

        let parts: Vec<&str> = line.split("|").collect();
        let input = parts[0];
        let surname = parts[1];
        let given_name = parts[2];
        let middle_names = parts[3];
        let first_initial = parts[4].chars().nth(0).unwrap();
        let middle_initials = parts[5];
        let suffix = parts[6];

        let name = human_name::Name::parse(input);
        assert!(!name.is_none(), "[{}] Could not parse!", input);

        let given_name = none_if_empty(&given_name);
        let middle_names = none_if_empty(&middle_names);
        let middle_initials = none_if_empty(&middle_initials);
        let suffix = none_if_empty(&suffix);

        let name = name.unwrap();
        assert!(name.surname() == surname,
                "[{}] Expected surname {}, got {}",
                input,
                surname,
                name.surname());
        assert!(name.first_initial() == first_initial,
                "[{}] Expected first initial {}, got {}",
                input,
                first_initial,
                name.first_initial());
        assert!(name.given_name() == given_name,
                "[{}] Expected given_name {:?}, got {:?}",
                input,
                given_name,
                name.given_name());
        assert!(name.middle_name().map(|w| w.to_string()) == middle_names.map(|w| w.to_string()),
                "[{}] Expected middle names {:?}, got {:?}",
                input,
                middle_names,
                name.middle_name());
        assert!(name.middle_initials() == middle_initials,
                "[{}] Expected middle initials {:?}, got {:?}",
                input,
                middle_initials,
                name.middle_initials());
        assert!(name.suffix() == suffix,
                "[{}] Expected suffix {:?}, got {:?}",
                input,
                suffix,
                name.suffix());
    }
}

#[test]
fn unparseable() {
    let f = File::open("tests/unparseable-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    for line in reader.lines() {
        let line = line.ok().unwrap();

        if line.starts_with("#") {
            continue;
        }

        let result = human_name::Name::parse(&line);
        assert!(result.is_none(),
                "'Parsed' junk name: '{}' as '{}'",
                line,
                result.unwrap().display_first_last());
    }
}

#[test]
fn equality() {
    let f = File::open("tests/equal-names.txt").ok().unwrap();
    let reader = BufReader::new(f);

    for line in reader.lines() {
        let line = line.ok().unwrap();

        if line.starts_with("#") {
            continue;
        }

        let parts: Vec<&str> = line.split('|').collect();
        let a = parts[0];
        let b = parts[1];
        let expect = parts[2];

        let parsed_a = human_name::Name::parse(&a);
        let parsed_b = human_name::Name::parse(&b);

        assert!(parsed_a.is_some(), "{} was not parsed", a);
        assert!(parsed_b.is_some(), "{} was not parsed", b);

        if expect == "==" {
            assert!(parsed_a == parsed_b,
                    "{} should be equal to {} but was not!",
                    a,
                    b);
            assert!(parsed_b == parsed_a,
                    "{} should be equal to {} but was not!",
                    b,
                    a);
            assert!(parsed_a.unwrap().memoized_surname_hash() == parsed_b.unwrap().memoized_surname_hash(),
                    "{} should have the same hash as {} but did not!",
                    a,
                    b);
        } else {
            assert!(parsed_a != parsed_b,
                    "{} should not be equal to {} but was!",
                    a,
                    b);
            assert!(parsed_b != parsed_a,
                    "{} should not be equal to {} but was!",
                    b,
                    a);
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate libracerd;
extern crate rustc_serialize;
extern crate env_logger;

#[macro_use]
extern crate hyper;

extern crate crypto;

mod util;

/// Although the value is not used, running env! for RUST_SRC_PATH checks, before running the tests,
/// that the required environment variable is defined.
const _RUST_SRC_PATH: &'static str = env!("RUST_SRC_PATH");

macro_rules! init_logging {
    () => {
        let _ = ::env_logger::init();
    }
}

#[test]
#[should_panic]
#[cfg(not(windows))]
fn panics_when_invalid_secret_given() {
    use ::libracerd::engine::{Racer, SemanticEngine};
    use ::libracerd::http::serve;
    use ::libracerd::Config;

    init_logging!();

    let config = Config {
        secret_file: Some("a.file.that.does.not.exist".to_owned()),
        print_http_logs: true,
        .. Default::default()
    };

    let engine = Racer::new();
    engine.initialize(&config).unwrap();
    serve(&config, engine).unwrap();
}

mod http {
    use hyper::header::ContentType;
    use hyper::Client;

    use std::io::Read;

    header! { (XRacerdHmac, "x-racerd-hmac") => [String] }

    use util::http::{self, UrlBuilder, request_str};

    use rustc_serialize::json::{Json};
    use libracerd::util::fs::TmpFile;

    use hyper::method::Method;

    /// Checks that /find_definition works within a single buffer
    #[test]
    fn find_definition() {
        init_logging!();
        http::with_server(|server| {
            // Build request args
            let url = server.url("/find_definition");
            let request_obj = stringify!({
                "buffers": [{
                    "file_path": "src.rs",
                    "contents": "fn foo() {}\nfn bar() {}\nfn main() {\nfoo();\n}"
                }],
                "file_path": "src.rs",
                "line": 4,
                "column": 3
            });

            // Make request
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "foo",
                "line": 1,
                "column": 3,
                "file_path": "src.rs",
                "context": "fn foo() {}",
                "kind": "Function"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    /// Checks that /find_definition correctly resolves cross file definitions when the buffers have
    /// not been written to disk.
    #[test]
    fn find_definition_multiple_dirty_buffers() {
        init_logging!();
        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "mod src2;\nuse src2::{foo,myfn};\nfn main() {\n    myfn();\n}\n"
            }, {
                "file_path": "src2.rs",
                "contents": "\npub fn myfn()\npub fn foo() {}\n"
            }],
            "file_path": "src.rs",
            "line": 4,
            "column": 7
        });

        // Create an *empty* temporary file. The request contains unsaved file contents. For rust
        // module inclusions to work, the compiler checks certain locations on the file system where
        // a module file could be located. It simply doesn't work with unnamed files.
        let _f = TmpFile::with_name("src2.rs", "");

        http::with_server(|server| {
            // Make request
            let url = server.url("/find_definition");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "myfn",
                "line": 2,
                "column": 7,
                "file_path": "src2.rs",
                "context": "pub fn myfn()",
                "kind": "Function"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    macro_rules! assert_str_prop_on_obj_in_list {
        ($prop:expr, $val:expr, $list:expr) => {
            assert!($list.as_array().unwrap().iter().any(|c| {
                $val == c.as_object().unwrap().get($prop).unwrap().as_string().unwrap()
            }));
        }
    }

    #[test]
    fn find_definition_in_std_library() {
        init_logging!();
        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "use std::path::Path;\nfn main() {\nlet p = &Path::new(\"arst\")\n}\n"
            }],
            "file_path": "src.rs",
            "line": 3,
            "column": 16
        });

        http::with_server(|server| {
            // Make request
            let url = server.url("/find_definition");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();

            // We don't know exactly how the result is going to look in this case.
            let obj = actual.as_object().unwrap();

            // Check that `file_path` ends_with "path.rs"
            let found_path = obj.get("file_path").unwrap().as_string().unwrap();
            assert!(found_path.ends_with("path.rs"));

            // Check that we found a thing called "new"
            let found_text = obj.get("text").unwrap().as_string().unwrap();
            assert_eq!(found_text, "new");
        });
    }

    #[test]
    fn list_path_completions_std_library() {
        use rustc_serialize::json;
        init_logging!();

        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "use std::path;\nfn main() {\nlet p = &path::\n}\n"
            }],
            "file_path": "src.rs",
            "line": 3,
            "column": 15
        });

        http::with_server(|server| {
            // Make request
            let url = server.url("/list_completions");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            let list = Json::from_str(&res[..]).unwrap();

            println!("{}", json::as_pretty_json(&list));

            // Check that the "Path" completion is available
            assert_str_prop_on_obj_in_list!("text", "Path", list);
            assert_str_prop_on_obj_in_list!("text", "PathBuf", list);
        });
    }

    #[test]
    fn ping_pong() {
        init_logging!();
        http::with_server(|server| {
            let url = server.url("/ping");
            let res = request_str(Method::Get, &url[..], None).unwrap().unwrap();
            let actual = Json::from_str(&res[..]).unwrap();

            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong_hmac_with_correct_secret() {
        init_logging!();
        let secret = "hello hmac ping pong";

        http::with_hmac_server(secret, |server| {
            // The request hmac in this case should be
            let hmac = ::util::request_hmac(secret, "GET", "/ping", "");

            let url = server.url("/ping");

            let client = Client::new();
            let mut res = client.get(&url[..])
                                .header(XRacerdHmac(hmac))
                                .header(ContentType::json())
                                .send().unwrap();

            assert_eq!(res.status, ::hyper::status::StatusCode::Ok);

            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();

            let actual = Json::from_str(&body[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong_hmac_wrong_secret() {
        init_logging!();
        let secret = "hello hmac ping pong";

        http::with_hmac_server(secret, |server| {
            // The request hmac in this case should be
            let hmac = ::util::request_hmac("different secret", "GET", "/ping", "");

            let url = server.url("/ping");

            let client = Client::new();
            let res = client.get(&url[..])
                            .header(XRacerdHmac(hmac))
                            .header(ContentType::json())
                            .send().unwrap();

            assert_eq!(res.status, ::hyper::status::StatusCode::Forbidden);
        });
    }
}
<commit_msg>Fix tests for racer 1.2.10.<commit_after>#![deny(warnings)]

extern crate libracerd;
extern crate rustc_serialize;
extern crate env_logger;

#[macro_use]
extern crate hyper;

extern crate crypto;

mod util;

/// Although the value is not used, running env! for RUST_SRC_PATH checks, before running the tests,
/// that the required environment variable is defined.
const _RUST_SRC_PATH: &'static str = env!("RUST_SRC_PATH");

macro_rules! init_logging {
    () => {
        let _ = ::env_logger::init();
    }
}

#[test]
#[should_panic]
#[cfg(not(windows))]
fn panics_when_invalid_secret_given() {
    use ::libracerd::engine::{Racer, SemanticEngine};
    use ::libracerd::http::serve;
    use ::libracerd::Config;

    init_logging!();

    let config = Config {
        secret_file: Some("a.file.that.does.not.exist".to_owned()),
        print_http_logs: true,
        .. Default::default()
    };

    let engine = Racer::new();
    engine.initialize(&config).unwrap();
    serve(&config, engine).unwrap();
}

mod http {
    use hyper::header::ContentType;
    use hyper::Client;

    use std::io::Read;

    header! { (XRacerdHmac, "x-racerd-hmac") => [String] }

    use util::http::{self, UrlBuilder, request_str};

    use rustc_serialize::json::{Json};
    use libracerd::util::fs::TmpFile;

    use hyper::method::Method;

    /// Checks that /find_definition works within a single buffer
    #[test]
    fn find_definition() {
        init_logging!();
        http::with_server(|server| {
            // Build request args
            let url = server.url("/find_definition");
            let request_obj = stringify!({
                "buffers": [{
                    "file_path": "src.rs",
                    "contents": "fn foo() {}\nfn bar() {}\nfn main() {\nfoo();\n}"
                }],
                "file_path": "src.rs",
                "line": 4,
                "column": 3
            });

            // Make request
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "foo",
                "line": 1,
                "column": 3,
                "file_path": "src.rs",
                "context": "fn foo()",
                "kind": "Function"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    /// Checks that /find_definition correctly resolves cross file definitions when the buffers have
    /// not been written to disk.
    #[test]
    fn find_definition_multiple_dirty_buffers() {
        init_logging!();
        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "mod src2;\nuse src2::{foo,myfn};\nfn main() {\n    myfn();\n}\n"
            }, {
                "file_path": "src2.rs",
                "contents": "\npub fn myfn()\npub fn foo() {}\n"
            }],
            "file_path": "src.rs",
            "line": 4,
            "column": 7
        });

        // Create an *empty* temporary file. The request contains unsaved file contents. For rust
        // module inclusions to work, the compiler checks certain locations on the file system where
        // a module file could be located. It simply doesn't work with unnamed files.
        let _f = TmpFile::with_name("src2.rs", "");

        http::with_server(|server| {
            // Make request
            let url = server.url("/find_definition");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "text": "myfn",
                "line": 2,
                "column": 7,
                "file_path": "src2.rs",
                "context": "pub fn myfn() pub fn foo()",
                "kind": "Function"
            })).unwrap();

            // They should be equal
            assert_eq!(actual, expected);
        });
    }

    macro_rules! assert_str_prop_on_obj_in_list {
        ($prop:expr, $val:expr, $list:expr) => {
            assert!($list.as_array().unwrap().iter().any(|c| {
                $val == c.as_object().unwrap().get($prop).unwrap().as_string().unwrap()
            }));
        }
    }

    #[test]
    fn find_definition_in_std_library() {
        init_logging!();
        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "use std::path::Path;\nfn main() {\nlet p = &Path::new(\"arst\");\n}\n"
            }],
            "file_path": "src.rs",
            "line": 3,
            "column": 16
        });

        http::with_server(|server| {
            // Make request
            let url = server.url("/find_definition");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            // Build actual/expected objects
            let actual = Json::from_str(&res[..]).unwrap();

            // We don't know exactly how the result is going to look in this case.
            let obj = actual.as_object().unwrap();

            // Check that `file_path` ends_with "path.rs"
            let found_path = obj.get("file_path").unwrap().as_string().unwrap();
            assert!(found_path.ends_with("path.rs"));

            // Check that we found a thing called "new"
            let found_text = obj.get("text").unwrap().as_string().unwrap();
            assert_eq!(found_text, "new");
        });
    }

    #[test]
    fn list_path_completions_std_library() {
        use rustc_serialize::json;
        init_logging!();

        // Build request args
        let request_obj = stringify!({
            "buffers": [{
                "file_path": "src.rs",
                "contents": "use std::path;\nfn main() {\nlet p = &path::\n}\n"
            }],
            "file_path": "src.rs",
            "line": 3,
            "column": 15
        });

        http::with_server(|server| {
            // Make request
            let url = server.url("/list_completions");
            let res = request_str(Method::Post, &url[..], Some(request_obj)).unwrap().unwrap();

            let list = Json::from_str(&res[..]).unwrap();

            println!("{}", json::as_pretty_json(&list));

            // Check that the "Path" completion is available
            assert_str_prop_on_obj_in_list!("text", "Path", list);
            assert_str_prop_on_obj_in_list!("text", "PathBuf", list);
        });
    }

    #[test]
    fn ping_pong() {
        init_logging!();
        http::with_server(|server| {
            let url = server.url("/ping");
            let res = request_str(Method::Get, &url[..], None).unwrap().unwrap();
            let actual = Json::from_str(&res[..]).unwrap();

            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong_hmac_with_correct_secret() {
        init_logging!();
        let secret = "hello hmac ping pong";

        http::with_hmac_server(secret, |server| {
            // The request hmac in this case should be
            let hmac = ::util::request_hmac(secret, "GET", "/ping", "");

            let url = server.url("/ping");

            let client = Client::new();
            let mut res = client.get(&url[..])
                                .header(XRacerdHmac(hmac))
                                .header(ContentType::json())
                                .send().unwrap();

            assert_eq!(res.status, ::hyper::status::StatusCode::Ok);

            let mut body = String::new();
            res.read_to_string(&mut body).unwrap();

            let actual = Json::from_str(&body[..]).unwrap();
            let expected = Json::from_str(stringify!({
                "pong": true
            })).unwrap();

            assert_eq!(actual, expected);
        });
    }

    #[test]
    fn ping_pong_hmac_wrong_secret() {
        init_logging!();
        let secret = "hello hmac ping pong";

        http::with_hmac_server(secret, |server| {
            // The request hmac in this case should be
            let hmac = ::util::request_hmac("different secret", "GET", "/ping", "");

            let url = server.url("/ping");

            let client = Client::new();
            let res = client.get(&url[..])
                            .header(XRacerdHmac(hmac))
                            .header(ContentType::json())
                            .send().unwrap();

            assert_eq!(res.status, ::hyper::status::StatusCode::Forbidden);
        });
    }
}
<|endoftext|>


<commit_before>extern crate jservice;

#[test]
fn deserialize_clue() {
    extern crate serde_json;

    let bytes = r#"{"id":1,"answer":"Election Day","question":"1st Tuesday after the 1st Monday in November","value":100,"airdate":"1985-02-08T12:00:00.000Z","created_at":"2014-02-11T22:47:18.786Z","updated_at":"2014-02-11T22:47:18.786Z","category_id":1,"game_id":null,"invalid_count":null,"category":{"id":1,"title":"politics","created_at":"2014-02-11T22:47:18.687Z","updated_at":"2014-02-11T22:47:18.687Z","clues_count":30}}"#;
    let clue: Clue = serde_json::from_str(bytes).unwrap();
    assert_eq!(clue.question, "1st Tuesday after the 1st Monday in November");
}

#[test]
fn get_clues() {
    jservice::get_clues(None, None, None, None, None).unwrap();
}

#[test]
fn get_random() {
    jservice::get_random(None).unwrap();
}

#[test]
fn get_categories() {
    jservice::get_categories(None, None).unwrap();
}

#[test]
fn get_category() {
    jservice::get_category(1).unwrap();
}
<commit_msg>Fix test<commit_after>extern crate jservice;

#[test]
fn deserialize_clue() {
    extern crate serde_json;

    let bytes = r#"{"id":1,"answer":"Election Day","question":"1st Tuesday after the 1st Monday in November","value":100,"airdate":"1985-02-08T12:00:00.000Z","created_at":"2014-02-11T22:47:18.786Z","updated_at":"2014-02-11T22:47:18.786Z","category_id":1,"game_id":null,"invalid_count":null,"category":{"id":1,"title":"politics","created_at":"2014-02-11T22:47:18.687Z","updated_at":"2014-02-11T22:47:18.687Z","clues_count":30}}"#;
    let clue: jservice::Clue = serde_json::from_str(bytes).unwrap();
    assert_eq!(clue.question, "1st Tuesday after the 1st Monday in November");
}

#[test]
fn get_clues() {
    jservice::get_clues(None, None, None, None, None).unwrap();
}

#[test]
fn get_random() {
    jservice::get_random(None).unwrap();
}

#[test]
fn get_categories() {
    jservice::get_categories(None, None).unwrap();
}

#[test]
fn get_category() {
    jservice::get_category(1).unwrap();
}
<|endoftext|>


<commit_before>use crate::thread::Time;
use crate::*;
use rustc_target::abi::{Align, Size};
use std::time::{Instant, SystemTime};

/// Implementation of the SYS_futex syscall.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if !(4..=7).contains(&args.len()) {
        throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len());
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // We checked above that these definitely exist.
    let addr = this.read_immediate(args[1])?;
    let op = this.read_scalar(args[2])?.to_i32()?;
    let val = this.read_scalar(args[3])?.to_i32()?;

    // The raw pointer value is used to identify the mutex.
    // Not all mutex operations actually read from this address or even require this address to exist.
    // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on
    // such a pointer can never work anyway, so that seems fine.
    let futex_ptr = this.force_ptr(addr.to_scalar()?)?;

    let thread = this.get_active_thread();

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
    let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        op if op & !futex_realtime == futex_wait => {
            if args.len() < 5 {
                throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len());
            }
            let timeout = args[4];
            let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? {
                None
            } else {
                let duration = match this.read_timespec(timeout)? {
                    Some(duration) => duration,
                    None => {
                        let einval = this.eval_libc("EINVAL")?;
                        this.set_last_error(einval)?;
                        this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                        return Ok(());
                    }
                };
                this.check_no_isolation("FUTEX_WAIT with timeout")?;
                Some(if op & futex_realtime != 0 {
                    Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
                } else {
                    Time::Monotonic(Instant::now().checked_add(duration).unwrap())
                })
            };
            // Check the pointer for alignment and validity.
            // The API requires `addr` to be a 4-byte aligned pointer, and will
            // use the 4 bytes at the given address as an (atomic) i32.
            this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
            // Read an `i32` through the pointer, regardless of any wrapper types.
            // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
            let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the trait make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(futex_ptr, thread);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_machine_isize(0, this), dest)?;
                // Register a timeout callback if a timeout was specified.
                // This callback will override the return value when the timeout triggers.
                if let Some(timeout_time) = timeout_time {
                    this.register_timeout_callback(
                        thread,
                        timeout_time,
                        Box::new(move |this| {
                            this.unblock_thread(thread);
                            this.futex_remove_waiter(futex_ptr, thread);
                            let etimedout = this.eval_libc("ETIMEDOUT")?;
                            this.set_last_error(etimedout)?;
                            this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                            Ok(())
                        }),
                    );
                }
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        op if op == futex_wake => {
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(futex_ptr) {
                    this.unblock_thread(thread);
                    this.unregister_timeout_callback_if_exists(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_machine_isize(n, this), dest)?;
        }
        op => throw_unsup_format!("miri does not support SYS_futex operation {}", op),
    }

    Ok(())
}
<commit_msg>Add FIXME about type of `addr` in futex implementation.<commit_after>use crate::thread::Time;
use crate::*;
use rustc_target::abi::{Align, Size};
use std::time::{Instant, SystemTime};

/// Implementation of the SYS_futex syscall.
pub fn futex<'tcx>(
    this: &mut MiriEvalContext<'_, 'tcx>,
    args: &[OpTy<'tcx, Tag>],
    dest: PlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx> {
    // The amount of arguments used depends on the type of futex operation.
    // The full futex syscall takes six arguments (excluding the syscall
    // number), which is also the maximum amount of arguments a linux syscall
    // can take on most architectures.
    // However, not all futex operations use all six arguments. The unused ones
    // may or may not be left out from the `syscall()` call.
    // Therefore we don't use `check_arg_count` here, but only check for the
    // number of arguments to fall within a range.
    if !(4..=7).contains(&args.len()) {
        throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len());
    }

    // The first three arguments (after the syscall number itself) are the same to all futex operations:
    //     (int *addr, int op, int val).
    // We checked above that these definitely exist.
    let addr = this.read_immediate(args[1])?;
    let op = this.read_scalar(args[2])?.to_i32()?;
    let val = this.read_scalar(args[3])?.to_i32()?;

    // The raw pointer value is used to identify the mutex.
    // Not all mutex operations actually read from this address or even require this address to exist.
    // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on
    // such a pointer can never work anyway, so that seems fine.
    let futex_ptr = this.force_ptr(addr.to_scalar()?)?;

    let thread = this.get_active_thread();

    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
    let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
    let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
    let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;

    // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
    // Miri doesn't support that anyway, so we ignore that flag.
    match op & !futex_private {
        // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
        // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
        // or *timeout expires. `timeout == null` for an infinite timeout.
        op if op & !futex_realtime == futex_wait => {
            if args.len() < 5 {
                throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len());
            }
            let timeout = args[4];
            let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? {
                None
            } else {
                let duration = match this.read_timespec(timeout)? {
                    Some(duration) => duration,
                    None => {
                        let einval = this.eval_libc("EINVAL")?;
                        this.set_last_error(einval)?;
                        this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                        return Ok(());
                    }
                };
                this.check_no_isolation("FUTEX_WAIT with timeout")?;
                Some(if op & futex_realtime != 0 {
                    Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
                } else {
                    Time::Monotonic(Instant::now().checked_add(duration).unwrap())
                })
            };
            // Check the pointer for alignment and validity.
            // The API requires `addr` to be a 4-byte aligned pointer, and will
            // use the 4 bytes at the given address as an (atomic) i32.
            this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?;
            // Read an `i32` through the pointer, regardless of any wrapper types.
            // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
            // FIXME: this fails if `addr` is not a pointer type.
            let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?;
            if val == futex_val {
                // The value still matches, so we block the trait make it wait for FUTEX_WAKE.
                this.block_thread(thread);
                this.futex_wait(futex_ptr, thread);
                // Succesfully waking up from FUTEX_WAIT always returns zero.
                this.write_scalar(Scalar::from_machine_isize(0, this), dest)?;
                // Register a timeout callback if a timeout was specified.
                // This callback will override the return value when the timeout triggers.
                if let Some(timeout_time) = timeout_time {
                    this.register_timeout_callback(
                        thread,
                        timeout_time,
                        Box::new(move |this| {
                            this.unblock_thread(thread);
                            this.futex_remove_waiter(futex_ptr, thread);
                            let etimedout = this.eval_libc("ETIMEDOUT")?;
                            this.set_last_error(etimedout)?;
                            this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
                            Ok(())
                        }),
                    );
                }
            } else {
                // The futex value doesn't match the expected value, so we return failure
                // right away without sleeping: -1 and errno set to EAGAIN.
                let eagain = this.eval_libc("EAGAIN")?;
                this.set_last_error(eagain)?;
                this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
            }
        }
        // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
        // Wakes at most `val` threads waiting on the futex at `addr`.
        // Returns the amount of threads woken up.
        // Does not access the futex value at *addr.
        op if op == futex_wake => {
            let mut n = 0;
            for _ in 0..val {
                if let Some(thread) = this.futex_wake(futex_ptr) {
                    this.unblock_thread(thread);
                    this.unregister_timeout_callback_if_exists(thread);
                    n += 1;
                } else {
                    break;
                }
            }
            this.write_scalar(Scalar::from_machine_isize(n, this), dest)?;
        }
        op => throw_unsup_format!("miri does not support SYS_futex operation {}", op),
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt;

use anyhow::Context;
use disk::AsyncDisk;
use disk::DiskFile;
use disk::SingleFileDisk;
use winapi::um::winnt::FILE_SHARE_READ;
use winapi::um::winnt::FILE_SHARE_WRITE;

use crate::virtio::block::block::DiskOption;

pub fn get_seg_max(_queue_size: u16) -> u32 {
    // Allow a single segment per request, since vectored I/O is not implemented for Windows yet.
    1
}

impl DiskOption {
    /// Open the specified disk file.
    pub fn open(&self) -> anyhow::Result<Box<dyn DiskFile>> {
        let io_concurrency = self.io_concurrency.get();

        // We can only take the write lock if a single handle is used (otherwise we can't open
        // multiple handles).
        let share_flags = if io_concurrency == 1 {
            FILE_SHARE_READ
        } else {
            FILE_SHARE_READ | FILE_SHARE_WRITE
        };

        let mut files = Vec::new();
        for _ in 0..io_concurrency {
            files.push(
                OpenOptions::new()
                    .read(true)
                    .write(!self.read_only)
                    .share_mode(share_flags)
                    .open(&self.path)
                    .context("Failed to open disk file")?,
            );
        }

        Ok(Box::new(SingleFileDisk::new_from_files(files)?).into_inner())
    }
}
<commit_msg>devices: simpler disk image opens + bug fix for Windows.<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt;

use anyhow::Context;
use winapi::um::winnt::FILE_SHARE_READ;
use winapi::um::winnt::FILE_SHARE_WRITE;

use crate::virtio::block::block::DiskOption;

pub fn get_seg_max(_queue_size: u16) -> u32 {
    // Allow a single segment per request, since vectored I/O is not implemented for Windows yet.
    1
}

impl DiskOption {
    /// Open the specified disk file.
    pub fn open(&self) -> anyhow::Result<Box<dyn disk::DiskFile>> {
        Ok(disk::create_disk_file(
            OpenOptions::new()
                .read(true)
                .write(!self.read_only)
                .share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
                .open(&self.path)
                .context("Failed to open disk file")?,
            self.sparse,
            disk::MAX_NESTING_DEPTH,
            &self.path,
        )?)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Macros and wrapper functions for dealing with ioctls.
use libc;
use std::os::raw::{c_int, c_uint, c_ulong, c_void};
use std::os::unix::io::AsRawFd;

/// Raw macro to declare a function that returns an ioctl number.
#[macro_export]
macro_rules! ioctl_ioc_nr {
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        #[allow(non_snake_case)]
        pub fn $name() -> ::std::os::raw::c_ulong {
            (($dir << $crate::ioctl::_IOC_DIRSHIFT)
                | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
                | ($nr << $crate::ioctl::_IOC_NRSHIFT)
                | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
        }
    };
}

/// Declare an ioctl that transfers no data.
#[macro_export]
macro_rules! ioctl_io_nr {
    ($name:ident, $ty:expr, $nr:expr) => {
        ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
    };
}

/// Declare an ioctl that reads data.
#[macro_export]
macro_rules! ioctl_ior_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

/// Declare an ioctl that writes data.
#[macro_export]
macro_rules! ioctl_iow_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

/// Declare an ioctl that reads and writes data.
#[macro_export]
macro_rules! ioctl_iowr_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

pub const _IOC_NRBITS: c_uint = 8;
pub const _IOC_TYPEBITS: c_uint = 8;
pub const _IOC_SIZEBITS: c_uint = 14;
pub const _IOC_DIRBITS: c_uint = 2;
pub const _IOC_NRMASK: c_uint = 255;
pub const _IOC_TYPEMASK: c_uint = 255;
pub const _IOC_SIZEMASK: c_uint = 16383;
pub const _IOC_DIRMASK: c_uint = 3;
pub const _IOC_NRSHIFT: c_uint = 0;
pub const _IOC_TYPESHIFT: c_uint = 8;
pub const _IOC_SIZESHIFT: c_uint = 16;
pub const _IOC_DIRSHIFT: c_uint = 30;
pub const _IOC_NONE: c_uint = 0;
pub const _IOC_WRITE: c_uint = 1;
pub const _IOC_READ: c_uint = 2;
pub const IOC_IN: c_uint = 1073741824;
pub const IOC_OUT: c_uint = 2147483648;
pub const IOC_INOUT: c_uint = 3221225472;
pub const IOCSIZE_MASK: c_uint = 1073676288;
pub const IOCSIZE_SHIFT: c_uint = 16;

/// Run an ioctl with no arguments.
pub unsafe fn ioctl<F: AsRawFd>(fd: &F, req: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as c_int, 0)
}

/// Run an ioctl with a single value argument.
pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, req: c_ulong, arg: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as c_int, arg)
}

/// Run an ioctl with an immutable reference.
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> c_int {
    libc::ioctl(
        fd.as_raw_fd(),
        req as c_int,
        arg as *const T as *const c_void,
    )
}

/// Run an ioctl with a mutable reference.
pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as c_int, arg as *mut T as *mut c_void)
}

/// Run an ioctl with a raw pointer.
pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *const T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as c_int, arg as *const c_void)
}

/// Run an ioctl with a mutable raw pointer.
pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as c_int, arg as *mut c_void)
}

#[cfg(test)]
mod tests {
    const TUNTAP: ::std::os::raw::c_uint = 0x54;
    const KVMIO: ::std::os::raw::c_uint = 0xAE;

    ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
    ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
    ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
    ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x2, ::std::os::raw::c_int);

    #[test]
    fn ioctl_macros() {
        assert_eq!(0x0000AE01, KVM_CREATE_VM());
        assert_eq!(0x800454CF, TUNGETFEATURES());
        assert_eq!(0x400454D9, TUNSETQUEUE());
        assert_eq!(0xC004AE02, KVM_GET_MSR_INDEX_LIST());
    }
}
<commit_msg>sys_util: enable build for non-musl libraries<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Macros and wrapper functions for dealing with ioctls.
use libc;
use std::os::raw::{c_int, c_uint, c_ulong, c_void};
use std::os::unix::io::AsRawFd;

/// Raw macro to declare a function that returns an ioctl number.
#[macro_export]
macro_rules! ioctl_ioc_nr {
    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
        #[allow(non_snake_case)]
        pub fn $name() -> ::std::os::raw::c_ulong {
            (($dir << $crate::ioctl::_IOC_DIRSHIFT)
                | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
                | ($nr << $crate::ioctl::_IOC_NRSHIFT)
                | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
        }
    };
}

/// Declare an ioctl that transfers no data.
#[macro_export]
macro_rules! ioctl_io_nr {
    ($name:ident, $ty:expr, $nr:expr) => {
        ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
    };
}

/// Declare an ioctl that reads data.
#[macro_export]
macro_rules! ioctl_ior_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

/// Declare an ioctl that writes data.
#[macro_export]
macro_rules! ioctl_iow_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

/// Declare an ioctl that reads and writes data.
#[macro_export]
macro_rules! ioctl_iowr_nr {
    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
        ioctl_ioc_nr!(
            $name,
            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
            $ty,
            $nr,
            ::std::mem::size_of::<$size>() as u32
        );
    };
}

pub const _IOC_NRBITS: c_uint = 8;
pub const _IOC_TYPEBITS: c_uint = 8;
pub const _IOC_SIZEBITS: c_uint = 14;
pub const _IOC_DIRBITS: c_uint = 2;
pub const _IOC_NRMASK: c_uint = 255;
pub const _IOC_TYPEMASK: c_uint = 255;
pub const _IOC_SIZEMASK: c_uint = 16383;
pub const _IOC_DIRMASK: c_uint = 3;
pub const _IOC_NRSHIFT: c_uint = 0;
pub const _IOC_TYPESHIFT: c_uint = 8;
pub const _IOC_SIZESHIFT: c_uint = 16;
pub const _IOC_DIRSHIFT: c_uint = 30;
pub const _IOC_NONE: c_uint = 0;
pub const _IOC_WRITE: c_uint = 1;
pub const _IOC_READ: c_uint = 2;
pub const IOC_IN: c_uint = 1073741824;
pub const IOC_OUT: c_uint = 2147483648;
pub const IOC_INOUT: c_uint = 3221225472;
pub const IOCSIZE_MASK: c_uint = 1073676288;
pub const IOCSIZE_SHIFT: c_uint = 16;

// The type of the `req` parameter is different for the `musl` library. This will enable
// successful build for other non-musl libraries.
#[cfg(target_env = "musl")]
type IoctlRequest = c_int;
#[cfg(not(target_env = "musl"))]
type IoctlRequest = c_ulong;

/// Run an ioctl with no arguments.
pub unsafe fn ioctl<F: AsRawFd>(fd: &F, req: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, 0)
}

/// Run an ioctl with a single value argument.
pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, req: c_ulong, arg: c_ulong) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg)
}

/// Run an ioctl with an immutable reference.
pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &T) -> c_int {
    libc::ioctl(
        fd.as_raw_fd(),
        req as IoctlRequest,
        arg as *const T as *const c_void,
    )
}

/// Run an ioctl with a mutable reference.
pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: &mut T) -> c_int {
    libc::ioctl(
        fd.as_raw_fd(),
        req as IoctlRequest,
        arg as *mut T as *mut c_void,
    )
}

/// Run an ioctl with a raw pointer.
pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *const T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg as *const c_void)
}

/// Run an ioctl with a mutable raw pointer.
pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, req: c_ulong, arg: *mut T) -> c_int {
    libc::ioctl(fd.as_raw_fd(), req as IoctlRequest, arg as *mut c_void)
}

#[cfg(test)]
mod tests {
    const TUNTAP: ::std::os::raw::c_uint = 0x54;
    const KVMIO: ::std::os::raw::c_uint = 0xAE;

    ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
    ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
    ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
    ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x2, ::std::os::raw::c_int);

    #[test]
    fn ioctl_macros() {
        assert_eq!(0x0000AE01, KVM_CREATE_VM());
        assert_eq!(0x800454CF, TUNGETFEATURES());
        assert_eq!(0x400454D9, TUNSETQUEUE());
        assert_eq!(0xC004AE02, KVM_GET_MSR_INDEX_LIST());
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Debug};
use std::cell::Cell;
use std::io::Read;
use std::io;
use nom;

const DEFAULT_BUF_SIZE: usize = 8 * 1024;

pub trait StreamBuf<O> {
    fn fill(&mut self, min_count: usize) -> Result<(), io::Error>;
    fn recycle(&mut self);
    fn consume(&mut self, count: usize);
    fn data<'b>(&'b self) -> &'b[O];
    fn needed(&self) -> Option<nom::Needed>;
    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [O], E>> where
        O: 'b, C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E>;

    fn fill_apply<'b, C, CO, E>(&'b mut self, combinator: C) -> Result<Option<CO>, FillApplyError<&'b [O], E>> where
        C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E> {

        match self.needed() {
            Some(nom::Needed::Size(bytes)) => try!(self.fill(bytes)),
            Some(nom::Needed::Unknown) => try!(self.fill(1)),
            None => ()
        }

        Ok(try!(self.apply(combinator)))
    }
}

#[derive(Debug)]
pub enum FillApplyError<I, E> {
    Io(io::Error),
    Parser(nom::Err<I, E>),
}

impl<I, E> From<io::Error> for FillApplyError<I, E> {
    fn from(e: io::Error) -> FillApplyError<I, E> {
        FillApplyError::Io(e)
    }
}

impl<I, E> From<nom::Err<I, E>> for FillApplyError<I, E> {
    fn from(e: nom::Err<I, E>) -> FillApplyError<I, E> {
        FillApplyError::Parser(e)
    }
}

impl<I, E> Display for FillApplyError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FillApplyError::Io(ref e) => write!(f, "Failed to read data (IO error): {}", e),
            &FillApplyError::Parser(ref e) => write!(f, "Failed to parse data (parser error): {}", e),
        }
    }
}

pub struct ReadStreamBuf<R: Read> {
    reader: R,
    //TODO: alignment?
    buf: Vec<u8>,
    cap: usize,
    needed: Cell<Option<nom::Needed>>,
    offset: Cell<usize>,
}

impl<R: Read> ReadStreamBuf<R> {
    pub fn new(reader: R) -> ReadStreamBuf<R> {
        ReadStreamBuf::with_capacity(reader, DEFAULT_BUF_SIZE)
    }

    pub fn with_capacity(reader: R, cap: usize) -> ReadStreamBuf<R> {
        ReadStreamBuf {
            reader: reader,
            buf: Vec::with_capacity(cap),
            cap: cap,
            needed: Cell::new(Some(nom::Needed::Unknown)),
            offset: Cell::new(0),
        }
    }
}

impl<R: Read> StreamBuf<u8> for ReadStreamBuf<R> {
    fn fill(&mut self, min_bytes: usize) -> Result<(), io::Error> {
        let len = self.buf.len();
        let have = len - self.offset.get();

        if have >= min_bytes {
            return Ok(())
        }

        let needed = min_bytes - have;

        if min_bytes > self.cap {
            panic!("Cannot fit {} B of data in {} B buffer", min_bytes, self.cap)
        }
        if len + needed > self.cap {
            self.recycle();
            assert_eq!(self.offset.get(), 0);
            assert_eq!(self.buf.len(), have);
            return self.fill(min_bytes)
        }

        self.buf.resize(self.cap, 0);
        //trace!("fill needed: {}", needed);
        //trace!("buf write: {}..{} ({}); have: {} will have: {}", len, len + needed, self.buf[len..len + needed].len(), have, have + needed);
        if let Err(err) = self.reader.read_exact(&mut self.buf[len..len + needed]) {
            self.buf.resize(len, 0);
            return Err(err);
        }

        // Try to read to the end of the buffer if we can
        match self.reader.read(&mut self.buf[len + needed..self.cap]) {
            Err(err) => {
                self.buf.resize(len + needed, 0);
                return Err(err)
            },
            Ok(bytes_read) => {
                self.buf.resize(len + needed + bytes_read, 0);
            }
        }

        //trace!("buf have: {:?}", self.data());
        Ok(())
    }

    fn recycle(&mut self) {
        if self.offset.get() == 0 {
            return
        }
        self.buf = self.buf.split_off(self.offset.get());
        self.offset.set(0);
    }

    fn consume(&mut self, bytes: usize) {
        let len = self.buf.len();

        let consume = if self.offset.get() + bytes > len {
            len - self.offset.get()
        } else {
            bytes
        };
        self.offset.set(self.offset.get() + consume);
    }

    fn data<'b>(&'b self) -> &'b[u8] {
        &self.buf[self.offset.get()..self.buf.len()]
    }

    fn needed(&self) -> Option<nom::Needed> {
        self.needed.get().clone()
    }

    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [u8], E>> where
        C: Fn(&'b [u8]) -> nom::IResult<&'b [u8], CO, E> {
        let data = self.data();
        match combinator(data) {
            nom::IResult::Done(left, out) => {
                let consumed = data.len() - left.len();
                //trace!("done: consumed: {}", consumed);

                // Move the offset
                self.offset.set(self.offset.get() + consumed);
                // We don't know how much we will need now
                self.needed.set(None);
                Ok(Some(out))
            },
            nom::IResult::Error(err) => Err(err),
            nom::IResult::Incomplete(needed) => {
                //trace!("incomplete: needed: {:?}", needed);
                self.needed.set(Some(needed));
                Ok(None)
            }
        }
    }
}

#[cfg(test)]
mod resd_stream_buf_tests {
    use super::StreamBuf;
    use super::ReadStreamBuf;
    use nom::{IResult, Needed};
    use std::io::Cursor;

    fn subject(data: Vec<u8>) -> ReadStreamBuf<Cursor<Vec<u8>>> {
        ReadStreamBuf::new(Cursor::new(data))
    }

    fn subject_with_default_data() -> ReadStreamBuf<Cursor<Vec<u8>>> {
        subject(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    }

    #[test]
    fn reading() {
        let mut rsb = subject_with_default_data();
        assert_eq!(rsb.data(), [].as_ref());

        // fill reads as much as it can non-blocking
        // TODO: how to test blocking streaming?
        rsb.fill(3).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9].as_ref());
    }

    #[test]
    fn recycle() {
        let mut rsb = subject_with_default_data();

        //TODO: this test does nothing...
        rsb.fill(10).unwrap();
        rsb.recycle();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn consume() {
        let mut rsb = subject_with_default_data();

        rsb.fill(10).unwrap();
        rsb.consume(8);
        assert_eq!(rsb.data(), [8, 9].as_ref());
    }

    #[test]
    fn consume_more_than_we_have() {
        let mut rsb = subject_with_default_data();

        rsb.consume(3);
        rsb.fill(10).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn apply_function() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
    }

    #[test]
    fn apply_should_consume() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(1));
    }

    #[test]
    fn apply_converted_macro() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(closure!(tag!([0, 1]))).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_closure() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(|i| tag!(i, [0, 1])).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_custom_fuction_with_refs() {
        let mut rsb = subject_with_default_data();
        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        rsb.fill(3).unwrap();
        assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
    }

    #[test]
    fn needed_with_apply() {
        let mut rsb = subject_with_default_data();

        fn comb<'a>(input: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> {
            tag!(input, [0, 1, 2])
        }

        assert!(rsb.apply(comb).unwrap().is_none());

        let needed = rsb.needed().unwrap();
        assert_eq!(needed, Needed::Size(3));

        if let Needed::Size(bytes) = needed {
            rsb.fill(bytes).unwrap();
            assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        }
    }

    #[test]
    fn fill_apply() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        //assert_eq!(rsb.fill_apply(comb).unwrap(), None);
        assert_eq!(rsb.fill_apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        //assert_eq!(rsb.fill_apply(be_u8).unwrap(), None);
        assert_eq!(rsb.fill_apply(be_u8).unwrap(), Some(3));
    }

    #[test]
    #[should_panic(expected = "Cannot fit 8193 B of data in 8192 B buffer")]
    fn fill_over_buf() {
        let mut rsb = subject_with_default_data();
        rsb.fill(super::DEFAULT_BUF_SIZE + 1).ok();
    }
}
<commit_msg>cleanup<commit_after>use std::fmt::{self, Display, Debug};
use std::cell::Cell;
use std::io::Read;
use std::io;
use nom;

const DEFAULT_BUF_SIZE: usize = 8 * 1024;

pub trait StreamBuf<O> {
    fn fill(&mut self, min_count: usize) -> Result<(), io::Error>;
    fn recycle(&mut self);
    fn consume(&mut self, count: usize);
    fn data<'b>(&'b self) -> &'b[O];
    fn needed(&self) -> Option<nom::Needed>;
    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [O], E>> where
        O: 'b, C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E>;

    fn fill_apply<'b, C, CO, E>(&'b mut self, combinator: C) -> Result<Option<CO>, FillApplyError<&'b [O], E>> where
        C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E> {

        match self.needed() {
            Some(nom::Needed::Size(bytes)) => try!(self.fill(bytes)),
            Some(nom::Needed::Unknown) => try!(self.fill(1)),
            None => ()
        }

        Ok(try!(self.apply(combinator)))
    }
}

#[derive(Debug)]
pub enum FillApplyError<I, E> {
    Io(io::Error),
    Parser(nom::Err<I, E>),
}

impl<I, E> From<io::Error> for FillApplyError<I, E> {
    fn from(e: io::Error) -> FillApplyError<I, E> {
        FillApplyError::Io(e)
    }
}

impl<I, E> From<nom::Err<I, E>> for FillApplyError<I, E> {
    fn from(e: nom::Err<I, E>) -> FillApplyError<I, E> {
        FillApplyError::Parser(e)
    }
}

impl<I, E> Display for FillApplyError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FillApplyError::Io(ref e) => write!(f, "Failed to read data (IO error): {}", e),
            &FillApplyError::Parser(ref e) => write!(f, "Failed to parse data (parser error): {}", e),
        }
    }
}

pub struct ReadStreamBuf<R: Read> {
    reader: R,
    //TODO: alignment?
    buf: Vec<u8>,
    cap: usize,
    needed: Cell<Option<nom::Needed>>,
    offset: Cell<usize>,
}

impl<R: Read> ReadStreamBuf<R> {
    pub fn new(reader: R) -> ReadStreamBuf<R> {
        ReadStreamBuf::with_capacity(reader, DEFAULT_BUF_SIZE)
    }

    pub fn with_capacity(reader: R, cap: usize) -> ReadStreamBuf<R> {
        ReadStreamBuf {
            reader: reader,
            buf: Vec::with_capacity(cap),
            cap: cap,
            needed: Cell::new(Some(nom::Needed::Unknown)),
            offset: Cell::new(0),
        }
    }
}

impl<R: Read> StreamBuf<u8> for ReadStreamBuf<R> {
    fn fill(&mut self, min_bytes: usize) -> Result<(), io::Error> {
        let len = self.buf.len();
        let have = len - self.offset.get();

        if have >= min_bytes {
            return Ok(())
        }

        let needed = min_bytes - have;

        if min_bytes > self.cap {
            panic!("Cannot fit {} B of data in {} B buffer", min_bytes, self.cap)
        }
        if len + needed > self.cap {
            self.recycle();
            assert_eq!(self.offset.get(), 0);
            assert_eq!(self.buf.len(), have);
            return self.fill(min_bytes)
        }

        self.buf.resize(self.cap, 0);
        //trace!("fill needed: {}", needed);
        //trace!("buf write: {}..{} ({}); have: {} will have: {}", len, len + needed, self.buf[len..len + needed].len(), have, have + needed);
        if let Err(err) = self.reader.read_exact(&mut self.buf[len..len + needed]) {
            self.buf.resize(len, 0);
            return Err(err);
        }

        // Try to read to the end of the buffer if we can
        match self.reader.read(&mut self.buf[len + needed..self.cap]) {
            Err(err) => {
                self.buf.resize(len + needed, 0);
                return Err(err)
            },
            Ok(bytes_read) => {
                self.buf.resize(len + needed + bytes_read, 0);
            }
        }

        //trace!("buf have: {:?}", self.data());
        Ok(())
    }

    fn recycle(&mut self) {
        if self.offset.get() == 0 {
            return
        }
        self.buf = self.buf.split_off(self.offset.get());
        self.offset.set(0);
    }

    fn consume(&mut self, bytes: usize) {
        let len = self.buf.len();

        let consume = if self.offset.get() + bytes > len {
            len - self.offset.get()
        } else {
            bytes
        };
        self.offset.set(self.offset.get() + consume);
    }

    fn data<'b>(&'b self) -> &'b[u8] {
        &self.buf[self.offset.get()..self.buf.len()]
    }

    fn needed(&self) -> Option<nom::Needed> {
        self.needed.get().clone()
    }

    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [u8], E>> where
        C: Fn(&'b [u8]) -> nom::IResult<&'b [u8], CO, E> {
        let data = self.data();
        match combinator(data) {
            nom::IResult::Done(left, out) => {
                let consumed = data.len() - left.len();
                //trace!("done: consumed: {}", consumed);

                // Move the offset
                self.offset.set(self.offset.get() + consumed);
                // We don't know how much we will need now
                self.needed.set(None);
                Ok(Some(out))
            },
            nom::IResult::Error(err) => Err(err),
            nom::IResult::Incomplete(needed) => {
                //trace!("incomplete: needed: {:?}", needed);
                self.needed.set(Some(needed));
                Ok(None)
            }
        }
    }
}

#[cfg(test)]
mod resd_stream_buf_tests {
    use super::StreamBuf;
    use super::ReadStreamBuf;
    use nom::{IResult, Needed};
    use std::io::Cursor;

    fn subject(data: Vec<u8>) -> ReadStreamBuf<Cursor<Vec<u8>>> {
        ReadStreamBuf::new(Cursor::new(data))
    }

    fn subject_with_default_data() -> ReadStreamBuf<Cursor<Vec<u8>>> {
        subject(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    }

    #[test]
    fn reading() {
        let mut rsb = subject_with_default_data();
        assert_eq!(rsb.data(), [].as_ref());

        // fill reads as much as it can non-blocking
        // TODO: how to test blocking streaming?
        rsb.fill(3).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9].as_ref());
    }

    #[test]
    fn recycle() {
        let mut rsb = subject_with_default_data();

        //TODO: this test does nothing...
        rsb.fill(10).unwrap();
        rsb.recycle();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn consume() {
        let mut rsb = subject_with_default_data();

        rsb.fill(10).unwrap();
        rsb.consume(8);
        assert_eq!(rsb.data(), [8, 9].as_ref());
    }

    #[test]
    fn consume_more_than_we_have() {
        let mut rsb = subject_with_default_data();

        rsb.consume(3);
        rsb.fill(10).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn apply_function() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
    }

    #[test]
    fn apply_should_consume() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(1));
    }

    #[test]
    fn apply_converted_macro() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(closure!(tag!([0, 1]))).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_closure() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(|i| tag!(i, [0, 1])).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_custom_fuction_with_refs() {
        let mut rsb = subject_with_default_data();
        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        rsb.fill(3).unwrap();
        assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
    }

    #[test]
    fn needed_with_apply() {
        let mut rsb = subject_with_default_data();

        fn comb<'a>(input: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> {
            tag!(input, [0, 1, 2])
        }

        assert!(rsb.apply(comb).unwrap().is_none());

        let needed = rsb.needed().unwrap();
        assert_eq!(needed, Needed::Size(3));

        if let Needed::Size(bytes) = needed {
            rsb.fill(bytes).unwrap();
            assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        }
    }

    #[test]
    fn fill_apply() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        //TODO: test None scenario

        rsb.fill(10).unwrap();
        assert_eq!(rsb.fill_apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        assert_eq!(rsb.fill_apply(be_u8).unwrap(), Some(3));
    }

    #[test]
    #[should_panic(expected = "Cannot fit 8193 B of data in 8192 B buffer")]
    fn fill_over_buf() {
        let mut rsb = subject_with_default_data();
        rsb.fill(super::DEFAULT_BUF_SIZE + 1).ok();
    }
}
<|endoftext|>