<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Misc low level stuff

use cast;
use cmp::{Eq, Ord};
use gc;
use io;
use libc;
use libc::{c_void, c_char, size_t};
use repr;
use str;

pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void);

// Corresponds to runtime type_desc type
pub struct TypeDesc {
    size: uint,
    align: uint,
    take_glue: uint,
    drop_glue: uint,
    free_glue: uint
    // Remaining fields not listed
}

/// The representation of a Rust closure
pub struct Closure {
    code: *(),
    env: *(),
}

pub mod rusti {
    #[abi = "rust-intrinsic"]
    pub extern "rust-intrinsic" {
        fn get_tydesc<T>() -> *();
        fn size_of<T>() -> uint;
        fn pref_align_of<T>() -> uint;
        fn min_align_of<T>() -> uint;
    }
}

pub mod rustrt {
    use libc::{c_char, size_t};

    pub extern {
        #[rust_stack]
        unsafe fn rust_upcall_fail(expr: *c_char,
                                   file: *c_char,
                                   line: size_t);
    }
}

/// Compares contents of two pointers using the default method.
/// Equivalent to `*x1 == *x2`.  Useful for hashtables.
pub fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
    *x1 == *x2
}

pub fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 < *x2
}

pub fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 <= *x2
}

/**
 * Returns a pointer to a type descriptor.
 *
 * Useful for calling certain function in the Rust runtime or otherwise
 * performing dark magick.
 */
#[inline(always)]
pub fn get_type_desc<T>() -> *TypeDesc {
    unsafe { rusti::get_tydesc::<T>() as *TypeDesc }
}

/// Returns the size of a type
#[inline(always)]
pub fn size_of<T>() -> uint {
    unsafe { rusti::size_of::<T>() }
}

/**
 * Returns the size of a type, or 1 if the actual size is zero.
 *
 * Useful for building structures containing variable-length arrays.
 */
#[inline(always)]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/**
 * Returns the ABI-required minimum alignment of a type
 *
 * This is the alignment used for struct fields. It may be smaller
 * than the preferred alignment.
 */
#[inline(always)]
pub fn min_align_of<T>() -> uint {
    unsafe { rusti::min_align_of::<T>() }
}

/// Returns the preferred alignment of a type
#[inline(always)]
pub fn pref_align_of<T>() -> uint {
    unsafe { rusti::pref_align_of::<T>() }
}

/// Returns the refcount of a shared box (as just before calling this)
#[inline(always)]
pub fn refcount<T>(t: @T) -> uint {
    unsafe {
        let ref_ptr: *uint = cast::reinterpret_cast(&t);
        *ref_ptr - 1
    }
}

pub fn log_str<T>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        repr::write_repr(wr, t)
    }
}

/** Initiate task failure */
pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
    do str::as_buf(msg) |msg_buf, _msg_len| {
        do str::as_buf(file) |file_buf, _file_len| {
            unsafe {
                let msg_buf = cast::transmute(msg_buf);
                let file_buf = cast::transmute(file_buf);
                begin_unwind_(msg_buf, file_buf, line as libc::size_t)
            }
        }
    }
}

// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
    unsafe {
        gc::cleanup_stack_for_failure();
        rustrt::rust_upcall_fail(msg, file, line);
        cast::transmute(())
    }
}

pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
    let (msg, file) = (msg.to_owned(), file.to_owned());
    begin_unwind(~"assertion failed: " + msg, file, line)
}

#[cfg(test)]
mod tests {
    use cast;
    use sys::{Closure, pref_align_of, size_of, nonzero_size_of};

    #[test]
    fn size_of_basic() {
        assert!(size_of::<u8>() == 1u);
        assert!(size_of::<u16>() == 2u);
        assert!(size_of::<u32>() == 4u);
        assert!(size_of::<u64>() == 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert!(size_of::<uint>() == 4u);
        assert!(size_of::<*uint>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert!(size_of::<uint>() == 8u);
        assert!(size_of::<*uint>() == 8u);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert!(size_of::<Z>() == 0u);
        assert!(nonzero_size_of::<Z>() == 1u);
        assert!(nonzero_size_of::<uint>() == size_of::<uint>());
    }

    #[test]
    fn align_of_basic() {
        assert!(pref_align_of::<u8>() == 1u);
        assert!(pref_align_of::<u16>() == 2u);
        assert!(pref_align_of::<u32>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert!(pref_align_of::<uint>() == 4u);
        assert!(pref_align_of::<*uint>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert!(pref_align_of::<uint>() == 8u);
        assert!(pref_align_of::<*uint>() == 8u);
    }

    #[test]
    fn synthesize_closure() {
        unsafe {
            let x = 10;
            let f: &fn(int) -> int = |y| x + y;

            assert!(f(20) == 30);

            let original_closure: Closure = cast::transmute(f);

            let actual_function_pointer = original_closure.code;
            let environment = original_closure.env;

            let new_closure = Closure {
                code: actual_function_pointer,
                env: environment
            };

            let new_f: &fn(int) -> int = cast::transmute(new_closure);
            assert!(new_f(20) == 30);
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>auto merge of #5970 : huonw/rust/core-sys-size_of-val, r=pcwalton<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Misc low level stuff

use cast;
use cmp::{Eq, Ord};
use gc;
use io;
use libc;
use libc::{c_void, c_char, size_t};
use repr;
use str;

pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void);

// Corresponds to runtime type_desc type
pub struct TypeDesc {
    size: uint,
    align: uint,
    take_glue: uint,
    drop_glue: uint,
    free_glue: uint
    // Remaining fields not listed
}

/// The representation of a Rust closure
pub struct Closure {
    code: *(),
    env: *(),
}

pub mod rusti {
    #[abi = "rust-intrinsic"]
    pub extern "rust-intrinsic" {
        fn get_tydesc<T>() -> *();
        fn size_of<T>() -> uint;
        fn pref_align_of<T>() -> uint;
        fn min_align_of<T>() -> uint;
    }
}

pub mod rustrt {
    use libc::{c_char, size_t};

    pub extern {
        #[rust_stack]
        unsafe fn rust_upcall_fail(expr: *c_char,
                                   file: *c_char,
                                   line: size_t);
    }
}

/// Compares contents of two pointers using the default method.
/// Equivalent to `*x1 == *x2`.  Useful for hashtables.
pub fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
    *x1 == *x2
}

pub fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 < *x2
}

pub fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 <= *x2
}

/**
 * Returns a pointer to a type descriptor.
 *
 * Useful for calling certain function in the Rust runtime or otherwise
 * performing dark magick.
 */
#[inline(always)]
pub fn get_type_desc<T>() -> *TypeDesc {
    unsafe { rusti::get_tydesc::<T>() as *TypeDesc }
}

/// Returns a pointer to a type descriptor.
#[inline(always)]
pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc {
    get_type_desc::<T>()
}

/// Returns the size of a type
#[inline(always)]
pub fn size_of<T>() -> uint {
    unsafe { rusti::size_of::<T>() }
}

/// Returns the size of the type that `_val` points to
#[inline(always)]
pub fn size_of_val<T>(_val: &T) -> uint {
    size_of::<T>()
}

/**
 * Returns the size of a type, or 1 if the actual size is zero.
 *
 * Useful for building structures containing variable-length arrays.
 */
#[inline(always)]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/// Returns the size of the type of the value that `_val` points to
#[inline(always)]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
    nonzero_size_of::<T>()
}

/**
 * Returns the ABI-required minimum alignment of a type
 *
 * This is the alignment used for struct fields. It may be smaller
 * than the preferred alignment.
 */
#[inline(always)]
pub fn min_align_of<T>() -> uint {
    unsafe { rusti::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn min_align_of_val<T>(_val: &T) -> uint {
    min_align_of::<T>()
}

/// Returns the preferred alignment of a type
#[inline(always)]
pub fn pref_align_of<T>() -> uint {
    unsafe { rusti::pref_align_of::<T>() }
}

/// Returns the preferred alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn pref_align_of_val<T>(_val: &T) -> uint {
    pref_align_of::<T>()
}

/// Returns the refcount of a shared box (as just before calling this)
#[inline(always)]
pub fn refcount<T>(t: @T) -> uint {
    unsafe {
        let ref_ptr: *uint = cast::reinterpret_cast(&t);
        *ref_ptr - 1
    }
}

pub fn log_str<T>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        repr::write_repr(wr, t)
    }
}

/** Initiate task failure */
pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
    do str::as_buf(msg) |msg_buf, _msg_len| {
        do str::as_buf(file) |file_buf, _file_len| {
            unsafe {
                let msg_buf = cast::transmute(msg_buf);
                let file_buf = cast::transmute(file_buf);
                begin_unwind_(msg_buf, file_buf, line as libc::size_t)
            }
        }
    }
}

// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
    unsafe {
        gc::cleanup_stack_for_failure();
        rustrt::rust_upcall_fail(msg, file, line);
        cast::transmute(())
    }
}

pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
    let (msg, file) = (msg.to_owned(), file.to_owned());
    begin_unwind(~"assertion failed: " + msg, file, line)
}

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

    #[test]
    fn size_of_basic() {
        assert!(size_of::<u8>() == 1u);
        assert!(size_of::<u16>() == 2u);
        assert!(size_of::<u32>() == 4u);
        assert!(size_of::<u64>() == 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert!(size_of::<uint>() == 4u);
        assert!(size_of::<*uint>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert!(size_of::<uint>() == 8u);
        assert!(size_of::<*uint>() == 8u);
    }

    #[test]
    fn size_of_val_basic() {
        assert_eq!(size_of_val(&1u8), 1);
        assert_eq!(size_of_val(&1u16), 2);
        assert_eq!(size_of_val(&1u32), 4);
        assert_eq!(size_of_val(&1u64), 8);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert!(size_of::<Z>() == 0u);
        assert!(nonzero_size_of::<Z>() == 1u);
        assert!(nonzero_size_of::<uint>() == size_of::<uint>());
    }

    #[test]
    fn nonzero_size_of_val_basic() {
        let z = [0u8, ..0];
        assert_eq!(size_of_val(&z), 0u);
        assert_eq!(nonzero_size_of_val(&z), 1u);
        assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
    }

    #[test]
    fn align_of_basic() {
        assert!(pref_align_of::<u8>() == 1u);
        assert!(pref_align_of::<u16>() == 2u);
        assert!(pref_align_of::<u32>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert!(pref_align_of::<uint>() == 4u);
        assert!(pref_align_of::<*uint>() == 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert!(pref_align_of::<uint>() == 8u);
        assert!(pref_align_of::<*uint>() == 8u);
    }

    #[test]
    fn align_of_val_basic() {
        assert_eq!(pref_align_of_val(&1u8), 1u);
        assert_eq!(pref_align_of_val(&1u16), 2u);
        assert_eq!(pref_align_of_val(&1u32), 4u);
    }

    #[test]
    fn synthesize_closure() {
        unsafe {
            let x = 10;
            let f: &fn(int) -> int = |y| x + y;

            assert!(f(20) == 30);

            let original_closure: Closure = cast::transmute(f);

            let actual_function_pointer = original_closure.code;
            let environment = original_closure.env;

            let new_closure = Closure {
                code: actual_function_pointer,
                env: environment
            };

            let new_f: &fn(int) -> int = cast::transmute(new_closure);
            assert!(new_f(20) == 30);
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(missing_doc)];

/** Task-local reference counted smart pointers

Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to
prevent cycles.

Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a
cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.

*/

use core::prelude::*;

use core::cast;
use core::libc::{c_void, size_t, malloc, free};
use core::ptr;
use core::sys;
use core::unstable::intrinsics;

struct RcBox<T> {
    value: T,
    count: uint
}

/// Immutable reference counted pointer type
#[non_owned]
pub struct Rc<T> {
    priv ptr: *mut RcBox<T>,
}

impl<T> Rc<T> {
    unsafe fn new(value: T) -> Rc<T> {
        let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
        assert!(!ptr::is_null(ptr));
        intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
        Rc{ptr: ptr}
    }
}

// FIXME: #6516: should be a static method
pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> {
    unsafe { Rc::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_from_const<T: Const>(value: T) -> Rc<T> {
    unsafe { Rc::new(value) }
}

impl<T> Rc<T> {
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
    }
}

#[unsafe_destructor]
impl<T> Drop for Rc<T> {
    fn drop(&self) {
        unsafe {
            if self.ptr.is_not_null() {
                (*self.ptr).count -= 1;
                if (*self.ptr).count == 0 {
                    ptr::replace_ptr(self.ptr, intrinsics::uninit());
                    free(self.ptr as *c_void)
                }
            }
        }
    }
}

impl<T> Clone for Rc<T> {
    /// Return a shallow copy of the reference counted pointer.
    #[inline]
    fn clone(&self) -> Rc<T> {
        unsafe {
            (*self.ptr).count += 1;
            Rc{ptr: self.ptr}
        }
    }
}

impl<T: DeepClone> DeepClone for Rc<T> {
    /// Return a deep copy of the reference counted pointer.
    #[inline]
    fn deep_clone(&self) -> Rc<T> {
        unsafe { Rc::new(self.borrow().deep_clone()) }
    }
}

#[cfg(test)]
mod test_rc {
    use super::*;
    use core::cell::Cell;

    #[test]
    fn test_clone() {
        let x = rc_from_owned(Cell::new(5));
        let y = x.clone();
        do x.borrow().with_mut_ref |inner| {
            *inner = 20;
        }
        assert_eq!(y.borrow().take(), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = rc_from_owned(Cell::new(5));
        let y = x.deep_clone();
        do x.borrow().with_mut_ref |inner| {
            *inner = 20;
        }
        assert_eq!(y.borrow().take(), 5);
    }

    #[test]
    fn test_simple() {
        let x = rc_from_const(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = rc_from_const(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_destructor() {
        let x = rc_from_owned(~5);
        assert_eq!(**x.borrow(), 5);
    }
}

#[abi = "rust-intrinsic"]
extern "rust-intrinsic" {
    fn init<T>() -> T;
    fn uninit<T>() -> T;
}

#[deriving(Eq)]
enum Borrow {
    Mutable,
    Immutable,
    Nothing
}

struct RcMutBox<T> {
    value: T,
    count: uint,
    borrow: Borrow
}

/// Mutable reference counted pointer type
#[non_owned]
#[mutable]
pub struct RcMut<T> {
    priv ptr: *mut RcMutBox<T>,
}

impl<T> RcMut<T> {
    unsafe fn new(value: T) -> RcMut<T> {
        let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
        assert!(!ptr::is_null(ptr));
        intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
        RcMut{ptr: ptr}
    }
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> {
    unsafe { RcMut::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> {
    unsafe { RcMut::new(value) }
}

impl<T> RcMut<T> {
    /// Fails if there is already a mutable borrow of the box
    #[inline]
    pub fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
        unsafe {
            assert!((*self.ptr).borrow != Mutable);
            let previous = (*self.ptr).borrow;
            (*self.ptr).borrow = Immutable;
            let res = f(&(*self.ptr).value);
            (*self.ptr).borrow = previous;
            res
        }
    }

    /// Fails if there is already a mutable or immutable borrow of the box
    #[inline]
    pub fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
        unsafe {
            assert_eq!((*self.ptr).borrow, Nothing);
            (*self.ptr).borrow = Mutable;
            let res = f(&mut (*self.ptr).value);
            (*self.ptr).borrow = Nothing;
            res
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for RcMut<T> {
    fn drop(&self) {
        unsafe {
            if self.ptr.is_not_null() {
                (*self.ptr).count -= 1;
                if (*self.ptr).count == 0 {
                    ptr::replace_ptr(self.ptr, uninit());
                    free(self.ptr as *c_void)
                }
            }
        }
    }
}

impl<T> Clone for RcMut<T> {
    /// Return a shallow copy of the reference counted pointer.
    #[inline]
    fn clone(&self) -> RcMut<T> {
        unsafe {
            (*self.ptr).count += 1;
            RcMut{ptr: self.ptr}
        }
    }
}

impl<T: DeepClone> DeepClone for RcMut<T> {
    /// Return a deep copy of the reference counted pointer.
    #[inline]
    fn deep_clone(&self) -> RcMut<T> {
        do self.with_borrow |x| {
            // FIXME: #6497: should avoid freeze (slow)
            unsafe { RcMut::new(x.deep_clone()) }
        }
    }
}

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

    #[test]
    fn test_clone() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();
        do x.with_mut_borrow |value| {
            *value = 20;
        }
        do y.with_borrow |value| {
            assert_eq!(*value, 20);
        }
    }

    #[test]
    fn test_deep_clone() {
        let x = rc_mut_from_const(5);
        let y = x.deep_clone();
        do x.with_mut_borrow |value| {
            *value = 20;
        }
        do y.with_borrow |value| {
            assert_eq!(*value, 5);
        }
    }

    #[test]
    fn borrow_many() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_borrow |a| {
            assert_eq!(*a, 5);
            do y.with_borrow |b| {
                assert_eq!(*b, 5);
                do x.with_borrow |c| {
                    assert_eq!(*c, 5);
                }
            }
        }
    }

    #[test]
    fn modify() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do y.with_mut_borrow |a| {
            assert_eq!(*a, 5);
            *a = 6;
        }

        do x.with_borrow |a| {
            assert_eq!(*a, 6);
        }
    }

    #[test]
    fn release_immutable() {
        let x = rc_mut_from_owned(5);
        do x.with_borrow |_| {}
        do x.with_mut_borrow |_| {}
    }

    #[test]
    fn release_mutable() {
        let x = rc_mut_from_const(5);
        do x.with_mut_borrow |_| {}
        do x.with_borrow |_| {}
    }

    #[test]
    #[should_fail]
    fn frozen() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_borrow |_| {
            do y.with_mut_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn mutable_dupe() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do x.with_mut_borrow |_| {
            do y.with_mut_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn mutable_freeze() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_mut_borrow |_| {
            do y.with_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn restore_freeze() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do x.with_borrow |_| {
            do x.with_borrow |_| {}
            do y.with_mut_borrow |_| {}
        }
    }
}
<commit_msg>rc: add missing `#[unsafe_no_drop_flag]`<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(missing_doc)];

/** Task-local reference counted smart pointers

Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to
prevent cycles.

Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a
cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.

*/

use core::prelude::*;

use core::cast;
use core::libc::{c_void, size_t, malloc, free};
use core::ptr;
use core::sys;
use core::unstable::intrinsics;

struct RcBox<T> {
    value: T,
    count: uint
}

/// Immutable reference counted pointer type
#[non_owned]
#[unsafe_no_drop_flag]
pub struct Rc<T> {
    priv ptr: *mut RcBox<T>,
}

impl<T> Rc<T> {
    unsafe fn new(value: T) -> Rc<T> {
        let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
        assert!(!ptr::is_null(ptr));
        intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
        Rc{ptr: ptr}
    }
}

// FIXME: #6516: should be a static method
pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> {
    unsafe { Rc::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_from_const<T: Const>(value: T) -> Rc<T> {
    unsafe { Rc::new(value) }
}

impl<T> Rc<T> {
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
    }
}

#[unsafe_destructor]
impl<T> Drop for Rc<T> {
    fn drop(&self) {
        unsafe {
            if self.ptr.is_not_null() {
                (*self.ptr).count -= 1;
                if (*self.ptr).count == 0 {
                    ptr::replace_ptr(self.ptr, intrinsics::uninit());
                    free(self.ptr as *c_void)
                }
            }
        }
    }
}

impl<T> Clone for Rc<T> {
    /// Return a shallow copy of the reference counted pointer.
    #[inline]
    fn clone(&self) -> Rc<T> {
        unsafe {
            (*self.ptr).count += 1;
            Rc{ptr: self.ptr}
        }
    }
}

impl<T: DeepClone> DeepClone for Rc<T> {
    /// Return a deep copy of the reference counted pointer.
    #[inline]
    fn deep_clone(&self) -> Rc<T> {
        unsafe { Rc::new(self.borrow().deep_clone()) }
    }
}

#[cfg(test)]
mod test_rc {
    use super::*;
    use core::cell::Cell;

    #[test]
    fn test_clone() {
        let x = rc_from_owned(Cell::new(5));
        let y = x.clone();
        do x.borrow().with_mut_ref |inner| {
            *inner = 20;
        }
        assert_eq!(y.borrow().take(), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = rc_from_owned(Cell::new(5));
        let y = x.deep_clone();
        do x.borrow().with_mut_ref |inner| {
            *inner = 20;
        }
        assert_eq!(y.borrow().take(), 5);
    }

    #[test]
    fn test_simple() {
        let x = rc_from_const(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = rc_from_const(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_destructor() {
        let x = rc_from_owned(~5);
        assert_eq!(**x.borrow(), 5);
    }
}

#[abi = "rust-intrinsic"]
extern "rust-intrinsic" {
    fn init<T>() -> T;
    fn uninit<T>() -> T;
}

#[deriving(Eq)]
enum Borrow {
    Mutable,
    Immutable,
    Nothing
}

struct RcMutBox<T> {
    value: T,
    count: uint,
    borrow: Borrow
}

/// Mutable reference counted pointer type
#[non_owned]
#[mutable]
#[unsafe_no_drop_flag]
pub struct RcMut<T> {
    priv ptr: *mut RcMutBox<T>,
}

impl<T> RcMut<T> {
    unsafe fn new(value: T) -> RcMut<T> {
        let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
        assert!(!ptr::is_null(ptr));
        intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
        RcMut{ptr: ptr}
    }
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> {
    unsafe { RcMut::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> {
    unsafe { RcMut::new(value) }
}

impl<T> RcMut<T> {
    /// Fails if there is already a mutable borrow of the box
    #[inline]
    pub fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
        unsafe {
            assert!((*self.ptr).borrow != Mutable);
            let previous = (*self.ptr).borrow;
            (*self.ptr).borrow = Immutable;
            let res = f(&(*self.ptr).value);
            (*self.ptr).borrow = previous;
            res
        }
    }

    /// Fails if there is already a mutable or immutable borrow of the box
    #[inline]
    pub fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
        unsafe {
            assert_eq!((*self.ptr).borrow, Nothing);
            (*self.ptr).borrow = Mutable;
            let res = f(&mut (*self.ptr).value);
            (*self.ptr).borrow = Nothing;
            res
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for RcMut<T> {
    fn drop(&self) {
        unsafe {
            if self.ptr.is_not_null() {
                (*self.ptr).count -= 1;
                if (*self.ptr).count == 0 {
                    ptr::replace_ptr(self.ptr, uninit());
                    free(self.ptr as *c_void)
                }
            }
        }
    }
}

impl<T> Clone for RcMut<T> {
    /// Return a shallow copy of the reference counted pointer.
    #[inline]
    fn clone(&self) -> RcMut<T> {
        unsafe {
            (*self.ptr).count += 1;
            RcMut{ptr: self.ptr}
        }
    }
}

impl<T: DeepClone> DeepClone for RcMut<T> {
    /// Return a deep copy of the reference counted pointer.
    #[inline]
    fn deep_clone(&self) -> RcMut<T> {
        do self.with_borrow |x| {
            // FIXME: #6497: should avoid freeze (slow)
            unsafe { RcMut::new(x.deep_clone()) }
        }
    }
}

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

    #[test]
    fn test_clone() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();
        do x.with_mut_borrow |value| {
            *value = 20;
        }
        do y.with_borrow |value| {
            assert_eq!(*value, 20);
        }
    }

    #[test]
    fn test_deep_clone() {
        let x = rc_mut_from_const(5);
        let y = x.deep_clone();
        do x.with_mut_borrow |value| {
            *value = 20;
        }
        do y.with_borrow |value| {
            assert_eq!(*value, 5);
        }
    }

    #[test]
    fn borrow_many() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_borrow |a| {
            assert_eq!(*a, 5);
            do y.with_borrow |b| {
                assert_eq!(*b, 5);
                do x.with_borrow |c| {
                    assert_eq!(*c, 5);
                }
            }
        }
    }

    #[test]
    fn modify() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do y.with_mut_borrow |a| {
            assert_eq!(*a, 5);
            *a = 6;
        }

        do x.with_borrow |a| {
            assert_eq!(*a, 6);
        }
    }

    #[test]
    fn release_immutable() {
        let x = rc_mut_from_owned(5);
        do x.with_borrow |_| {}
        do x.with_mut_borrow |_| {}
    }

    #[test]
    fn release_mutable() {
        let x = rc_mut_from_const(5);
        do x.with_mut_borrow |_| {}
        do x.with_borrow |_| {}
    }

    #[test]
    #[should_fail]
    fn frozen() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_borrow |_| {
            do y.with_mut_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn mutable_dupe() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do x.with_mut_borrow |_| {
            do y.with_mut_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn mutable_freeze() {
        let x = rc_mut_from_owned(5);
        let y = x.clone();

        do x.with_mut_borrow |_| {
            do y.with_borrow |_| {
            }
        }
    }

    #[test]
    #[should_fail]
    fn restore_freeze() {
        let x = rc_mut_from_const(5);
        let y = x.clone();

        do x.with_borrow |_| {
            do x.with_borrow |_| {}
            do y.with_mut_borrow |_| {}
        }
    }
}
<|endoftext|>


<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom};
use std::path::Path;

pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result<String> {
    let mut buf = String::with_capacity(size);
    file.seek(SeekFrom::Start(0))?;
    file.read_to_string(&mut buf)?;
    Ok(buf)
}

pub(crate) fn get_all_data<P: AsRef<Path>>(file_path: P, size: usize) -> io::Result<String> {
    let mut file = File::open(file_path.as_ref())?;
    get_all_data_from_file(&mut file, size)
}

#[allow(clippy::useless_conversion)]
pub(crate) fn realpath(original: &Path) -> std::path::PathBuf {
    use libc::{c_char, lstat, stat, S_IFLNK, S_IFMT};
    use std::fs;
    use std::mem::MaybeUninit;
    use std::path::PathBuf;

    fn and(x: u32, y: u32) -> u32 {
        x & y
    }

    // let ori = Path::new(original.to_str().unwrap());
    // Right now lstat on windows doesn't work quite well
    // if cfg!(windows) {
    //     return PathBuf::from(ori);
    // }
    let result = PathBuf::from(original);
    let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec();
    result_s.push(0);
    let mut buf = MaybeUninit::<stat>::uninit();
    unsafe {
        let res = lstat(result_s.as_ptr() as *const c_char, buf.as_mut_ptr());
        if res < 0 {
            PathBuf::new()
        } else {
            let buf = buf.assume_init();
            if and(buf.st_mode.into(), S_IFMT.into()) != S_IFLNK.into() {
                PathBuf::new()
            } else {
                match fs::read_link(&result) {
                    Ok(f) => f,
                    Err(_) => PathBuf::new(),
                }
            }
        }
    }
}
<commit_msg>Remove explicit cast type<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom};
use std::path::Path;

pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result<String> {
    let mut buf = String::with_capacity(size);
    file.seek(SeekFrom::Start(0))?;
    file.read_to_string(&mut buf)?;
    Ok(buf)
}

pub(crate) fn get_all_data<P: AsRef<Path>>(file_path: P, size: usize) -> io::Result<String> {
    let mut file = File::open(file_path.as_ref())?;
    get_all_data_from_file(&mut file, size)
}

#[allow(clippy::useless_conversion)]
pub(crate) fn realpath(original: &Path) -> std::path::PathBuf {
    use libc::{lstat, stat, S_IFLNK, S_IFMT};
    use std::fs;
    use std::mem::MaybeUninit;
    use std::path::PathBuf;

    fn and(x: u32, y: u32) -> u32 {
        x & y
    }

    // let ori = Path::new(original.to_str().unwrap());
    // Right now lstat on windows doesn't work quite well
    // if cfg!(windows) {
    //     return PathBuf::from(ori);
    // }
    let result = PathBuf::from(original);
    let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec();
    result_s.push(0);
    let mut buf = MaybeUninit::<stat>::uninit();
    unsafe {
        let res = lstat(result_s.as_ptr() as *const _, buf.as_mut_ptr());
        if res < 0 {
            PathBuf::new()
        } else {
            let buf = buf.assume_init();
            if and(buf.st_mode.into(), S_IFMT.into()) != S_IFLNK.into() {
                PathBuf::new()
            } else {
                match fs::read_link(&result) {
                    Ok(f) => f,
                    Err(_) => PathBuf::new(),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;

//Following semver here
#[derive(Clone, Debug, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    pub fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    pub fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    pub fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl ToString for Version {
    fn to_string(&self) -> String {
        String::from(self.major.to_string() + "." + &self.minor.to_string() + "." + &self.minor.to_string())
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<commit_msg>More details on error<commit_after>use std::error::Error;

//Following semver here
#[derive(Clone, Debug, PartialOrd, RustcDecodable, RustcEncodable)]
pub struct Version {
    pub major: u16,
    pub minor: u16,
    pub patch: u32
}

#[derive(Clone, RustcDecodable, RustcEncodable)]
pub struct Package {
    pub name: String,
    pub version: Version,
    pub crc32: u32,
    pub child_url: String, // Examples: /some_dir/something.exe
    pub dependencies: Vec<Package>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct PackageList {
    pub packages: Vec<Package>,
    pub parent_url: String, // Examples: https://www.foo.bar
    pub version: u32
}

impl Version {
    pub fn new() -> Version {
        Version {
            major: 0u16,
            minor: 0u16,
            patch: 0u32
        }
    }

    pub fn from(major: u16, minor: u16, patch: u32) -> Version {
        Version {
            major: major,
            minor: minor,
            patch: patch
        }
    }

    pub fn from_str(input: &str) -> Result<Version, String> {
        let versions: Vec<&str> = input.split('.').collect();
        if versions.len() == 3 {
            return Ok(
                Version {
                    major: get!(versions[0].parse::<u16>(),"Version: Unable to parse &str into u16 (major)"),
                    minor: get!(versions[1].parse::<u16>(),"Version: Unable to parse &str into u16 (minor)"),
                    patch: get!(versions[2].parse::<u32>(),"Version: Unable to parse &str into u32 (patch)")
                }
            )
        } else {
            return Err("Version::from_str() cannot parse provided input into Version: invalid input".to_string())
        }
    }
}

impl PartialEq for Version {
    fn eq(&self, other: &Version) -> bool {
        self.major == other.major &&
        self.minor == other.minor &&
        self.patch == other.patch
    }
}

impl ToString for Version {
    fn to_string(&self) -> String {
        String::from(self.major.to_string() + "." + &self.minor.to_string() + "." + &self.minor.to_string())
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self.name == other.name &&
        self.version == other.version &&
        self.crc32 == other.crc32 &&
        self.dependencies == other.dependencies
    }
}<|endoftext|>


<commit_before>use satyrs::cnf::{CNF, Assignment, PartialAssignment};
use std::io;

/**
 * DPLL Algorithm implementation
 * Start by cloning the cnf so we can modify the HashMap
 * Clone might be slow, consider a faster option
 * TODO: Consider using HashSet instead of Vec for the clauses
 */
#[allow(non_snake_case)]
pub fn DPLL(cnf: &CNF) -> Option<Assignment> {
    //let _cnf = cnf.clone();
    //println!("DPLL {:?}", _cnf);
    let mut p_assn = PartialAssignment::new(cnf.nvar as usize);
    match _dpll(cnf, &mut p_assn) {
        Some(assn) => Some(assn.assignment.iter().map(|a| {
            println!("WE HERE ");
            match *a {
                Some(a) => a,
                None => true,
            }
        }).collect()),
        None => None,
    }
}

#[allow(unused_variables)]
fn _dpll(cnf: &CNF, p_assn: &mut PartialAssignment) -> Option<PartialAssignment> {
    // If consistent set of literals, return True
    println!("{}\n{}",cnf,p_assn);
    if cnf.clauses.is_empty() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);  // Display optional value
    }

    // If contains an empty clause return None
    // TODO: Consider optimizing
    for clause in cnf.clauses.values() {
        if clause.len() == 0 {
            return None;
        }
    }

    // For every unit-clause, unit-propogate
    let mut _cnf = cnf.clone();
    for unit in cnf.units.iter() {
        let clause = cnf.clauses.get(&unit).expect("Clause not found");
        let lit : i32 = zeroth!(clause);
        p_assn.assign_literal(lit);
        _cnf.unit_propagate(*unit); // Only propogate in the clone
    } // FIXME: Unit propogate might be the end of things
    println!("After Prop! {}",_cnf);
    // Clone for the right
    let mut r_cnf = _cnf.clone();

    // TODO: For every pure literal, pure literal assign
    // Choose literal L for split
    //let literal: i32 = zeroth!(_cnf.clauses.values().next().unwrap());
    let literal = match _cnf.clauses.values().next() {
        Some(thing) => Some(zeroth!(thing)),
        None => None,
    };

    if literal.is_none() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);
    }
    let lit = literal.unwrap();
    println!("Split on {} ({})",lit,lit/2);
    // Propagate literal
    _cnf.propagate(lit);

    // Return DPLL with L and -L
    p_assn.assign_literal(lit);

    //let mut buffer = String::new();
    //let _ = io::stdin().read_line(&mut buffer);

    let left = _dpll(&_cnf, p_assn);
    if left.is_some() { return left; }
    p_assn.unassign_literal(lit);
    p_assn.assign_literal(lit ^ 1);
    r_cnf.propagate(lit^1);
    _dpll(&_cnf, p_assn)
}
<commit_msg>Check for empty clauses when unwrapping<commit_after>use satyrs::cnf::{CNF, Assignment, PartialAssignment};
use std::io;

/**
 * DPLL Algorithm implementation
 * Start by cloning the cnf so we can modify the HashMap
 * Clone might be slow, consider a faster option
 * TODO: Consider using HashSet instead of Vec for the clauses
 */
#[allow(non_snake_case)]
pub fn DPLL(cnf: &CNF) -> Option<Assignment> {
    //let _cnf = cnf.clone();
    //println!("DPLL {:?}", _cnf);
    let mut p_assn = PartialAssignment::new(cnf.nvar as usize);
    match _dpll(cnf, &mut p_assn) {
        Some(assn) => Some(assn.assignment.iter().map(|a| {
            println!("WE HERE ");
            match *a {
                Some(a) => a,
                None => true,
            }
        }).collect()),
        None => None,
    }
}

#[allow(unused_variables)]
fn _dpll(cnf: &CNF, p_assn: &mut PartialAssignment) -> Option<PartialAssignment> {
    // If consistent set of literals, return True
    println!("{}\n{}",cnf,p_assn);
    if cnf.clauses.is_empty() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);  // Display optional value
    }

    // If contains an empty clause return None
    // TODO: Consider optimizing
    for clause in cnf.clauses.values() {
        if clause.is_empty() {
            return None;
        }
    }

    // For every unit-clause, unit-propogate
    let mut _cnf = cnf.clone();
    for unit in cnf.units.iter() {
        // XXX: Previous versions of this for loop could have unit-propagated and
        // remove the unit clause here, so it's not necessary that the unit clause id
        // still exists in the clauses.
        if let Some(clause) = cnf.clauses.get(&unit) {
            // Then via unit propagation we've created an empty clause; no solution down this path
            if clause.is_empty() {
                return None;
            }
            let lit : i32 = zeroth!(clause);
            p_assn.assign_literal(lit);
            _cnf.unit_propagate(*unit); // Only propogate in the clone
        }
    } // FIXME: Unit propogate might be the end of things
    println!("After Prop! {}",_cnf);
    // Clone for the right
    let mut r_cnf = _cnf.clone();

    // TODO: For every pure literal, pure literal assign
    // Choose literal L for split
    //let literal: i32 = zeroth!(_cnf.clauses.values().next().unwrap());
    let literal = match _cnf.clauses.values().next() {
        Some(clause) => {
            if !clause.is_empty() {
                Some(zeroth!(clause))
            } else {
                return None;
            }
        }
        None => None,
    };

    if literal.is_none() {
        let _p_assn = p_assn.clone();
        return Some(_p_assn);
    }
    let lit = literal.unwrap();
    println!("Split on {} ({})",lit,lit/2);
    // Propagate literal
    _cnf.propagate(lit);

    // Return DPLL with L and -L
    p_assn.assign_literal(lit);

    //let mut buffer = String::new();
    //let _ = io::stdin().read_line(&mut buffer);

    let left = _dpll(&_cnf, p_assn);
    if left.is_some() { return left; }
    p_assn.unassign_literal(lit);
    p_assn.assign_literal(lit ^ 1);
    r_cnf.propagate(lit^1);
    _dpll(&_cnf, p_assn)
}
<|endoftext|>


<commit_before>use tokenizer::{TokenStream, Tokenizer, Token};
use std::collections::BTreeMap;
use Term;
use Document;
use Index;
use schema::FieldValue;
use schema::Value;
use tokenizer::BoxedTokenizer;

#[derive(Debug)]
pub struct HighlightSection {
    start: usize,
    stop: usize,
}

impl HighlightSection {
    fn new(start: usize, stop: usize) -> HighlightSection {
        HighlightSection {
            start,
            stop
        }
    }
}

#[derive(Debug)]
pub struct FragmentCandidate {
    score: f32,
    start_offset: usize,
    stop_offset: usize,
    num_chars: usize,
    highlighted: Vec<HighlightSection>,
}

impl FragmentCandidate {

    fn new(start_offset: usize, end_offset: usize) -> FragmentCandidate {
        FragmentCandidate{score: 0.0,
                          start_offset: start_offset,
                          stop_offset: end_offset,
                          num_chars: 0,
                          highlighted: vec![]}
    }

    /// Updates `score` and `highlighted` fields of the objects.
    ///
    ///
    fn calculate_score(&mut self, token: &Token, terms: &BTreeMap<String, f32>) {
        if let Some(score) = terms.get(&token.text.to_lowercase()) {
            self.score += score;
            self.highlighted.push(HighlightSection{start: token.offset_from,
                                                   stop: token.offset_to});
        }
    }
}

#[derive(Debug)]
pub struct Snippet {
    fragments: String,
    highlighted: Vec<HighlightSection>,
}

const HIGHLIGHTEN_PREFIX:&str = "";
const HIGHLIGHTEN_POSTFIX:&str = "";

impl Snippet {

    /// Returns a hignlightned html from the `Snippet`.
    pub fn to_html(&self) -> String {
        let mut html = String::new();
        let mut start_from: usize = 0;

        for item in self.highlighted.iter() {
            html.push_str(&self.fragments[start_from..item.start]);
            html.push_str(HIGHLIGHTEN_PREFIX);
            html.push_str(&self.fragments[item.start..item.stop]);
            html.push_str(HIGHLIGHTEN_POSTFIX);
            start_from = item.stop;
        }
        html.push_str(&self.fragments[start_from..self.fragments.len()]);
        html
    }
}

/// Returns a non-empty list of "good" fragments.
///
/// If no target term is within the text, then the function
/// should return an empty Vec.
///
/// If a target term is within the text, then the returned
/// list is required to be non-empty.
///
/// The returned list is non-empty and contain less
/// than 12 possibly overlapping fragments.
///
/// All fragments should contain at least one target term
/// and have at most `max_num_chars` characters (not bytes).
///
/// It is ok to emit non-overlapping fragments, for instance,
/// one short and one long containing the same keyword, in order
/// to leave optimization opportunity to the fragment selector
/// upstream.
///
/// Fragments must be valid in the sense that `&text[fragment.start..fragment.stop]`\
/// has to be a valid string.
fn search_fragments<'a>(
    tokenizer: Box<BoxedTokenizer>,
    text: &'a str,
    terms: BTreeMap<String, f32>,
    max_num_chars: usize) -> Vec<FragmentCandidate> {
    let mut token_stream = tokenizer.token_stream(text);
    let mut fragment = FragmentCandidate::new(0, 0);
    let mut fragments:Vec<FragmentCandidate> = vec![];

    loop {
        if let Some(next) = token_stream.next() {
            if (next.offset_to - fragment.start_offset) > max_num_chars {
                let txt = &text[fragment.start_offset..fragment.stop_offset];
                if fragment.score > 0.0 {
                    fragments.push(fragment)
                };
                fragment = FragmentCandidate::new(next.offset_from, next.offset_to);
            } else {
                fragment.calculate_score(next, &terms);
                fragment.stop_offset = next.offset_to;
            }
        } else {
            let txt = &text[fragment.start_offset..fragment.stop_offset];
            if fragment.score > 0.0 {
                fragments.push(fragment)
            };
            break;
        }
    }

    fragments
}

/// Returns a Snippet
///
/// Takes a vector of `FragmentCandidate`s and the text.
/// Figures out the best fragment from it and creates a snippet.
fn select_best_fragment_combination<'a>(fragments: Vec<FragmentCandidate>,
                                        text: &'a str,) -> Snippet {
    if let Some(init) = fragments.iter().nth(0) {
        let fragment = fragments.iter().skip(1).fold(init, |acc, item| {
            if item.score > init.score { item } else { init }
        });
        let fragment_text = &text[fragment.start_offset..fragment.stop_offset];
        let highlighted = fragment.highlighted.iter().map(|item| {
            HighlightSection{start: item.start-fragment.start_offset,
                             stop: item.stop-fragment.start_offset}
        }).collect();
        Snippet{fragments: fragment_text.to_owned(),
                highlighted: highlighted}
    } else {
        // when there no fragments to chose from,
        // for now create a empty snippet
        Snippet{fragments: String::new(),
                highlighted: vec![]}
    }
}

pub fn generate_snippet<'a>(
    doc: &'a [FieldValue],
    index: &Index,
    terms: Vec<Term>,
    max_num_chars: usize) -> Snippet {
    unimplemented!();
}

#[cfg(test)]
mod tests {
    use tokenizer::{SimpleTokenizer, box_tokenizer};
    use std::iter::Iterator;
    use std::collections::BTreeMap;
    use super::{search_fragments, select_best_fragment_combination};

    #[test]
    fn test_snippet() {
        let tokenizer = SimpleTokenizer;

        let t = box_tokenizer(tokenizer);

        let text = "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe, concurrent, practical language\", supporting functional and imperative-procedural paradigms. Rust is syntactically similar to C++[according to whom?], but its designers intend it to provide better memory safety while still maintaining performance.

Rust is free and open-source software, released under an MIT License, or Apache License 2.0. Its designers have refined the language through the experiences of writing the Servo web browser layout engine[14] and the Rust compiler. A large proportion of current commits to the project are from community members.[15]

Rust won first place for \"most loved programming language\" in the Stack Overflow Developer Survey in 2016, 2017, and 2018.
";

        let mut terms = BTreeMap::new();
        terms.insert(String::from("rust"), 1.0);
        terms.insert(String::from("language"), 0.9);

        let fragments = search_fragments(t, &text, terms, 100);
        assert_eq!(fragments.len(), 7);
        {
            let first = fragments.iter().nth(0).unwrap();
            assert_eq!(first.score, 1.9);
            assert_eq!(first.stop_offset, 89);
        }
        let snippet = select_best_fragment_combination(fragments, &text);
        assert_eq!(snippet.fragments, "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe".to_owned());
        assert_eq!(snippet.to_html(), "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe".to_owned())
    }
}
<commit_msg>compare against accumulator rather than init value<commit_after>use tokenizer::{TokenStream, Tokenizer, Token};
use std::collections::BTreeMap;
use Term;
use Document;
use Index;
use schema::FieldValue;
use schema::Value;
use tokenizer::BoxedTokenizer;

#[derive(Debug)]
pub struct HighlightSection {
    start: usize,
    stop: usize,
}

impl HighlightSection {
    fn new(start: usize, stop: usize) -> HighlightSection {
        HighlightSection {
            start,
            stop
        }
    }
}

#[derive(Debug)]
pub struct FragmentCandidate {
    score: f32,
    start_offset: usize,
    stop_offset: usize,
    num_chars: usize,
    highlighted: Vec<HighlightSection>,
}

impl FragmentCandidate {

    fn new(start_offset: usize, end_offset: usize) -> FragmentCandidate {
        FragmentCandidate{score: 0.0,
                          start_offset: start_offset,
                          stop_offset: end_offset,
                          num_chars: 0,
                          highlighted: vec![]}
    }

    /// Updates `score` and `highlighted` fields of the objects.
    ///
    ///
    fn calculate_score(&mut self, token: &Token, terms: &BTreeMap<String, f32>) {
        if let Some(score) = terms.get(&token.text.to_lowercase()) {
            self.score += score;
            self.highlighted.push(HighlightSection{start: token.offset_from,
                                                   stop: token.offset_to});
        }
    }
}

#[derive(Debug)]
pub struct Snippet {
    fragments: String,
    highlighted: Vec<HighlightSection>,
}

const HIGHLIGHTEN_PREFIX:&str = "";
const HIGHLIGHTEN_POSTFIX:&str = "";

impl Snippet {

    /// Returns a hignlightned html from the `Snippet`.
    pub fn to_html(&self) -> String {
        let mut html = String::new();
        let mut start_from: usize = 0;

        for item in self.highlighted.iter() {
            html.push_str(&self.fragments[start_from..item.start]);
            html.push_str(HIGHLIGHTEN_PREFIX);
            html.push_str(&self.fragments[item.start..item.stop]);
            html.push_str(HIGHLIGHTEN_POSTFIX);
            start_from = item.stop;
        }
        html.push_str(&self.fragments[start_from..self.fragments.len()]);
        html
    }
}

/// Returns a non-empty list of "good" fragments.
///
/// If no target term is within the text, then the function
/// should return an empty Vec.
///
/// If a target term is within the text, then the returned
/// list is required to be non-empty.
///
/// The returned list is non-empty and contain less
/// than 12 possibly overlapping fragments.
///
/// All fragments should contain at least one target term
/// and have at most `max_num_chars` characters (not bytes).
///
/// It is ok to emit non-overlapping fragments, for instance,
/// one short and one long containing the same keyword, in order
/// to leave optimization opportunity to the fragment selector
/// upstream.
///
/// Fragments must be valid in the sense that `&text[fragment.start..fragment.stop]`\
/// has to be a valid string.
fn search_fragments<'a>(
    tokenizer: Box<BoxedTokenizer>,
    text: &'a str,
    terms: BTreeMap<String, f32>,
    max_num_chars: usize) -> Vec<FragmentCandidate> {
    let mut token_stream = tokenizer.token_stream(text);
    let mut fragment = FragmentCandidate::new(0, 0);
    let mut fragments:Vec<FragmentCandidate> = vec![];

    loop {
        if let Some(next) = token_stream.next() {
            if (next.offset_to - fragment.start_offset) > max_num_chars {
                let txt = &text[fragment.start_offset..fragment.stop_offset];
                if fragment.score > 0.0 {
                    fragments.push(fragment)
                };
                fragment = FragmentCandidate::new(next.offset_from, next.offset_to);
            } else {
                fragment.calculate_score(next, &terms);
                fragment.stop_offset = next.offset_to;
            }
        } else {
            let txt = &text[fragment.start_offset..fragment.stop_offset];
            if fragment.score > 0.0 {
                fragments.push(fragment)
            };
            break;
        }
    }

    fragments
}

/// Returns a Snippet
///
/// Takes a vector of `FragmentCandidate`s and the text.
/// Figures out the best fragment from it and creates a snippet.
fn select_best_fragment_combination<'a>(fragments: Vec<FragmentCandidate>,
                                        text: &'a str,) -> Snippet {
    if let Some(init) = fragments.iter().nth(0) {
        let fragment = fragments.iter().skip(1).fold(init, |acc, item| {
            if item.score > acc.score { item } else { acc }
        });
        let fragment_text = &text[fragment.start_offset..fragment.stop_offset];
        let highlighted = fragment.highlighted.iter().map(|item| {
            HighlightSection{start: item.start-fragment.start_offset,
                             stop: item.stop-fragment.start_offset}
        }).collect();
        Snippet{fragments: fragment_text.to_owned(),
                highlighted: highlighted}
    } else {
        // when there no fragments to chose from,
        // for now create a empty snippet
        Snippet{fragments: String::new(),
                highlighted: vec![]}
    }
}

pub fn generate_snippet<'a>(
    doc: &'a [FieldValue],
    index: &Index,
    terms: Vec<Term>,
    max_num_chars: usize) -> Snippet {
    unimplemented!();
}

#[cfg(test)]
mod tests {
    use tokenizer::{SimpleTokenizer, box_tokenizer};
    use std::iter::Iterator;
    use std::collections::BTreeMap;
    use super::{search_fragments, select_best_fragment_combination};

    #[test]
    fn test_snippet() {
        let tokenizer = SimpleTokenizer;

        let t = box_tokenizer(tokenizer);

        let text = "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe, concurrent, practical language\", supporting functional and imperative-procedural paradigms. Rust is syntactically similar to C++[according to whom?], but its designers intend it to provide better memory safety while still maintaining performance.

Rust is free and open-source software, released under an MIT License, or Apache License 2.0. Its designers have refined the language through the experiences of writing the Servo web browser layout engine[14] and the Rust compiler. A large proportion of current commits to the project are from community members.[15]

Rust won first place for \"most loved programming language\" in the Stack Overflow Developer Survey in 2016, 2017, and 2018.
";

        let mut terms = BTreeMap::new();
        terms.insert(String::from("rust"), 1.0);
        terms.insert(String::from("language"), 0.9);

        let fragments = search_fragments(t, &text, terms, 100);
        assert_eq!(fragments.len(), 7);
        {
            let first = fragments.iter().nth(0).unwrap();
            assert_eq!(first.score, 1.9);
            assert_eq!(first.stop_offset, 89);
        }
        let snippet = select_best_fragment_combination(fragments, &text);
        assert_eq!(snippet.fragments, "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe".to_owned());
        assert_eq!(snippet.to_html(), "Rust is a systems programming language sponsored by Mozilla which describes it as a \"safe".to_owned())
    }
}
<|endoftext|>


<commit_before>extern crate uuid;
use self::uuid::Uuid;

use std::fs;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::process::Command;

use dsl::LpProblem;
use format::lp_format::*;
use solvers::{Status, SolverTrait};

pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
}

impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver {
            name: "Cbc".to_string(),
            command_name: "cbc".to_string(),
            temp_solution_file: format!("{}.sol", Uuid::new_v4().to_string()),
        }
    }
    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name,
            temp_solution_file: self.temp_solution_file.clone(),
        }
    }
    pub fn temp_solution_file(&self, temp_solution_file: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name: self.command_name.clone(),
            temp_solution_file,
        }
    }
    pub fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {
            let mut vars_value: HashMap<_, _> = HashMap::new();

            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);

            let status = if let Some(status_line) = buffer.split_whitespace().next() {
                match status_line.split_whitespace().next() {
                    Some("Optimal") => Status::Optimal,
                    // Infeasible status is either "Infeasible" or "Integer infeasible"
                    Some("Infeasible") | Some("Integer") => Status::Infeasible,
                    Some("Unbounded") => Status::Unbounded,
                    // "Stopped" can be "on time", "on iterations", "on difficulties" or "on ctrl-c"
                    Some("Stopped") => Status::SubOptimal,
                    _ => Status::NotSolved,
                }
            } else {
                return Err("Incorrect solution format".to_string());
            };
            for line in file.lines() {
                let l = line.unwrap();
                let mut result_line: Vec<_> = l.split_whitespace().collect();
                if result_line[0] == "**" {
                    result_line.remove(0);
                };
                if result_line.len() == 4 {
                    match result_line[2].parse::<f32>() {
                        Ok(n) => {
                            vars_value.insert(result_line[1].to_string(), n);
                        }
                        Err(e) => return Err(e.to_string()),
                    }
                } else {
                    return Err("Incorrect solution format".to_string());
                }
            }
            Ok((status, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            }
            Err(_) => return Err("Cannot open file".to_string()),
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;
    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String, f32>), String> {
        let file_model = &format!("{}.lp", problem.unique_name);

        match problem.write_lp(file_model) {
            Ok(_) => {
                let result = match Command::new(&self.command_name)
                    .arg(file_model)
                    .arg("solve")
                    .arg("solution")
                    .arg(&self.temp_solution_file)
                    .output()
                    {
                        Ok(r) => {
                            if r.status.success() {
                                self.read_solution()
                            } else {
                                Err(r.status.to_string())
                            }
                        }
                        Err(_) => Err(format!("Error running the {} solver", self.name)),
                    };
                let _ = fs::remove_file(&file_model);

                result
            }
            Err(e) => Err(e.to_string()),
        }
    }
}

<commit_msg>Allow setting threads and seconds for CBC<commit_after>extern crate uuid;
use self::uuid::Uuid;

use std::fs;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::process::Command;

use dsl::LpProblem;
use format::lp_format::*;
use solvers::{Status, SolverTrait};

pub struct CbcSolver {
    name: String,
    command_name: String,
    temp_solution_file: String,
    params: HashMap<String, String>,
}

impl CbcSolver {
    pub fn new() -> CbcSolver {
        CbcSolver {
            name: "Cbc".to_string(),
            command_name: "cbc".to_string(),
            temp_solution_file: format!("{}.sol", Uuid::new_v4().to_string()),
            params: Default::default(),
        }
    }

    pub fn command_name(&self, command_name: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name,
            temp_solution_file: self.temp_solution_file.clone(),
            params: self.params.clone(),
        }
    }

    pub fn temp_solution_file(&self, temp_solution_file: String) -> CbcSolver {
        CbcSolver {
            name: self.name.clone(),
            command_name: self.command_name.clone(),
            temp_solution_file,
            params: self.params.clone(),
        }
    }

    pub fn seconds(&self, seconds: f32) -> CbcSolver {
        self.add_param("seconds".to_owned(), seconds.to_string())
    }

    pub fn threads(&self, threads: u32) -> CbcSolver {
        self.add_param("threads".to_owned(), threads.to_string())
    }

    fn add_param(&self, name: String, value: String) -> CbcSolver {
        let mut new_params = self.params.clone();
        new_params.insert(name, value);

        CbcSolver {
            name: self.name.clone(),
            command_name: self.command_name.clone(),
            temp_solution_file: self.temp_solution_file.clone(),
            params: new_params,
        }
    }

    pub fn read_solution(&self) -> Result<(Status, HashMap<String, f32>), String> {
        fn read_specific_solution(f: &File) -> Result<(Status, HashMap<String, f32>), String> {
            let mut vars_value: HashMap<_, _> = HashMap::new();

            let mut file = BufReader::new(f);
            let mut buffer = String::new();
            let _ = file.read_line(&mut buffer);

            let status = if let Some(status_line) = buffer.split_whitespace().next() {
                match status_line.split_whitespace().next() {
                    Some("Optimal") => Status::Optimal,
                    // Infeasible status is either "Infeasible" or "Integer infeasible"
                    Some("Infeasible") | Some("Integer") => Status::Infeasible,
                    Some("Unbounded") => Status::Unbounded,
                    // "Stopped" can be "on time", "on iterations", "on difficulties" or "on ctrl-c"
                    Some("Stopped") => Status::SubOptimal,
                    _ => Status::NotSolved,
                }
            } else {
                return Err("Incorrect solution format".to_string());
            };
            for line in file.lines() {
                let l = line.unwrap();
                let mut result_line: Vec<_> = l.split_whitespace().collect();
                if result_line[0] == "**" {
                    result_line.remove(0);
                };
                if result_line.len() == 4 {
                    match result_line[2].parse::<f32>() {
                        Ok(n) => {
                            vars_value.insert(result_line[1].to_string(), n);
                        }
                        Err(e) => return Err(e.to_string()),
                    }
                } else {
                    return Err("Incorrect solution format".to_string());
                }
            }
            Ok((status, vars_value))
        }

        match File::open(&self.temp_solution_file) {
            Ok(f) => {
                let res = try!(read_specific_solution(&f));
                let _ = fs::remove_file(&self.temp_solution_file);
                Ok(res)
            }
            Err(_) => return Err("Cannot open file".to_string()),
        }
    }
}

impl SolverTrait for CbcSolver {
    type P = LpProblem;

    fn run(&self, problem: &Self::P) -> Result<(Status, HashMap<String, f32>), String> {
        let file_model = format!("{}.lp", problem.unique_name);
        problem.write_lp(&file_model).map_err(|e| e.to_string())?;

        let result = Command::new(&self.command_name)
            .arg(&file_model)
            .args(self.params.iter().flat_map(|(k, v)| vec![k, v]))
            .arg("solve")
            .arg("solution")
            .arg(&self.temp_solution_file)
            .output()
            .map_err(|_| format!("Error running the {} solver", self.name))
            .and_then(|r| {
                if r.status.success() {
                    self.read_solution()
                } else {
                    Err(r.status.to_string())
                }
            });

        let _ = fs::remove_file(file_model);
        result
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{DWORD, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let ret = WSARecv(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                0 as *mut _,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let mut acceptor = TcpListener::bind("0.0.0.0").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<commit_msg>add port to windows test addr<commit_after>extern crate winapi;
extern crate ws2_32;

use std::io;
use std::os::windows::io::{AsRawSocket, RawSocket};

use self::winapi::{DWORD, LPWSABUF};

use self::ws2_32::{WSASend, WSARecv};

use ::{Rawv, Writev, Readv};

struct WinSock(RawSocket);

impl<T: AsRawSocket> Rawv for T {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).readv(buffers)
    }

    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        WinSock(self.as_raw_socket()).writev(buffers)
    }
}

impl Writev for WinSock {
    fn writev(&mut self, buffers: &[&[u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let ret = WSASend(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                0,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(bytes as usize)
            }
        }
    }
}

impl Readv for WinSock {
    fn readv(&mut self, buffers: &[&mut [u8]]) -> io::Result<usize> {
        unsafe {
            let mut bytes = 0;
            let ret = WSARecv(
                self.0,
                buffers.as_ptr() as LPWSABUF,
                buffers.len() as DWORD,
                &mut bytes,
                0 as *mut _,
                0 as *mut _,
                None
            );
            if ret != 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(ret as usize)
            }
        }
    }
}

#[test]
fn test_rawv() {
    use std::net::{TcpListener, TcpStream};
    use std::thread;

    let mut acceptor = TcpListener::bind("0.0.0.0:0").unwrap();
    let addr = acceptor.local_addr().unwrap();

    thread::spawn(move || {
        let mut outgoing = TcpStream::connect(addr).unwrap();
        outgoing.writev(&[b"foo", b"bar"]).unwrap();
    });

    let (mut incoming, _) = acceptor.accept().unwrap();
    let mut one = [0u8; 2];
    let mut two = [0u8; 4];

    incoming.readv(&[&mut one, &mut two]).unwrap();
    assert_eq!(&one, b"fo");
    assert_eq!(&two, b"obar");
}
<|endoftext|>


<commit_before>extern crate fht2plib;

use fht2plib::how;
use std::{
    env,
    fs::{read_to_string, remove_file},
    io,
    panic::catch_unwind,
    path::Path,
    thread,
    time::Duration,
};

// use futures::FutureExt;
use reqwest::{redirect::Policy, Client, StatusCode};
use tokio::{
    process::{Child, Command},
    runtime::{Builder, Runtime},
    time::timeout,
};
use walkdir::WalkDir;

const ARGS: &[&str] = &[
    "run",
    "--release",
    "--",
    "-p",
    "9000",
    "-u",
    "-m",
    "-r",
    "-vvv",
    ".",
    ".gitignore",
];

fn uri(pq: &str) -> String {
    format!("http://127.0.0.1:{}/{}", ARGS[4], pq)
}

async fn start_server() -> Child {
    let mut command = Command::new("cargo");
    command.current_dir(".").args(ARGS);

    let mut child = command.spawn().map_err(|e| eprintln!("exec fht2p failed: {:?}", e)).unwrap();

    if timeout(Duration::from_millis(2380), &mut child).await.is_ok() {
        panic!("start fht2p failed, exited early")
    }

    child
}

const CURDIR: &str = "tests/upload/";

async fn httpt() {
    env::set_current_dir(CURDIR).expect("set_current_dir(tests/upload)");

    let client = Client::builder().redirect(Policy::none()).build().expect("Client::builder()");

    let get = get_text("", &client)
        .await
        .map_err(|e| eprintln!("get / failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_success());
    assert!(get.1.len() > 1);

    let get = get_text("/", &client)
        .await
        .map_err(|e| eprintln!("get // failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    let get = get_text("tests/dir/index.html/", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.html/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    let get = get_text("tests/dir/index.htm/", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.htm/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    // the path of route is file
    let get = get_text(".gitignore", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.htm/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_success());
    assert_eq!(get.1.as_str(), include_str!("../.gitignore"));

    #[cfg(unix)]
    {
        dir_post_files("../../src/base", &client).await;
        dir_post_files("../dir", &client).await;
    }
}

async fn dir_post_files(dir: &str, client: &Client) {
    for entry in WalkDir::new(dir)
        .max_depth(1)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| p.file_type().is_file())
    {
        let path = entry.path();
        let fina = entry.file_name().to_str().expect("entry.file_name().to_str()");
        let upa = format!("{}{}", CURDIR, fina);
        let url = uri(CURDIR);

        println!("{}: {}: {}", path.display(), fina, url);

        post_file(&path, &fina, &upa, &url, client).await.unwrap();
    }
}

async fn post_file(path: &Path, fina: &str, upa: &str, url: &str, client: &Client) -> io::Result<()> {
    remove_file(fina).ok();

    let get = get_text(upa, client).await.unwrap();
    assert_eq!(get.0.as_u16(), 404);

    let before = get_text(CURDIR, client).await.unwrap();
    assert_eq!(before.0, 200);

    let fina_arg = path.to_str().unwrap();
    let fina_arg = format!("filename=@{}", fina_arg);
    let es = Command::new("curl")
        .args(&["curl", "-vF", fina_arg.as_str(), url])
        .spawn()
        .unwrap()
        .await
        .expect("exec curl failed0");
    if !es.success() {
        panic!("exec curl failed1");
    }

    let get = get_text(upa, client).await.unwrap();
    assert_eq!(get.0.as_u16(), 200);

    let fc = read_to_string(fina).unwrap();
    assert_eq!(get.1, fc);

    let after = get_text(CURDIR, client).await.unwrap();

    assert_eq!(after.0, 200);

    remove_file(fina).ok();

    Ok(())
}

async fn get_text(path: &str, client: &Client) -> Result<(StatusCode, String), how::Error> {
    let url = uri(path);
    let resp = client.get(&url).send().await?;
    let code = resp.status();

    let text = resp.text().await?;
    Ok((code, text))
}

#[test]
fn full_http_test() {
    let mut rt = Builder::new().basic_scheduler().enable_all().build().unwrap();

    rt.block_on(async {
        let mut server = start_server().await;

        let rest = thread::spawn(|| {
            catch_unwind(|| {
                let mut rt = Runtime::new().expect("Runtime::new()");
                rt.block_on(httpt());
            })
        })
        .join();

        server.kill().unwrap();

        let _ = rest.unwrap().unwrap();
    })
}
<commit_msg>Add test for upload multiple files together<commit_after>extern crate fht2plib;

use fht2plib::how;
use std::{
    env,
    fs::{read_to_string, remove_file},
    io,
    panic::catch_unwind,
    path::{Path, PathBuf},
    thread,
    time::Duration,
};

// use futures::FutureExt;
use reqwest::{redirect::Policy, Client, StatusCode};
use tokio::{
    process::{Child, Command},
    runtime::{Builder, Runtime},
    time::timeout,
};
use walkdir::WalkDir;

const ARGS: &[&str] = &[
    "run",
    "--release",
    "--",
    "-p",
    "9000",
    "-u",
    "-m",
    "-r",
    "-vvv",
    ".",
    ".gitignore",
];

fn uri(pq: &str) -> String {
    format!("http://127.0.0.1:{}/{}", ARGS[4], pq)
}

async fn start_server() -> Child {
    let mut command = Command::new("cargo");
    command.current_dir(".").args(ARGS);

    let mut child = command.spawn().map_err(|e| eprintln!("exec fht2p failed: {:?}", e)).unwrap();

    if timeout(Duration::from_millis(2380), &mut child).await.is_ok() {
        panic!("start fht2p failed, exited early")
    }

    child
}

const CURDIR: &str = "tests/upload/";

async fn httpt() {
    env::set_current_dir(CURDIR).expect("set_current_dir(tests/upload)");

    let client = Client::builder().redirect(Policy::none()).build().expect("Client::builder()");

    let get = get_text("", &client)
        .await
        .map_err(|e| eprintln!("get / failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_success());
    assert!(get.1.len() > 1);

    let get = get_text("/", &client)
        .await
        .map_err(|e| eprintln!("get // failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    let get = get_text("tests/dir/index.html/", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.html/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    let get = get_text("tests/dir/index.htm/", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.htm/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_redirection());
    assert!(get.1.len() < 1);

    // the path of route is file
    let get = get_text(".gitignore", &client)
        .await
        .map_err(|e| eprintln!("get /tests/dir/index.htm/ failed: {:?}", e))
        .unwrap();
    assert!(get.0.is_success());
    assert_eq!(get.1.as_str(), include_str!("../.gitignore"));

    #[cfg(unix)]
    {
        dir_post_files("../../src/base", &client).await;
        dir_post_files("../dir", &client).await;
    }
}

async fn dir_post_files(dir: &str, client: &Client) {
    println!("dir_post_files: {}", dir);

    let mut files = vec![];

    for entry in WalkDir::new(dir)
        .max_depth(1)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| p.file_type().is_file())
    {
        let path = entry.path();
        let fina = entry.file_name().to_str().expect("entry.file_name().to_str()");
        let upa = format!("{}{}", CURDIR, fina);
        let url = uri(CURDIR);

        println!("{}: {}: {}", path.display(), fina, url);

        post_file(&path, &fina, &upa, &url, client).await.unwrap();
        files.push((path.to_path_buf(), fina.to_owned(), upa));
    }

    // upload multi files once
    post_files(dir, files, client).await
}

async fn post_file(path: &Path, fina: &str, upa: &str, url: &str, client: &Client) -> io::Result<()> {
    remove_file(fina).ok();

    let get = get_text(upa, client).await.unwrap();
    assert_eq!(get.0.as_u16(), 404);

    let before = get_text(CURDIR, client).await.unwrap();
    assert_eq!(before.0, 200);

    let fina_arg = path.to_str().unwrap();
    let fina_arg = format!("filename=@{}", fina_arg);
    let es = Command::new("curl")
        .args(&["-vF", fina_arg.as_str(), url])
        .spawn()
        .unwrap()
        .await
        .expect("exec curl failed0");
    if !es.success() {
        panic!("exec curl failed1");
    }

    let get = get_text(upa, client).await.unwrap();
    assert_eq!(get.0.as_u16(), 200);

    let upfc = read_to_string(fina).unwrap();
    assert_eq!(get.1, upfc);
    let rawfc = read_to_string(path).unwrap();
    assert_eq!(get.1, rawfc);

    remove_file(fina).ok();

    let after = get_text(CURDIR, client).await.unwrap();
    assert_eq!(after.0, 200);
    assert_eq!(before.1, after.1);

    Ok(())
}

async fn post_files(dir: &str, files: Vec<(PathBuf, String, String)>, client: &Client) {
    println!("post_files: {}", dir);

    let before = get_text(CURDIR, client).await.unwrap();
    assert_eq!(before.0, 200);

    let mut fina_args = vec![];

    for (path, fina, upa) in &files {
        remove_file(fina).ok();

        let get = get_text(upa, client).await.unwrap();
        assert_eq!(get.0.as_u16(), 404);

        let fina_arg = path.to_str().unwrap();
        let fina_arg = format!("filename=@{}", fina_arg);
        fina_args.push(fina_arg);
    }

    let url = uri(CURDIR);
    let mut args = vec!["-v", url.as_str()];
    fina_args.iter().for_each(|arg| {
        args.push("-F");
        args.push(arg.as_str());
    });

    let es = Command::new("curl")
        .args(&args)
        .spawn()
        .unwrap()
        .await
        .expect("exec curl failed0");
    if !es.success() {
        panic!("exec curl failed1");
    }

    for (path, fina, upa) in &files {
        let get = get_text(upa, client).await.unwrap();
        assert_eq!(get.0.as_u16(), 200);

        let upfc = read_to_string(fina).unwrap();
        assert_eq!(get.1, upfc);

        let rawfc = read_to_string(path).unwrap();
        assert_eq!(get.1, rawfc);

        remove_file(fina).ok();
    }

    let after = get_text(CURDIR, client).await.unwrap();
    assert_eq!(after.0, 200);

    assert_eq!(before.1, after.1);
}

async fn get_text(path: &str, client: &Client) -> Result<(StatusCode, String), how::Error> {
    let url = uri(path);
    let resp = client.get(&url).send().await?;
    let code = resp.status();

    let text = resp.text().await?;
    Ok((code, text))
}

#[test]
fn full_http_test() {
    let mut rt = Builder::new().basic_scheduler().enable_all().build().unwrap();

    rt.block_on(async {
        let mut server = start_server().await;

        let rest = thread::spawn(|| {
            catch_unwind(|| {
                let mut rt = Runtime::new().expect("Runtime::new()");
                rt.block_on(httpt());
            })
        })
        .join();

        server.kill().unwrap();

        let _ = rest.unwrap().unwrap();
    })
}
<|endoftext|>