<commit_before>///! Selected intrusive types, including intrusive references.
///!
///! Use of intrusively-reference-counted objects allows easy creation of sharable reference
///! allows creation of references to e.g. self:
///!
///! ```rust
///! use relemon::util::intrusive
///! struct Quaternion { w: f64, x: f64, y: f64, z: f64 }
///! impl MyType {
///! fn new_on_heap(w: f64, x: f64, y: f64, z: f64) -> Ref<Quaternion>
///! }
///! ```
///!

extern crate core;
use std;
use std::fmt;
use std::mem;
use std::ptr::PtrExt;
use std::ops::Deref;
use std::hash::{Hash, Hasher};

/// Interface for types that can be used with intrusive references.
pub trait RefCounted {
    // Create a reference to the current object.
    fn ref_to_self<T: RefCounted + ExplicitlySized>(&self) -> Ref<T> {
        ref_to_raw(unsafe{std::mem::transmute(&self)})
    }

    /// Fetch the object's current reference count.
    fn get_refcount(&self) -> usize;

    /// Increment the object's reference count, returning the new value.
    fn add_ref(&mut self) -> usize;

    /// Decrement the object's reference count, returning the new value.
    fn remove_ref(&mut self) -> usize;
}

/// Interface required of unsized types used with intrusive references.
pub trait ExplicitlySized {
    /// Get the underlying type's allocation size.
    fn get_type_size(&self) -> usize;

    /// Get the underlying type's allocation alignment.
    fn get_type_align(&self) -> usize;
}

/// Create a simple implementation of util::intrusive::RefCounted for a type.
#[macro_export]
macro_rules! default_refcounted_impl {
    ($target:ident, $($mbr:ident).*) => (
        impl intrusive::RefCounted for $target {
            fn get_refcount(&self) -> usize { self.$($mbr).* }
            fn add_ref(&mut self) -> usize { self.$($mbr).* += 1; self.$($mbr).* }
            fn remove_ref(&mut self) -> usize { self.$($mbr).* -= 1; self.$($mbr).* }
        });
    ($target:ident<'a>, $($mbr:ident).*) => (
        impl<'a> intrusive::RefCounted for $target<'a> {
            fn get_refcount(&self) -> usize { self.$($mbr).* }
            fn add_ref(&mut self) -> usize { self.$($mbr).* += 1; self.$($mbr).* }
            fn remove_ref(&mut self) -> usize { self.$($mbr).* -= 1; self.$($mbr).* }
        });
    (<$typ:ident>, $($mbr:ident).*) => (
        impl<$typ> intrusive::RefCounted for $typ {
            fn get_refcount(&self) -> usize { self.$($mbr).* }
            fn add_ref(&mut self) -> usize { self.$($mbr).* += 1; self.$($mbr).* }
            fn remove_ref(&mut self) -> usize { self.$($mbr).* -= 1; self.$($mbr).* }
        });
}

/// Immutable reference to an intrusively-refcounted object.
pub struct Ref<T: RefCounted + ?Sized>(*const T);

/// Create an intrusive reference via raw pointer.
/// This method is all *kinds* of unsafe, and should **not** be used from
/// user code!
fn ref_to_raw<T: RefCounted + ExplicitlySized>(ptr: *mut T) -> Ref<T> {
    // Transmute into a mutable reference so we can increment the refcount.
    let mut_ref: &mut T = unsafe { &mut *ptr };
    panic_unless!(1 == mut_ref.add_ref(), "unexpected nonzero refcount on unowned raw pointer");
    Ref(ptr)
}

/// Move the given value into the heap, and return a Ref to it.  The value
/// should have a refcount of zero prior to this function.
///
/// # Examples
///
/// ```rust
/// #[macro_use]
/// use cripes::util::intrusive;
///
/// #[derive(Debug)]
/// struct Dog { refcount: usize }
/// default_refcounted_impl!(Dog);
/// let x = intrusive::ref_to_new(Dog{refcount: 0});   // x is an intrusive reference to the heap
/// println!("{:?}", x);
/// drop(x);                  // dropping the sole reference to that location
///                           // will free the memory.
/// ```
pub fn ref_to_new<U: RefCounted + ExplicitlySized, T: ?Sized + RefCounted + ExplicitlySized>(obj: U) -> Ref<T> {
    let mem = unsafe { mem::transmute::<_,*mut T>(std::boxed::into_raw(Box::new(obj))) };
    ref_to_raw(mem)
}

/* **************************************************************** */
impl<T: RefCounted + ExplicitlySized + ?Sized> Ref<T> {
    /// Create a null Ref.  This is probably not very safe.
    pub fn null() -> Ref<T> {
        Ref(std::mem::transmute::<_,*const T>(0))
    }

    /// Check if the ref's internal pointer is NULL.
    pub fn is_null(&self) -> bool { match *self { Ref(x) => (x == 0 as *const T) } }

    /// Get the reference count from the underlying object.
    pub fn get_refcount(&self) -> usize {
        self.deref().get_refcount()
    }

    /// Check if this refers to the same object as another Ref.
    pub fn is_same(&self, other: &Ref<T>) -> bool {
        match *self { Ref(x) => match *other { Ref(y) => (x as usize) == (y as usize) } }
    }
}

/* ================================================================
 * impl std::borrow::Borrow
 */
impl<T: RefCounted + ?Sized>  std::borrow::Borrow<T> for Ref<T> {
    fn borrow(&self) -> &T {
        self.deref()
    }
}

/* ================================================================
 * impl fmt::Display
 */
impl<T: RefCounted + fmt::Display + ?Sized> fmt::Display for Ref<T>  {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Ref(p) => { assert!(! (p == 0 as *const T));
                        self.deref().fmt(f) } }
    }
}

/* ================================================================
 * impl fmt::Debug
 */
impl<T: RefCounted + fmt::Debug + ?Sized> fmt::Debug for Ref<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Ref(value) => {
                write!(f, "Ref {{ 0x{:X}=>", (value as usize));
                self.deref().fmt(f) }
        }
    }
}

/* ================================================================
 * impl Clone
 */
impl<T: RefCounted + ?Sized> Clone for Ref<T> {
    fn clone(&self) -> Self {
        ref_to_raw(self.deref())
    }
}

/* ================================================================
 * impl Deref
 */
impl<T: RefCounted + ?Sized> Deref for Ref<T> {
    type Target = T;
    fn deref(&self) -> &T {
        if self.is_null() { panic!("tried to deref a null pointer") }
        match *self { Ref(p) =>  { &*p }
        }
    }
}

/* ================================================================
 * impl Drop
 */
#[unsafe_destructor]
impl<T: RefCounted + ExplicitlySized + ?Sized> Drop for Ref<T> {
    fn drop(&mut self) {
        match *self {
            Ref(x) => { assert!((x as usize) != 0);
                        let _ref: &mut T = unsafe { &mut *x };
                        if _ref.remove_ref() == 0 {
                            let boxed = unsafe { Box::from_raw(mem::transmute::<_,*mut T>(x)) };
                            drop(boxed); } }
        }
    }
}

/* ================================================================
 * impl PartialEq<T>, Eq<T>
 */
impl<T: Eq + RefCounted + ExplicitlySized + ?Sized> Eq for Ref<T> {}

impl<T: PartialEq<T> + RefCounted + ExplicitlySized + ?Sized> PartialEq<Ref<T>> for Ref<T> {
    fn eq(&self, other: &Ref<T>) -> bool {
        *(*self) == *(*other)
    }
}
impl<T: PartialEq<T> + RefCounted + ExplicitlySized + ?Sized> PartialEq<T> for Ref<T> {
    fn eq(&self, other: &T) -> bool {
        *self == *other
    }
}

/* ================================================================
 * impl Hash<H>
 */
impl<T: ?Sized + ExplicitlySized + RefCounted + Hash> Hash for Ref<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self { Ref(..) => self.deref().hash(state) }
    }
}
<commit_msg>util/intrusive: full rewrite.<commit_after>//! Intrusive reference types.
//!
//! Use of intrusively-reference-counted objects with matching reference types
//! over containers like `std::rc::Rc` or `std::sync::Arc` trades some
//! compile-time safety checks (and likely performance benefits) for greater
//! flexibility in how those objects are allocated and used.
//!
//! `Rc` and `Arc` are themselves references to underlying *containers*; any
//! object passed to either's `::new` will be moved to a newly-allocated block
//! on the heap.  To support weak references the data's reference count is
//! stored in another heap-allocated block, which is freed *only when the last
//! reference, weak *or* strong, is dropped*.  Because these types have
//! a reference count stored separately from the data, it is impossible to
//! create a new `Rc`, `Arc`, or `Weak` pointer thereto without one of
//! the same.
//!
//! In contrast, the types defined here forgo support for weak references and
//! strong guarantees of lifetime-management and memory-safety to allow the
//! developer more flexibility in data storage and manipulation.
//!
//! Since reference counts are stored alongside the data (in types
//! implementing [`RefCountHolder`](trait.RefCountHolder.html)),
//! a stack-allocated value can safely provide references to itself as long as
//! its refcount is non-zero prior to its doing so.  they support references
//! to stack-allocated values and values in memory not managed directly the by
//! [`Reference`](trait.Reference.html) implementation.
use std;
use std::fmt;
use std::mem;
use std::ops::{Deref,DerefMut};
use std::ptr::PtrExt;
use std::clone::Clone;
use std::hash::{Hash, Hasher};
use std::borrow::Borrow;

/// Abstract interface for references to intrusively-refcounted values.
pub trait Reference<T: ?Sized> where T: RefCounted, Self: Sized {
    /// Create a reference from a raw pointer.  The reference-type
    /// implementation should do no management of the referand's refcount for
    /// this operation.
    fn from_obj<U>(obj: &U) -> Self;

    /// Create an intrusive reference from a trait object.  The reference-type
    /// implementation should do no management of the referand's refcount for
    /// this operation.
    fn from_trait_obj(obj: &T) -> Self;

    /// Move the given value into the heap, and return a reference to it.  The value
    /// should have a refcount of zero prior to this function.
    ///
    /// # Examples
    ///
    /// ```rust
    /// #[macro_use]
    /// use cripes::util::intrusive;
    /// use cripes::util::intrusive::{Ref,Reference};
    ///
    /// #[derive(Debug)]
    /// struct Dog { refcount: usize }
    /// default_refcounted_impl!(Dog);
    ///
    /// let x: Ref<_> = Reference::new_on_heap(Dog{refcount: 0});   // x is an intrusive reference to the heap
    ///
    /// println!("{:?}", x);
    /// drop(x);                  // dropping the sole reference to that location
    ///                           // will free the memory.
    /// ```
    fn new_on_heap<U>(mut obj: U) -> Self where Self: Sized, U: Sized + RefCounted {
        {
            let rc = obj.as_refcounted_mut();
            // Zero the reference count: we're "taking ownership" of the object.
            while rc.get_refcount() != 0 { rc.remove_ref(); }

            rc.add_ref();
        }

        // Move the object onto the heap using Box, then discard the box in
        // favor of a hot, sticky, unsafe mess.
        let heaped: *const () = unsafe { std::boxed::into_raw(Box::new(obj)) as *const () };

        if std::mem::size_of::<&T>() == std::mem::size_of::<usize>() {
            // standard pointer
            unsafe { Reference::from_obj(&*(heaped as *const U)) }
        } else {
            // trait object
            unsafe { Reference::from_trait_obj(&*(heaped as *const T)) }
        }
    }
}

/// Describes a type that holds a reference count.
pub trait RefCountHolder {
    /// Fetch the object's current reference count.
    fn get_refcount(&self) -> usize;

    /// Increment the object's reference count, returning the new value.
    fn add_ref(&mut self) -> usize;

    /// Decrement the object's reference count, returning the new value.
    fn remove_ref(&mut self) -> usize;
}

pub trait RefCounted {
    // /// Create a reference to the current object.
    // fn ref_to_self<T: ?Sized>(&self) -> Ref<T> where T: RefCounted, Self: T {
    //     Reference::from_raw(unsafe { std::mem::transmute::<_,*const Self>(self) })
    // }

    fn as_refcounted(&self) -> &RefCountHolder;
    fn as_refcounted_mut(&mut self) -> &mut RefCountHolder;
}

impl<T> RefCounted for T where T: RefCountHolder {
    fn as_refcounted(&self) -> &RefCountHolder { self as &RefCountHolder }
    fn as_refcounted_mut(&mut self) -> &mut RefCountHolder { self as &mut RefCountHolder }
}

/// Create a simple implementation of util::intrusive::RefCountHolder for a type.
#[macro_export]
macro_rules! default_refcounted_impl {
    ($target:ident) => (default_refcounted_impl!($target, refcount););

    ($target:ident, $($mbr:ident).*) => (
        impl ::cripes::util::intrusive::RefCountHolder for $target {
            fn get_refcount(&self) -> usize { self.$($mbr).* }
            fn add_ref(&mut self) -> usize { self.$($mbr).* += 1; self.$($mbr).* }
            fn remove_ref(&mut self) -> usize { self.$($mbr).* -= 1; self.$($mbr).* }
        });
}

/* ****************************************************************
 * MutRef<T>
 */
// This is disabled for now -- we'd need a refcounted `RwLock` type or
// something to make this properly intrusive.  Until that happens, we
// (!!unsafely) implement MutDeref for Ref<T>.

/* /// Mutable, RwLock-protected reference to an intrusively-refcounted object.
pub struct MutRef<T: ?Sized + RefCounted + Send + Sync>(std::sync::RwLock<*mut T>);

impl<T> Reference<T> for MutRef<T>
where T: RefCounted + Send + Sync {
    fn new(ptr: *mut T) -> MutRef<T> { MutRef(std::sync::RwLock::new(ptr)) }
}

impl<T> Deref for MutRef<T>
    where T: RefCounted + Send + Sync {
    type Target = T;
    fn deref(&self) -> &T {
        if (*self).is_null() { panic!("tried to deref a null pointer") }
        match *self { Ref(p) =>  { let val_ref: &T = unsafe { &*p };
                                   val_ref }
        }
    }
}
impl<T: RefCounted> DerefMut for Ref<T> {
    fn deref_mut(&mut self) -> &mut T {
        if (*self).is_null() { panic!("tried to deref a null pointer") }
        match *self { Ref(p) =>  unsafe { std::mem::transmute(&*p) }
        }
    }
}*/

/* ****************************************************************
 * Ref<T>
 */
/// Immutable reference to an intrusively-refcounted object.
pub struct Ref<T: ?Sized>(RefImpl<T>) where T: RefCounted;

/// Private data type for Ref<T>.
enum RefImpl<T: ?Sized> where T: RefCounted {
    /// Invalid reference.
    Empty,

    /// Simple pointer to a concrete type.
    Pointer(*const T),

    /// A fat pointer/trait object.
    TraitObject(std::raw::TraitObject)
}

impl<T: ?Sized> Reference<T> for Ref<T> where T: RefCounted {
    fn from_trait_obj(obj: &T) -> Self {
        Ref(RefImpl::TraitObject(std::mem::transmute(obj)))
    }

    fn from_obj<U>(obj: &U) -> Ref<T> {
        let ptr: *const T =  unsafe { std::mem::transmute(obj) };
        if ptr == (0 as *const T) { Ref(RefImpl::Empty) }
        else { Ref(RefImpl::Pointer(ptr)) }
    }
}

// impl<T: ?Sized, U> Reference<U> for Ref<T> where T: RefCounted {
//     fn from_trait_obj(obj: &T) -> Self {
//         Ref(RefImpl::TraitObject(std::mem::transmute(obj)))
//     }

//     fn from_obj<U>(obj: &U) -> Ref<T> {
//         let ptr: *const T =  unsafe { std::mem::transmute(obj) };
//         if ptr == (0 as *const T) { Ref(RefImpl::Empty) }
//         else { Ref(RefImpl::Pointer(ptr)) }
//     }
// }

impl<T: ?Sized> Ref<T> where T: RefCounted {
    /// Fetch the reference's data pointer as a `usize`.  This is intended
    /// primarily for implementing hashes over trait objects (the standard
    /// library's Hash is not object-safe) by simply hashing the instance's
    /// data pointer.
    pub unsafe fn data_id(&self) -> usize {
        match self.0 {
            RefImpl::Empty => 0,
            RefImpl::Pointer(p) => p as usize,
            RefImpl::TraitObject(ref to) => to.data as usize
        }
    }

    /// Create a null Ref.  This is probably not very safe.
    pub fn null() -> Ref<T> {
        Ref(RefImpl::Empty)
   }

    /// Check if the ref's internal pointer is NULL.
    pub fn is_null(&self) -> bool {
        match self.0 {
            RefImpl::Empty => true,
            _ => false
        }
    }

    /// Get the reference count from the underlying object.
    pub fn get_refcount(&self) -> usize {
        match self.0 {
            RefImpl::Empty => 0,
            _ => self.deref().as_refcounted().get_refcount()
        }
    }

    /// Check if this refers to the same object as another Ref.
    pub fn is_same(&self, other: &Ref<T>) -> bool {
        match self.0 {
            RefImpl::Empty => match other.0 { RefImpl::Empty => true, _ => false },
            RefImpl::Pointer(x) => match other.0 { RefImpl::Pointer(y) => x == y, _ => false },
            RefImpl::TraitObject(ref x) => match other.0 {
                RefImpl::TraitObject(ref y) => { x.data == y.data && x.vtable == y.vtable },
                _ => false },
        }
    }
}

/* ================================================================
 * impl Deref
 */
impl<T: ?Sized> Deref for Ref<T>
where T: RefCounted {
    type Target = T;
    fn deref(&self) -> &T {
        match self.0 {
            RefImpl::Empty => panic!("tried to deref from an empty reference"),
            RefImpl::Pointer(ptr) => &*ptr,
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj) }
        }
    }
}

impl<T: ?Sized> DerefMut for Ref<T>
where T: RefCounted {
    fn deref_mut(&mut self) -> &mut T {
        match self.0 {
            RefImpl::Empty => panic!("tried to mutably deref from an empty reference"),
            RefImpl::Pointer(ptr) => unsafe { &mut *std::mem::transmute::<_,*mut T>(ptr) },
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj) }
        }
    }
}

/* ================================================================
 * impl std::borrow::Borrow
 */
impl<T: ?Sized>  Borrow<T> for ::cripes::util::intrusive::Ref<T>
where T: RefCounted {
    fn borrow(&self) -> &T {
        self.deref()
    }
}

// impl<T: ?Sized>  Borrow<::cripes::util::intrusive::Ref<T>> for ::cripes::util::intrusive::Ref<T>
// where T: RefCounted {
//     fn borrow(&self) -> &T {
//         self
//     }
// }

/* ================================================================
 * impl fmt::Display
 */
impl<T: ?Sized> fmt::Display for Ref<T>
where T: RefCounted + fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            RefImpl::Pointer(p) => { assert!(! (p == 0 as *const T));
                                     let val: &T = (*self).deref();
                                     val.fmt(f) } }
    }
}

/* ================================================================
 * impl fmt::Debug
 */
impl<T: ?Sized> fmt::Debug for Ref<T>
where T:  RefCounted + fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ptr = match self.0 {
            RefImpl::Empty => { return write!(f, "Ref{{Empty}}"); },
            RefImpl::Pointer(p) => p,
            RefImpl::TraitObject(ref obj) => unsafe { std::mem::transmute(obj.data) }};
        let val = (*self).deref();
        try!(write!(f, "Ref {{ 0x{:X}=>", ptr as usize));
        try!(val.fmt(f));
        write!(f, " }}")

    }
}

/* ================================================================
 * impl Clone
 */
impl<T: ?Sized> Clone for Ref<T>
where T: RefCounted {
    fn clone(&self) -> Self {
        Ref(self.0)
    }
}

/* ================================================================
 * impl Drop
 */
#[unsafe_destructor]
impl<T: ?Sized> Drop for Ref<T>
where T: RefCounted {
    fn drop(&mut self) {
        match self.0 {
            RefImpl::Pointer(x) => { assert!((x as usize) != 0);
                                     unsafe {
                                         let _ref =  self.deref_mut().as_refcounted_mut();
                                         if _ref.remove_ref() == 0 {
                                             let boxed = Box::from_raw(mem::transmute::<_,*mut T>(x));
                                             drop(boxed); } } },
            _ => {}
        }
    }
}

/* ================================================================
 * impl Eq, PartialEq<T>, PartialEq<Ref<T>>
 */
impl<T: ?Sized> Eq for Ref<T>
where T: RefCounted + Eq {}

impl<T: ?Sized> PartialEq<T> for Ref<T>
where T: RefCounted + PartialEq<T> {
    fn eq(&self, other: &T) -> bool {
        self.deref() == other
    }
}

impl<T: ?Sized> PartialEq<Ref<T>> for Ref<T>
where T: RefCounted + PartialEq<T> {
    fn eq(&self, other: &Ref<T>) -> bool {
        *self == *other
    }
}

/* ================================================================
 * impl Hash<H>
 */
impl<T: ?Sized> Hash for Ref<T>
where T: RefCounted + Hash {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (*self).deref().hash(state)
    }
}
<|endoftext|>


<commit_before>// A parser combinator that scans for zeros in a number of bytes. When the
// current byte is all zeros, the parser fails. The last argument is the bit
// offset relative the first byte being parsed.
macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorCode::Digit as u32, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
);

// A parser combiner for previously allocated buffers that can be passed
// in as mutable slices. The macro will parse and fill the total length of
// the passed in slice.
macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

macro_rules! count_bits (
  ($input: expr, $submac: ident!( $($args:tt)* ), $count: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;
      let mut result   = Vec::with_capacity($count);

      loop {
        if count == $count {
          break;
        }

        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            result.push(o);

            input  = i;
            count += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $count {
        $crate::nom::IResult::Done(input, result)
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_bits!($i, call!($f), $count);
  );
);

macro_rules! take_signed_bits (
  ($input: expr, $signed_type: ty, $count: expr) => (
    map!($input, take_bits!(u32, $count), |value| {
      ::utility::extend_sign(value, $count) as $signed_type
    });
  );
  ($input: expr, $count: expr) => (
    take_signed_bits!($input, i32, $count);
  );
);
<commit_msg>Add a comment explaining the `count_bits!` macro<commit_after>// A parser combinator that scans for zeros in a number of bytes. When the
// current byte is all zeros, the parser fails. The last argument is the bit
// offset relative the first byte being parsed.
macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorCode::Digit as u32, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
);

// A parser combiner for previously allocated buffers that can be passed
// in as mutable slices. The macro will parse and fill the total length of
// the passed in slice.
macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

// A replacement for the default `count!` macro. This is specifically for
// bit parsers and will be removed as soon as the generic version of the
// macro comes out with the 1.0.0 release.
macro_rules! count_bits (
  ($input: expr, $submac: ident!( $($args:tt)* ), $count: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;
      let mut result   = Vec::with_capacity($count);

      loop {
        if count == $count {
          break;
        }

        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            result.push(o);

            input  = i;
            count += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $count {
        $crate::nom::IResult::Done(input, result)
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_bits!($i, call!($f), $count);
  );
);

macro_rules! take_signed_bits (
  ($input: expr, $signed_type: ty, $count: expr) => (
    map!($input, take_bits!(u32, $count), |value| {
      ::utility::extend_sign(value, $count) as $signed_type
    });
  );
  ($input: expr, $count: expr) => (
    take_signed_bits!($input, i32, $count);
  );
);
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde_json;
use std::ffi::OsStr;
use std::io::{BufReader, ErrorKind as IoErrorKind, Read, Result as IoResult};
use std::process::{Child, Command, Stdio};
use super::{AudioSource, AudioType, DcaError, DcaMetadata, VoiceError};
use internal::prelude::*;

use std::fs::File;
use std::result::Result as StdResult;

struct ChildContainer(Child);

impl Read for ChildContainer {
    fn read(&mut self, buffer: &mut [u8]) -> IoResult<usize> {
        self.0.stdout.as_mut().unwrap().read(buffer)
    }
}

struct InputSource<R: Read + Send + 'static> {
    stereo: bool,
    reader: R,
    kind: AudioType,
}

impl<R: Read + Send> AudioSource for InputSource<R> {
    fn is_stereo(&mut self) -> bool { self.stereo }

    fn get_type(&self) -> AudioType { self.kind.clone() }

    fn read_pcm_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
        for (i, v) in buffer.iter_mut().enumerate() {
            *v = match self.reader.read_i16::<LittleEndian>() {
                Ok(v) => v,
                Err(ref e) => {
                    return if e.kind() == IoErrorKind::UnexpectedEof {
                        Some(i)
                    } else {
                        None
                    }
                },
            }
        }

        Some(buffer.len())
    }

    fn read_opus_frame(&mut self) -> Option<Vec<u8>> {
        match self.reader.read_i16::<LittleEndian>() {
            Ok(size) => {
                let mut frame = Vec::with_capacity(size as usize + 2);
                frame.write_i16::<LittleEndian>(size);
                match self.reader.read_exact(&mut frame[2..]) {
                    Ok(_) => Some(frame),
                    _ => None,
                }
            },
            Err(ref e) => {
                return if e.kind() == IoErrorKind::UnexpectedEof {
                    Some(Vec::new())
                } else {
                    None
                }
            },
        }
    }
}

/// Opens an audio file through `ffmpeg` and creates an audio source.
pub fn ffmpeg<P: AsRef<OsStr>>(path: P) -> Result<Box<AudioSource>> {
    let path = path.as_ref();

    // Will fail if the path is not to a file on the fs. Likely a YouTube URI.
    let is_stereo = is_stereo(path).unwrap_or(false);
    let stereo_val = if is_stereo { "2" } else { "1" };

    let args = [
        "-f",
        "s16le",
        "-ac",
        stereo_val,
        "-ar",
        "48000",
        "-acodec",
        "pcm_s16le",
        "-",
    ];

    let command = Command::new("ffmpeg")
        .arg("-i")
        .arg(path)
        .args(&args)
        .stderr(Stdio::null())
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .spawn()?;

    Ok(pcm(is_stereo, ChildContainer(command)))
}

/// Creates a streamed audio source from a DCA file.
/// Currently only accepts the DCA1 format.
pub fn dca<P: AsRef<OsStr>>(path: P) -> StdResult<Box<AudioSource>, DcaError> {
    let file = File::open(path.as_ref()).map_err(DcaError::IoError)?;

    let mut reader = BufReader::new(file);

    let mut header = [0u8; 4];

    // Read in the magic number to verify it's a DCA file.
    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    if header != b"DCA1"[..] {
        return Err(DcaError::InvalidHeader);
    }

    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    let size = (&header[..]).read_i32::<LittleEndian>().unwrap();

    // Sanity check
    if size < 2 {
        return Err(DcaError::InvalidSize(size));
    }

    info!("Size: {}", size);

    let mut raw_json = Vec::with_capacity(size as usize);

    {
        let json_reader = reader.by_ref();
        json_reader.take(size as u64).read_to_end(&mut raw_json).map_err(DcaError::IoError)?;
    }

    info!("Raw JSON: {:?}", raw_json);

    let metadata = serde_json::from_slice::<DcaMetadata>(raw_json.as_slice()).map_err(DcaError::InvalidMetadata)?;

    Ok(opus(metadata.is_stereo(), reader))
}

/// Creates an Opus audio source.
pub fn opus<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Opus
    })
}

/// Creates a PCM audio source.
pub fn pcm<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Pcm
    })
}

/// Creates a streamed audio source with `youtube-dl` and `ffmpeg`.
pub fn ytdl(uri: &str) -> Result<Box<AudioSource>> {
    let args = [
        "-f",
        "webm[abr>0]/bestaudio/best",
        "--no-playlist",
        "--print-json",
        "--skip-download",
        uri,
    ];

    let out = Command::new("youtube-dl")
        .args(&args)
        .stdin(Stdio::null())
        .output()?;

    if !out.status.success() {
        return Err(Error::Voice(VoiceError::YouTubeDLRun(out)));
    }

    let value = serde_json::from_reader(&out.stdout[..])?;
    let mut obj = match value {
        Value::Object(obj) => obj,
        other => return Err(Error::Voice(VoiceError::YouTubeDLProcessing(other))),
    };

    let uri = match obj.remove("url") {
        Some(v) => {
            match v {
                Value::String(uri) => uri,
                other => return Err(Error::Voice(VoiceError::YouTubeDLUrl(other))),
            }
        },
        None => return Err(Error::Voice(VoiceError::YouTubeDLUrl(Value::Object(obj)))),
    };

    ffmpeg(&uri)
}

fn is_stereo(path: &OsStr) -> Result<bool> {
    let args = ["-v", "quiet", "-of", "json", "-show-streams", "-i"];

    let out = Command::new("ffprobe")
        .args(&args)
        .arg(path)
        .stdin(Stdio::null())
        .output()?;

    let value: Value = serde_json::from_reader(&out.stdout[..])?;

    let streams = value
        .as_object()
        .and_then(|m| m.get("streams"))
        .and_then(|v| v.as_array())
        .ok_or(Error::Voice(VoiceError::Streams))?;

    let check = streams.iter().any(|stream| {
        let channels = stream.as_object().and_then(|m| {
            m.get("channels").and_then(|v| v.as_i64())
        });

        channels == Some(2)
    });

    Ok(check)
}
<commit_msg>Remove size header from frame data<commit_after>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde_json;
use std::ffi::OsStr;
use std::io::{BufReader, ErrorKind as IoErrorKind, Read, Result as IoResult};
use std::process::{Child, Command, Stdio};
use super::{AudioSource, AudioType, DcaError, DcaMetadata, VoiceError};
use internal::prelude::*;

use std::fs::File;
use std::result::Result as StdResult;

struct ChildContainer(Child);

impl Read for ChildContainer {
    fn read(&mut self, buffer: &mut [u8]) -> IoResult<usize> {
        self.0.stdout.as_mut().unwrap().read(buffer)
    }
}

struct InputSource<R: Read + Send + 'static> {
    stereo: bool,
    reader: R,
    kind: AudioType,
}

impl<R: Read + Send> AudioSource for InputSource<R> {
    fn is_stereo(&mut self) -> bool { self.stereo }

    fn get_type(&self) -> AudioType { self.kind.clone() }

    fn read_pcm_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
        for (i, v) in buffer.iter_mut().enumerate() {
            *v = match self.reader.read_i16::<LittleEndian>() {
                Ok(v) => v,
                Err(ref e) => {
                    return if e.kind() == IoErrorKind::UnexpectedEof {
                        Some(i)
                    } else {
                        None
                    }
                },
            }
        }

        Some(buffer.len())
    }

    fn read_opus_frame(&mut self) -> Option<Vec<u8>> {
        match self.reader.read_i16::<LittleEndian>() {
            Ok(size) => {
                let mut frame = Vec::with_capacity(size as usize);

                {
                    let reader = self.reader.by_ref();

                    if let Err(_) = reader.take(size as u64).read_to_end(&mut frame) {
                        return None;
                    }
                }

                Some(frame)
            },
            Err(ref e) => {
                return if e.kind() == IoErrorKind::UnexpectedEof {
                    Some(Vec::new())
                } else {
                    None
                }
            },
        }
    }
}

/// Opens an audio file through `ffmpeg` and creates an audio source.
pub fn ffmpeg<P: AsRef<OsStr>>(path: P) -> Result<Box<AudioSource>> {
    let path = path.as_ref();

    // Will fail if the path is not to a file on the fs. Likely a YouTube URI.
    let is_stereo = is_stereo(path).unwrap_or(false);
    let stereo_val = if is_stereo { "2" } else { "1" };

    let args = [
        "-f",
        "s16le",
        "-ac",
        stereo_val,
        "-ar",
        "48000",
        "-acodec",
        "pcm_s16le",
        "-",
    ];

    let command = Command::new("ffmpeg")
        .arg("-i")
        .arg(path)
        .args(&args)
        .stderr(Stdio::null())
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .spawn()?;

    Ok(pcm(is_stereo, ChildContainer(command)))
}

/// Creates a streamed audio source from a DCA file.
/// Currently only accepts the DCA1 format.
pub fn dca<P: AsRef<OsStr>>(path: P) -> StdResult<Box<AudioSource>, DcaError> {
    let file = File::open(path.as_ref()).map_err(DcaError::IoError)?;

    let mut reader = BufReader::new(file);

    let mut header = [0u8; 4];

    // Read in the magic number to verify it's a DCA file.
    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    if header != b"DCA1"[..] {
        return Err(DcaError::InvalidHeader);
    }

    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    let size = (&header[..]).read_i32::<LittleEndian>().unwrap();

    // Sanity check
    if size < 2 {
        return Err(DcaError::InvalidSize(size));
    }

    info!("Size: {}", size);

    let mut raw_json = Vec::with_capacity(size as usize);

    {
        let json_reader = reader.by_ref();
        json_reader.take(size as u64).read_to_end(&mut raw_json).map_err(DcaError::IoError)?;
    }

    info!("Raw JSON: {:?}", raw_json);

    let metadata = serde_json::from_slice::<DcaMetadata>(raw_json.as_slice()).map_err(DcaError::InvalidMetadata)?;

    Ok(opus(metadata.is_stereo(), reader))
}

/// Creates an Opus audio source.
pub fn opus<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Opus
    })
}

/// Creates a PCM audio source.
pub fn pcm<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Pcm
    })
}

/// Creates a streamed audio source with `youtube-dl` and `ffmpeg`.
pub fn ytdl(uri: &str) -> Result<Box<AudioSource>> {
    let args = [
        "-f",
        "webm[abr>0]/bestaudio/best",
        "--no-playlist",
        "--print-json",
        "--skip-download",
        uri,
    ];

    let out = Command::new("youtube-dl")
        .args(&args)
        .stdin(Stdio::null())
        .output()?;

    if !out.status.success() {
        return Err(Error::Voice(VoiceError::YouTubeDLRun(out)));
    }

    let value = serde_json::from_reader(&out.stdout[..])?;
    let mut obj = match value {
        Value::Object(obj) => obj,
        other => return Err(Error::Voice(VoiceError::YouTubeDLProcessing(other))),
    };

    let uri = match obj.remove("url") {
        Some(v) => {
            match v {
                Value::String(uri) => uri,
                other => return Err(Error::Voice(VoiceError::YouTubeDLUrl(other))),
            }
        },
        None => return Err(Error::Voice(VoiceError::YouTubeDLUrl(Value::Object(obj)))),
    };

    ffmpeg(&uri)
}

fn is_stereo(path: &OsStr) -> Result<bool> {
    let args = ["-v", "quiet", "-of", "json", "-show-streams", "-i"];

    let out = Command::new("ffprobe")
        .args(&args)
        .arg(path)
        .stdin(Stdio::null())
        .output()?;

    let value: Value = serde_json::from_reader(&out.stdout[..])?;

    let streams = value
        .as_object()
        .and_then(|m| m.get("streams"))
        .and_then(|v| v.as_array())
        .ok_or(Error::Voice(VoiceError::Streams))?;

    let check = streams.iter().any(|stream| {
        let channels = stream.as_object().and_then(|m| {
            m.get("channels").and_then(|v| v.as_i64())
        });

        channels == Some(2)
    });

    Ok(check)
}
<|endoftext|>


<commit_before>//! Interfaces and implementations specific to integration with `ndarray`.
//!
//! This module introduces the trait [`IntoNdArray`], which is implemented for
//! all NIfTI volume types and enable their mapping into an [`Array`] with a
//! dynamic number of dimensions and an abitrary element type. The affine
//! scaling of the values (from the `scl_slope` and `scl_inter` attributes) are
//! also considered in this transformation.
//!
//! A target [element type] needs to be provided at compile time, which is
//! usually the data type that the user wishes to work the array with. If the
//! source and target types do not match, each voxel is cast in a way as to
//! avoid loss of precision.
//!
//! #### Note on memory order
//!
//! NIfTI volumes are usually stored in disk in column major order (also called
//! Fortran order). As such, the array resulting from this operation will also
//! be in this memory order, rather than the usual row major order (AKA C
//! ordering). When accessing the array, one should consider any potential
//! bottlenecks emerging from this ordering in their data processing pipelines.
//! Namely, it might be faster to produce output arrays in column major order
//! as well.
//!
//! [`IntoNdArray`]: ./trait.IntoNdArray.html
//! [`Array`]: ../../../ndarray/type.Array.html
//! [element type]: ../element/trait.DataElement.html
//!
use error::Result;
use ndarray::{Array, Axis, Ix, IxDyn};
use num_traits::AsPrimitive;
use std::ops::{Add, Mul};
use volume::element::DataElement;
use volume::NiftiVolume;

/// Trait for volumes which can be converted to an ndarray.
///
/// Please see the [module-level documentation](index.html) for more details.
pub trait IntoNdArray {
    /// Consume the volume into an ndarray with the same number of dimensions
    /// and the given target element type `T`.
    #[deprecated(
        since = "0.6.0",
        note = "unconventional naming, please use/implement `into_ndarray` instead"
    )]
    fn to_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        Self: Sized,
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>,
    {
        self.into_ndarray::<T>()
    }

    /// Consume the volume into an ndarray with the same number of dimensions
    /// and the given target element type `T`.
    fn into_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>;
}

impl<V> IntoNdArray for super::SliceView<V>
where
    V: NiftiVolume + IntoNdArray,
{
    fn into_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>,
    {
        // TODO optimize this implementation (we don't need the whole volume)
        let volume = self.volume.into_ndarray()?;
        Ok(volume.into_subview(Axis(self.axis as Ix), self.index as usize))
    }
}
<commit_msg>Change deprecated function.<commit_after>//! Interfaces and implementations specific to integration with `ndarray`.
//!
//! This module introduces the trait [`IntoNdArray`], which is implemented for
//! all NIfTI volume types and enable their mapping into an [`Array`] with a
//! dynamic number of dimensions and an abitrary element type. The affine
//! scaling of the values (from the `scl_slope` and `scl_inter` attributes) are
//! also considered in this transformation.
//!
//! A target [element type] needs to be provided at compile time, which is
//! usually the data type that the user wishes to work the array with. If the
//! source and target types do not match, each voxel is cast in a way as to
//! avoid loss of precision.
//!
//! #### Note on memory order
//!
//! NIfTI volumes are usually stored in disk in column major order (also called
//! Fortran order). As such, the array resulting from this operation will also
//! be in this memory order, rather than the usual row major order (AKA C
//! ordering). When accessing the array, one should consider any potential
//! bottlenecks emerging from this ordering in their data processing pipelines.
//! Namely, it might be faster to produce output arrays in column major order
//! as well.
//!
//! [`IntoNdArray`]: ./trait.IntoNdArray.html
//! [`Array`]: ../../../ndarray/type.Array.html
//! [element type]: ../element/trait.DataElement.html
//!
use error::Result;
use ndarray::{Array, Axis, Ix, IxDyn};
use num_traits::AsPrimitive;
use std::ops::{Add, Mul};
use volume::element::DataElement;
use volume::NiftiVolume;

/// Trait for volumes which can be converted to an ndarray.
///
/// Please see the [module-level documentation](index.html) for more details.
pub trait IntoNdArray {
    /// Consume the volume into an ndarray with the same number of dimensions
    /// and the given target element type `T`.
    #[deprecated(
        since = "0.6.0",
        note = "unconventional naming, please use/implement `into_ndarray` instead"
    )]
    fn to_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        Self: Sized,
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>,
    {
        self.into_ndarray::<T>()
    }

    /// Consume the volume into an ndarray with the same number of dimensions
    /// and the given target element type `T`.
    fn into_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>;
}

impl<V> IntoNdArray for super::SliceView<V>
where
    V: NiftiVolume + IntoNdArray,
{
    fn into_ndarray<T>(self) -> Result<Array<T, IxDyn>>
    where
        T: Mul<Output = T>,
        T: Add<Output = T>,
        T: DataElement,
        u8: AsPrimitive<T>,
        i8: AsPrimitive<T>,
        u16: AsPrimitive<T>,
        i16: AsPrimitive<T>,
        u32: AsPrimitive<T>,
        i32: AsPrimitive<T>,
        u64: AsPrimitive<T>,
        i64: AsPrimitive<T>,
        f32: AsPrimitive<T>,
        f64: AsPrimitive<T>,
    {
        // TODO optimize this implementation (we don't need the whole volume)
        let volume = self.volume.into_ndarray()?;
        Ok(volume.index_axis_move(Axis(self.axis as Ix), self.index as usize))
    }
}
<|endoftext|>


<commit_before>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;
// extern crate xinput;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::ptr::null_mut;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;

// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(dwUserIndex:DWORD, pState: *mut XINPUT_STATE) -> DWORD;
extern "system" fn XInputGetStateStub(dwUserIndex: DWORD, pState: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = XInputGetStateStub;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: u32, y_offset: u32) {

    let width = buffer.width;
    let height = buffer.height;
    let bytes_per_pixel = buffer.bytes_per_pixel;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x as u32 + x_offset) << 0 ) + ((y as u32 + y_offset) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);

        //Version available on modern windows without DX SDK Install
        let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

        if xinput_module == 0 as HMODULE {
            //Version available on old windows without DX SDK Install
            xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
        }

        if xinput_module != 0 as HMODULE {
            XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
        }
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                // let controller_found = xinput::XInputGetState(controller_index as DWORD, &mut controller_state);
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    println!("Controller found {}", controller_index);
                    let pad = controller_state.Gamepad;

                    let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += 1; }
                    if stick_y > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += 1; }
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset*pan_speed,y_offset*pan_speed);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<commit_msg>Some updates to input, allowed overflowing so moving left on screen works<commit_after>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::num::Wrapping;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;
// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_STATE) -> DWORD;
extern "system" fn xinput_get_state_stub(_: DWORD, _: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = xinput_get_state_stub;

type XInputSetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_VIBRATION) -> DWORD;
extern "system" fn xinput_set_state_stub(_: DWORD, _: *mut XINPUT_VIBRATION) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_SET_STATE_PTR: XInputSetStateType = xinput_set_state_stub;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn win32_load_xinput() {
        //Version available on modern windows without DX SDK Install
        let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

        if xinput_module == 0 as HMODULE {
            //Version available on old windows without DX SDK Install
            xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
        }

        if xinput_module != 0 as HMODULE {
            XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
            XINPUT_SET_STATE_PTR = mem::transmute::<FARPROC, XInputSetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputSetState")));
        }
}

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: i16, y_offset: i16) {

    let width = buffer.width as i16;
    let height = buffer.height as i16;
    let bytes_per_pixel = buffer.bytes_per_pixel as i16;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x.wrapping_add(x_offset) as u8) << 0) as u32 + (((y.wrapping_add(-y_offset) as u8) as u32) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);
        win32_load_xinput();
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    let pad = controller_state.Gamepad;

                    let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += stick_x >> 12; }
                    if stick_y.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += stick_y >> 12; }

                    //XINPUT_SET_STATE_PTR(controller_index, &mut XINPUT_VIBRATION { wLeftMotorSpeed: 60000, wRightMotorSpeed: 60000 });
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset, y_offset);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
            let vk_code = w_param;
            let was_down = (l_param & 1 << 30) != 0;
            let is_down = (l_param & 1 << 31) == 0;

            if vk_code == 'W' as u64 {
            }
            if vk_code == 'A' as u64 {
            }
            if vk_code == 'S' as u64 {
            }
            if vk_code == 'D' as u64 {
            }
            if vk_code == 'Q' as u64 {
            }
            if vk_code == VK_UP as u64 {
            }
            if vk_code == VK_DOWN as u64 {
            }
            if vk_code == VK_LEFT as u64 {
            }
            if vk_code == VK_RIGHT as u64 {
            }
            if vk_code == VK_ESCAPE as u64 {
                if is_down != was_down {
                    println!("ESCAPE");
                }
            }
            if vk_code == VK_SPACE as u64 {
                println!("\n");
            }

        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::disk::Disk;
use sys::processor::*;
use sys::users::get_users;

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::mem::{size_of, zeroed};
use std::time::SystemTime;

use LoadAvg;
use Networks;
use Pid;
use ProcessExt;
use RefreshKind;
use SystemExt;
use User;

use windows::process::{
    compute_cpu_usage, get_handle, get_system_computation_time, update_disk_usage, update_memory,
    Process,
};
use windows::tools::*;

use ntapi::ntexapi::{
    NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION,
};
use rayon::prelude::*;
use winapi::shared::minwindef::FALSE;
use winapi::shared::ntdef::{PVOID, ULONG};
use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH;
use winapi::um::minwinbase::STILL_ACTIVE;
use winapi::um::processthreadsapi::GetExitCodeProcess;
use winapi::um::sysinfoapi::{GetTickCount64, GlobalMemoryStatusEx, MEMORYSTATUSEX};
use winapi::um::winnt::HANDLE;

/// Struct containing the system's information.
pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_available: u64,
    swap_total: u64,
    swap_free: u64,
    global_processor: Processor,
    processors: Vec<Processor>,
    components: Vec<Component>,
    disks: Vec<Disk>,
    query: Option<Query>,
    networks: Networks,
    boot_time: u64,
    users: Vec<User>,
}

// Useful for parallel iterations.
struct Wrap<T>(T);

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

unsafe fn boot_time() -> u64 {
    match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
        Ok(n) => n.as_secs() - GetTickCount64() / 1000,
        Err(_e) => {
            sysinfo_debug!("Failed to compute boot time: {:?}", _e);
            0
        }
    }
}

impl SystemExt for System {
    #[allow(non_snake_case)]
    fn new_with_specifics(refreshes: RefreshKind) -> System {
        let (processors, vendor_id, brand) = init_processors();
        let mut s = System {
            process_list: HashMap::with_capacity(500),
            mem_total: 0,
            mem_available: 0,
            swap_total: 0,
            swap_free: 0,
            global_processor: Processor::new_with_values("Total CPU", vendor_id, brand, 0),
            processors,
            components: Vec::new(),
            disks: Vec::with_capacity(2),
            query: Query::new(),
            networks: Networks::new(),
            boot_time: unsafe { boot_time() },
            users: Vec::new(),
        };
        // TODO: in case a translation fails, it might be nice to log it somewhere...
        if let Some(ref mut query) = s.query {
            let x = unsafe { load_symbols() };
            if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) {
                // let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x);
                let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x);
                if let Some(ref proc_time_trans) = proc_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans),
                        query,
                        get_key_used(&mut s.global_processor),
                        "tot_0".to_owned(),
                    );
                }
                for (pos, proc_) in s.processors.iter_mut().enumerate() {
                    if let Some(ref proc_time_trans) = proc_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans),
                            query,
                            get_key_used(proc_),
                            format!("{}_0", pos),
                        );
                    }
                }
            } else {
                sysinfo_debug!("failed to get `Processor` translation");
            }
        }
        s.refresh_specifics(refreshes);
        s
    }

    fn refresh_cpu(&mut self) {
        if let Some(ref mut query) = self.query {
            query.refresh();
            let mut used_time = None;
            if let Some(ref key_used) = *get_key_used(&mut self.global_processor) {
                used_time = Some(
                    query
                        .get(&key_used.unique_id)
                        .expect("global_key_idle disappeared"),
                );
            }
            if let Some(used_time) = used_time {
                self.global_processor.set_cpu_usage(used_time);
            }
            for p in self.processors.iter_mut() {
                let mut used_time = None;
                if let Some(ref key_used) = *get_key_used(p) {
                    used_time = Some(
                        query
                            .get(&key_used.unique_id)
                            .expect("key_used disappeared"),
                    );
                }
                if let Some(used_time) = used_time {
                    p.set_cpu_usage(used_time);
                }
            }
        }
    }

    fn refresh_memory(&mut self) {
        unsafe {
            let mut mem_info: MEMORYSTATUSEX = zeroed();
            mem_info.dwLength = size_of::<MEMORYSTATUSEX>() as u32;
            GlobalMemoryStatusEx(&mut mem_info);
            self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64) / 1_000;
            self.mem_available = auto_cast!(mem_info.ullAvailPhys, u64) / 1_000;
            //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64);
            //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64);
        }
    }

    fn refresh_components_list(&mut self) {
        self.components = component::get_components();
    }

    #[allow(clippy::map_entry)]
    fn refresh_process(&mut self, pid: Pid) -> bool {
        if self.process_list.contains_key(&pid) {
            if !refresh_existing_process(self, pid) {
                self.process_list.remove(&pid);
                return false;
            }
            true
        } else if let Some(mut p) = Process::new_from_pid(pid) {
            let system_time = get_system_computation_time();
            compute_cpu_usage(&mut p, self.processors.len() as u64, system_time);
            update_disk_usage(&mut p);
            self.process_list.insert(pid, p);
            true
        } else {
            false
        }
    }

    #[allow(clippy::cast_ptr_alignment)]
    fn refresh_processes(&mut self) {
        // Windows 10 notebook requires at least 512KiB of memory to make it in one go
        let mut buffer_size: usize = 512 * 1024;

        loop {
            let mut process_information: Vec<u8> = Vec::with_capacity(buffer_size);

            let mut cb_needed = 0;
            let ntstatus = unsafe {
                process_information.set_len(buffer_size);
                NtQuerySystemInformation(
                    SystemProcessInformation,
                    process_information.as_mut_ptr() as PVOID,
                    buffer_size as ULONG,
                    &mut cb_needed,
                )
            };

            if ntstatus != STATUS_INFO_LENGTH_MISMATCH {
                if ntstatus < 0 {
                    sysinfo_debug!(
                        "Couldn't get process infos: NtQuerySystemInformation returned {}",
                        ntstatus
                    );
                }

                // Parse the data block to get process information
                let mut process_ids = Vec::with_capacity(500);
                let mut process_information_offset = 0;
                loop {
                    let p = unsafe {
                        process_information
                            .as_ptr()
                            .offset(process_information_offset)
                            as *const SYSTEM_PROCESS_INFORMATION
                    };
                    let pi = unsafe { &*p };

                    process_ids.push(Wrap(p));

                    if pi.NextEntryOffset == 0 {
                        break;
                    }

                    process_information_offset += pi.NextEntryOffset as isize;
                }
                let nb_processors = self.processors.len() as u64;
                let process_list = Wrap(UnsafeCell::new(&mut self.process_list));
                let system_time = get_system_computation_time();
                // TODO: instead of using parallel iterator only here, would be better to be able
                //       to run it over `process_information` directly!
                let processes = process_ids
                    .into_par_iter()
                    .filter_map(|pi| unsafe {
                        let pi = *pi.0;
                        let pid = pi.UniqueProcessId as usize;
                        if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) {
                            proc_.memory = (pi.WorkingSetSize as u64) / 1_000;
                            proc_.virtual_memory = (pi.VirtualSize as u64) / 1_000;
                            compute_cpu_usage(proc_, nb_processors, system_time);
                            update_disk_usage(proc_);
                            proc_.updated = true;
                            return None;
                        }
                        let name = get_process_name(&pi, pid);
                        let mut p = Process::new_full(
                            pid,
                            if pi.InheritedFromUniqueProcessId as usize != 0 {
                                Some(pi.InheritedFromUniqueProcessId as usize)
                            } else {
                                None
                            },
                            (pi.WorkingSetSize as u64) / 1_000,
                            (pi.VirtualSize as u64) / 1_000,
                            name,
                        );
                        compute_cpu_usage(&mut p, nb_processors, system_time);
                        update_disk_usage(&mut p);
                        Some(p)
                    })
                    .collect::<Vec<_>>();
                self.process_list.retain(|_, v| {
                    let x = v.updated;
                    v.updated = false;
                    x
                });
                for p in processes.into_iter() {
                    self.process_list.insert(p.pid(), p);
                }

                break;
            }

            // GetNewBufferSize
            if cb_needed == 0 {
                buffer_size *= 2;
                continue;
            }
            // allocating a few more kilo bytes just in case there are some new process
            // kicked in since new call to NtQuerySystemInformation
            buffer_size = (cb_needed + (1024 * 10)) as usize;
        }
    }

    fn refresh_disks_list(&mut self) {
        self.disks = unsafe { get_disks() };
    }

    fn refresh_users_list(&mut self) {
        self.users = unsafe { get_users() };
    }

    fn get_processes(&self) -> &HashMap<Pid, Process> {
        &self.process_list
    }

    fn get_process(&self, pid: Pid) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    fn get_global_processor_info(&self) -> &Processor {
        &self.global_processor
    }

    fn get_processors(&self) -> &[Processor] {
        &self.processors
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        // MEMORYSTATUSEX doesn't report free memory
        self.mem_available
    }

    fn get_available_memory(&self) -> u64 {
        self.mem_available
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_available
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components(&self) -> &[Component] {
        &self.components
    }

    fn get_components_mut(&mut self) -> &mut [Component] {
        &mut self.components
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks
    }

    fn get_disks_mut(&mut self) -> &mut [Disk] {
        &mut self.disks
    }

    fn get_users(&self) -> &[User] {
        &self.users
    }

    fn get_networks(&self) -> &Networks {
        &self.networks
    }

    fn get_networks_mut(&mut self) -> &mut Networks {
        &mut self.networks
    }

    fn get_uptime(&self) -> u64 {
        unsafe { GetTickCount64() / 1000 }
    }

    fn get_boot_time(&self) -> u64 {
        self.boot_time
    }

    fn get_load_average(&self) -> LoadAvg {
        get_load_average()
    }
}

impl Default for System {
    fn default() -> System {
        System::new()
    }
}

fn is_proc_running(handle: HANDLE) -> bool {
    let mut exit_code = 0;
    let ret = unsafe { GetExitCodeProcess(handle, &mut exit_code) };
    !(ret == FALSE || exit_code != STILL_ACTIVE)
}

fn refresh_existing_process(s: &mut System, pid: Pid) -> bool {
    if let Some(ref mut entry) = s.process_list.get_mut(&(pid as usize)) {
        if !is_proc_running(get_handle(entry)) {
            return false;
        }
        update_memory(entry);
        update_disk_usage(entry);
        compute_cpu_usage(
            entry,
            s.processors.len() as u64,
            get_system_computation_time(),
        );
        true
    } else {
        false
    }
}

pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String {
    let name = &process.ImageName;
    if name.Buffer.is_null() {
        match process_id {
            0 => "Idle".to_owned(),
            4 => "System".to_owned(),
            _ => format!("<no name> Process {}", process_id),
        }
    } else {
        let slice = unsafe {
            std::slice::from_raw_parts(
                name.Buffer,
                //The length is in bytes, not the length of string
                name.Length as usize / std::mem::size_of::<u16>(),
            )
        };

        String::from_utf16_lossy(slice)
    }
}
<commit_msg>Fix clippy lint on windows<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::disk::Disk;
use sys::processor::*;
use sys::users::get_users;

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::mem::{size_of, zeroed};
use std::time::SystemTime;

use LoadAvg;
use Networks;
use Pid;
use ProcessExt;
use RefreshKind;
use SystemExt;
use User;

use windows::process::{
    compute_cpu_usage, get_handle, get_system_computation_time, update_disk_usage, update_memory,
    Process,
};
use windows::tools::*;

use ntapi::ntexapi::{
    NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION,
};
use rayon::prelude::*;
use winapi::shared::minwindef::FALSE;
use winapi::shared::ntdef::{PVOID, ULONG};
use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH;
use winapi::um::minwinbase::STILL_ACTIVE;
use winapi::um::processthreadsapi::GetExitCodeProcess;
use winapi::um::sysinfoapi::{GetTickCount64, GlobalMemoryStatusEx, MEMORYSTATUSEX};
use winapi::um::winnt::HANDLE;

/// Struct containing the system's information.
pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_available: u64,
    swap_total: u64,
    swap_free: u64,
    global_processor: Processor,
    processors: Vec<Processor>,
    components: Vec<Component>,
    disks: Vec<Disk>,
    query: Option<Query>,
    networks: Networks,
    boot_time: u64,
    users: Vec<User>,
}

// Useful for parallel iterations.
struct Wrap<T>(T);

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

unsafe fn boot_time() -> u64 {
    match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
        Ok(n) => n.as_secs() - GetTickCount64() / 1000,
        Err(_e) => {
            sysinfo_debug!("Failed to compute boot time: {:?}", _e);
            0
        }
    }
}

impl SystemExt for System {
    #[allow(non_snake_case)]
    fn new_with_specifics(refreshes: RefreshKind) -> System {
        let (processors, vendor_id, brand) = init_processors();
        let mut s = System {
            process_list: HashMap::with_capacity(500),
            mem_total: 0,
            mem_available: 0,
            swap_total: 0,
            swap_free: 0,
            global_processor: Processor::new_with_values("Total CPU", vendor_id, brand, 0),
            processors,
            components: Vec::new(),
            disks: Vec::with_capacity(2),
            query: Query::new(),
            networks: Networks::new(),
            boot_time: unsafe { boot_time() },
            users: Vec::new(),
        };
        // TODO: in case a translation fails, it might be nice to log it somewhere...
        if let Some(ref mut query) = s.query {
            let x = unsafe { load_symbols() };
            if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) {
                // let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x);
                let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x);
                if let Some(ref proc_time_trans) = proc_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans),
                        query,
                        get_key_used(&mut s.global_processor),
                        "tot_0".to_owned(),
                    );
                }
                for (pos, proc_) in s.processors.iter_mut().enumerate() {
                    if let Some(ref proc_time_trans) = proc_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans),
                            query,
                            get_key_used(proc_),
                            format!("{}_0", pos),
                        );
                    }
                }
            } else {
                sysinfo_debug!("failed to get `Processor` translation");
            }
        }
        s.refresh_specifics(refreshes);
        s
    }

    fn refresh_cpu(&mut self) {
        if let Some(ref mut query) = self.query {
            query.refresh();
            let mut used_time = None;
            if let Some(ref key_used) = *get_key_used(&mut self.global_processor) {
                used_time = Some(
                    query
                        .get(&key_used.unique_id)
                        .expect("global_key_idle disappeared"),
                );
            }
            if let Some(used_time) = used_time {
                self.global_processor.set_cpu_usage(used_time);
            }
            for p in self.processors.iter_mut() {
                let mut used_time = None;
                if let Some(ref key_used) = *get_key_used(p) {
                    used_time = Some(
                        query
                            .get(&key_used.unique_id)
                            .expect("key_used disappeared"),
                    );
                }
                if let Some(used_time) = used_time {
                    p.set_cpu_usage(used_time);
                }
            }
        }
    }

    fn refresh_memory(&mut self) {
        unsafe {
            let mut mem_info: MEMORYSTATUSEX = zeroed();
            mem_info.dwLength = size_of::<MEMORYSTATUSEX>() as u32;
            GlobalMemoryStatusEx(&mut mem_info);
            self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64) / 1_000;
            self.mem_available = auto_cast!(mem_info.ullAvailPhys, u64) / 1_000;
            //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64);
            //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64);
        }
    }

    fn refresh_components_list(&mut self) {
        self.components = component::get_components();
    }

    #[allow(clippy::map_entry)]
    fn refresh_process(&mut self, pid: Pid) -> bool {
        if self.process_list.contains_key(&pid) {
            if !refresh_existing_process(self, pid) {
                self.process_list.remove(&pid);
                return false;
            }
            true
        } else if let Some(mut p) = Process::new_from_pid(pid) {
            let system_time = get_system_computation_time();
            compute_cpu_usage(&mut p, self.processors.len() as u64, system_time);
            update_disk_usage(&mut p);
            self.process_list.insert(pid, p);
            true
        } else {
            false
        }
    }

    #[allow(clippy::cast_ptr_alignment)]
    fn refresh_processes(&mut self) {
        // Windows 10 notebook requires at least 512KiB of memory to make it in one go
        let mut buffer_size: usize = 512 * 1024;

        loop {
            let mut process_information: Vec<u8> = Vec::with_capacity(buffer_size);

            let mut cb_needed = 0;
            let ntstatus = unsafe {
                process_information.set_len(buffer_size);
                NtQuerySystemInformation(
                    SystemProcessInformation,
                    process_information.as_mut_ptr() as PVOID,
                    buffer_size as ULONG,
                    &mut cb_needed,
                )
            };

            if ntstatus != STATUS_INFO_LENGTH_MISMATCH {
                if ntstatus < 0 {
                    sysinfo_debug!(
                        "Couldn't get process infos: NtQuerySystemInformation returned {}",
                        ntstatus
                    );
                }

                // Parse the data block to get process information
                let mut process_ids = Vec::with_capacity(500);
                let mut process_information_offset = 0;
                loop {
                    let p = unsafe {
                        process_information
                            .as_ptr()
                            .offset(process_information_offset)
                            as *const SYSTEM_PROCESS_INFORMATION
                    };
                    let pi = unsafe { &*p };

                    process_ids.push(Wrap(p));

                    if pi.NextEntryOffset == 0 {
                        break;
                    }

                    process_information_offset += pi.NextEntryOffset as isize;
                }
                let nb_processors = self.processors.len() as u64;
                let process_list = Wrap(UnsafeCell::new(&mut self.process_list));
                let system_time = get_system_computation_time();
                // TODO: instead of using parallel iterator only here, would be better to be able
                //       to run it over `process_information` directly!
                let processes = process_ids
                    .into_par_iter()
                    .filter_map(|pi| unsafe {
                        let pi = *pi.0;
                        let pid = pi.UniqueProcessId as usize;
                        if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) {
                            proc_.memory = (pi.WorkingSetSize as u64) / 1_000;
                            proc_.virtual_memory = (pi.VirtualSize as u64) / 1_000;
                            compute_cpu_usage(proc_, nb_processors, system_time);
                            update_disk_usage(proc_);
                            proc_.updated = true;
                            return None;
                        }
                        let name = get_process_name(&pi, pid);
                        let mut p = Process::new_full(
                            pid,
                            if pi.InheritedFromUniqueProcessId as usize != 0 {
                                Some(pi.InheritedFromUniqueProcessId as usize)
                            } else {
                                None
                            },
                            (pi.WorkingSetSize as u64) / 1_000,
                            (pi.VirtualSize as u64) / 1_000,
                            name,
                        );
                        compute_cpu_usage(&mut p, nb_processors, system_time);
                        update_disk_usage(&mut p);
                        Some(p)
                    })
                    .collect::<Vec<_>>();
                self.process_list.retain(|_, v| {
                    let x = v.updated;
                    v.updated = false;
                    x
                });
                for p in processes.into_iter() {
                    self.process_list.insert(p.pid(), p);
                }

                break;
            }

            // GetNewBufferSize
            if cb_needed == 0 {
                buffer_size *= 2;
                continue;
            }
            // allocating a few more kilo bytes just in case there are some new process
            // kicked in since new call to NtQuerySystemInformation
            buffer_size = (cb_needed + (1024 * 10)) as usize;
        }
    }

    fn refresh_disks_list(&mut self) {
        self.disks = unsafe { get_disks() };
    }

    fn refresh_users_list(&mut self) {
        self.users = unsafe { get_users() };
    }

    fn get_processes(&self) -> &HashMap<Pid, Process> {
        &self.process_list
    }

    fn get_process(&self, pid: Pid) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    fn get_global_processor_info(&self) -> &Processor {
        &self.global_processor
    }

    fn get_processors(&self) -> &[Processor] {
        &self.processors
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        // MEMORYSTATUSEX doesn't report free memory
        self.mem_available
    }

    fn get_available_memory(&self) -> u64 {
        self.mem_available
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_available
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components(&self) -> &[Component] {
        &self.components
    }

    fn get_components_mut(&mut self) -> &mut [Component] {
        &mut self.components
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks
    }

    fn get_disks_mut(&mut self) -> &mut [Disk] {
        &mut self.disks
    }

    fn get_users(&self) -> &[User] {
        &self.users
    }

    fn get_networks(&self) -> &Networks {
        &self.networks
    }

    fn get_networks_mut(&mut self) -> &mut Networks {
        &mut self.networks
    }

    fn get_uptime(&self) -> u64 {
        unsafe { GetTickCount64() / 1000 }
    }

    fn get_boot_time(&self) -> u64 {
        self.boot_time
    }

    fn get_load_average(&self) -> LoadAvg {
        get_load_average()
    }
}

impl Default for System {
    fn default() -> System {
        System::new()
    }
}

fn is_proc_running(handle: HANDLE) -> bool {
    let mut exit_code = 0;
    let ret = unsafe { GetExitCodeProcess(handle, &mut exit_code) };
    !(ret == FALSE || exit_code != STILL_ACTIVE)
}

fn refresh_existing_process(s: &mut System, pid: Pid) -> bool {
    if let Some(ref mut entry) = s.process_list.get_mut(&(pid as usize)) {
        if !is_proc_running(get_handle(entry)) {
            return false;
        }
        update_memory(entry);
        update_disk_usage(entry);
        compute_cpu_usage(
            entry,
            s.processors.len() as u64,
            get_system_computation_time(),
        );
        true
    } else {
        false
    }
}

#[allow(clippy::size_of_in_element_count)]
//^ needed for "name.Length as usize / std::mem::size_of::<u16>()"
pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String {
    let name = &process.ImageName;
    if name.Buffer.is_null() {
        match process_id {
            0 => "Idle".to_owned(),
            4 => "System".to_owned(),
            _ => format!("<no name> Process {}", process_id),
        }
    } else {
        let slice = unsafe {
            std::slice::from_raw_parts(
                name.Buffer,
                // The length is in bytes, not the length of string
                name.Length as usize / std::mem::size_of::<u16>(),
            )
        };

        String::from_utf16_lossy(slice)
    }
}
<|endoftext|>