<commit_before>//! Recycle allocator
//! Uses freed frames if possible, then uses inner allocator

use collections::Vec;

use paging::PhysicalAddress;

use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter};

pub struct RecycleAllocator<T: FrameAllocator> {
    inner: T,
    noncore: bool,
    free: Vec<(usize, usize)>,
}

impl<T: FrameAllocator> RecycleAllocator<T> {
    pub fn new(inner: T) -> Self {
        Self {
            inner: inner,
            noncore: false,
            free: Vec::new(),
        }
    }

    fn free_count(&self) -> usize {
        let mut count = 0;
        for free in self.free.iter() {
            count += free.1;
        }
        count
    }

    fn merge(&mut self, address: usize, count: usize) -> bool {
        for i in 0 .. self.free.len() {
            let changed = {
                let mut free = &mut self.free[i];
                if address + count * 4096 == free.0 {
                    free.0 = address;
                    free.1 += count;
                    true
                } else if free.0 + free.1 * 4096 == address {
                    free.1 += count;
                    true
                } else {
                    false
                }
            };

            if changed {
                //TODO: Use do not use recursion
                let (address, count) = self.free[i];
                if self.merge(address, count) {
                    self.free.remove(i);
                }
                return true;
            }
        }

        false
    }
}

impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> {
    fn set_noncore(&mut self, noncore: bool) {
        self.noncore = noncore;
    }

    fn free_frames(&self) -> usize {
        self.inner.free_frames() + self.free_count()
    }

    fn used_frames(&self) -> usize {
        self.inner.used_frames() - self.free_count()
    }

    fn allocate_frames(&mut self, count: usize) -> Option<Frame> {
        let mut small_i = None;
        {
            let mut small = (0, 0);
            for i in 0..self.free.len() {
                let free = self.free[i];
                // Later entries can be removed faster
                if free.1 >= count {
                    if free.1 <= small.1 || small_i.is_none() {
                        small_i = Some(i);
                        small = free;
                    }
                }
            }
        }

        if let Some(i) = small_i {
            let (address, remove) = {
                let free = &mut self.free[i];
                free.1 -= 1;
                (free.0 + free.1 * 4096, free.1 == 0)
            };

            if remove {
                self.free.remove(i);
            }

            //println!("Restoring frame {:?}, {}", frame, count);
            Some(Frame::containing_address(PhysicalAddress::new(address)))
        } else {
            //println!("No saved frames {}", count);
            self.inner.allocate_frames(count)
        }
    }

    fn deallocate_frames(&mut self, frame: Frame, count: usize) {
        if self.noncore {
            let address = frame.start_address().get();
            if ! self.merge(address, count) {
                self.free.push((address, count));
            }
        } else {
            //println!("Could not save frame {:?}, {}", frame, count);
            self.inner.deallocate_frames(frame, count);
        }
    }
}
<commit_msg>Fix overallocation<commit_after>//! Recycle allocator
//! Uses freed frames if possible, then uses inner allocator

use collections::Vec;

use paging::PhysicalAddress;

use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter};

pub struct RecycleAllocator<T: FrameAllocator> {
    inner: T,
    noncore: bool,
    free: Vec<(usize, usize)>,
}

impl<T: FrameAllocator> RecycleAllocator<T> {
    pub fn new(inner: T) -> Self {
        Self {
            inner: inner,
            noncore: false,
            free: Vec::new(),
        }
    }

    fn free_count(&self) -> usize {
        let mut count = 0;
        for free in self.free.iter() {
            count += free.1;
        }
        count
    }

    fn merge(&mut self, address: usize, count: usize) -> bool {
        for i in 0 .. self.free.len() {
            let changed = {
                let mut free = &mut self.free[i];
                if address + count * 4096 == free.0 {
                    free.0 = address;
                    free.1 += count;
                    true
                } else if free.0 + free.1 * 4096 == address {
                    free.1 += count;
                    true
                } else {
                    false
                }
            };

            if changed {
                //TODO: Use do not use recursion
                let (address, count) = self.free[i];
                if self.merge(address, count) {
                    self.free.remove(i);
                }
                return true;
            }
        }

        false
    }
}

impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> {
    fn set_noncore(&mut self, noncore: bool) {
        self.noncore = noncore;
    }

    fn free_frames(&self) -> usize {
        self.inner.free_frames() + self.free_count()
    }

    fn used_frames(&self) -> usize {
        self.inner.used_frames() - self.free_count()
    }

    fn allocate_frames(&mut self, count: usize) -> Option<Frame> {
        let mut small_i = None;
        {
            let mut small = (0, 0);
            for i in 0..self.free.len() {
                let free = self.free[i];
                // Later entries can be removed faster
                if free.1 >= count {
                    if free.1 <= small.1 || small_i.is_none() {
                        small_i = Some(i);
                        small = free;
                    }
                }
            }
        }

        if let Some(i) = small_i {
            let (address, remove) = {
                let free = &mut self.free[i];
                free.1 -= count;
                (free.0 + free.1 * 4096, free.1 == 0)
            };

            if remove {
                self.free.remove(i);
            }

            //println!("Restoring frame {:?}, {}", frame, count);
            Some(Frame::containing_address(PhysicalAddress::new(address)))
        } else {
            //println!("No saved frames {}", count);
            self.inner.allocate_frames(count)
        }
    }

    fn deallocate_frames(&mut self, frame: Frame, count: usize) {
        if self.noncore {
            let address = frame.start_address().get();
            if ! self.merge(address, count) {
                self.free.push((address, count));
            }
        } else {
            //println!("Could not save frame {:?}, {}", frame, count);
            self.inner.deallocate_frames(frame, count);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Replace some unsafe code for type checks with equivalent safe code<commit_after><|endoftext|>


<commit_before><commit_msg>Fix equivalent<commit_after><|endoftext|>


<commit_before>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::slice;

use imp_prelude::*;

/// Create a zero-dimensional array with the element `x`.
pub fn arr0(x: A) -> Array0
{
    unsafe { ArrayBase::from_shape_vec_unchecked((), vec![x]) }
}

/// Create a one-dimensional array with elements from `xs`.
pub fn arr1(xs: &[A]) -> Array1 {
    ArrayBase::from_vec(xs.to_vec())
}

/// Create a one-dimensional array with elements from `xs`.
pub fn rcarr1(xs: &[A]) -> RcArray {
    arr1(xs).into_shared()
}

/// Create a zero-dimensional array view borrowing `x`.
pub fn aview0(x: &A) -> ArrayView0 {
    unsafe { ArrayView::new_(x, Ix0(), Ix0()) }
}

/// Create a one-dimensional array view with elements borrowing `xs`.
///
/// ```
/// use ndarray::aview1;
///
/// let data = [1.0; 1024];
///
/// // Create a 2D array view from borrowed data
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
///
/// assert!(
///     a2d.scalar_sum() == 1024.0
/// );
/// ```
pub fn aview1(xs: &[A]) -> ArrayView1 {
    ArrayView::from(xs)
}

/// Create a two-dimensional array view with elements borrowing `xs`.
pub fn aview2<A, V: FixedInitializer<Elem=A>>(xs: &[V]) -> ArrayView2 {
    let cols = V::len();
    let rows = xs.len();
    let data = unsafe {
        slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows)
    };
    let dim = Ix2(rows, cols);
    unsafe {
        let strides = dim.default_strides();
        ArrayView::new_(data.as_ptr(), dim, strides)
    }
}

/// Create a one-dimensional read-write array view with elements borrowing `xs`.
///
/// ```
/// #[macro_use(s)]
/// extern crate ndarray;
///
/// use ndarray::aview_mut1;
///
/// // Create an array view over some data, then slice it and modify it.
/// fn main() {
///     let mut data = [0; 1024];
///     {
///         let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
///         a.slice_mut(s![.., ..;3]).fill(5);
///     }
///     assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
/// }
/// ```
pub fn aview_mut1(xs: &mut [A]) -> ArrayViewMut1 {
    ArrayViewMut::from(xs)
}

/// Fixed-size array used for array initialization
pub unsafe trait FixedInitializer {
    type Elem;
    fn as_init_slice(&self) -> &[Self::Elem];
    fn len() -> usize;
}

macro_rules! impl_arr_init {
    (__impl $n: expr) => (
        unsafe impl<T> FixedInitializer for [T;  $n] {
            type Elem = T;
            fn as_init_slice(&self) -> &[T] { self }
            fn len() -> usize { $n }
        }
    );
    () => ();
    ($n: expr, $($m:expr,)*) => (
        impl_arr_init!(__impl $n);
        impl_arr_init!($($m,)*);
    )

}

impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);

/// Create a two-dimensional array with elements from `xs`.
///
/// ```
/// use ndarray::arr2;
///
/// let a = arr2(&[[1, 2, 3],
///                [4, 5, 6]]);
/// assert!(
///     a.shape() == [2, 3]
/// );
/// ```
pub fn arr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> Array2 {
    let (m, n) = (xs.len(), V::len());
    let dim = Ix2(m, n);
    let mut result = Vec::::with_capacity(dim.size());
    for snd in xs {
        result.extend_from_slice(snd.as_init_slice());
    }
    unsafe {
        ArrayBase::from_shape_vec_unchecked(dim, result)
    }
}

/// Create a two-dimensional array with elements from `xs`.
///
pub fn rcarr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> RcArray {
    arr2(xs).into_shared()
}

/// Create a three-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
/// ```
/// use ndarray::arr3;
///
/// let a = arr3(&[[[1, 2],
///                 [3, 4]],
///                [[5, 6],
///                 [7, 8]],
///                [[9, 0],
///                 [1, 2]]]);
/// assert!(
///     a.shape() == [3, 2, 2]
/// );
/// ```
pub fn arr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> Array3
{
    let dim = Ix3(xs.len(), V::len(), U::len());
    let mut result = Vec::::with_capacity(dim.size());
    for snd in xs {
        for thr in snd.as_init_slice() {
            result.extend_from_slice(thr.as_init_slice());
        }
    }
    unsafe {
        ArrayBase::from_shape_vec_unchecked(dim, result)
    }
}

/// Create a three-dimensional array with elements from `xs`.
pub fn rcarr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> RcArray
{
    arr3(xs).into_shared()
}
<commit_msg>Implement Array::from for vectors of nested arrays<commit_after>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::slice;
use std::mem::{size_of, forget};

use imp_prelude::*;

/// Create a zero-dimensional array with the element `x`.
pub fn arr0(x: A) -> Array0
{
    unsafe { ArrayBase::from_shape_vec_unchecked((), vec![x]) }
}

/// Create a one-dimensional array with elements from `xs`.
pub fn arr1(xs: &[A]) -> Array1 {
    ArrayBase::from_vec(xs.to_vec())
}

/// Create a one-dimensional array with elements from `xs`.
pub fn rcarr1(xs: &[A]) -> RcArray {
    arr1(xs).into_shared()
}

/// Create a zero-dimensional array view borrowing `x`.
pub fn aview0(x: &A) -> ArrayView0 {
    unsafe { ArrayView::new_(x, Ix0(), Ix0()) }
}

/// Create a one-dimensional array view with elements borrowing `xs`.
///
/// ```
/// use ndarray::aview1;
///
/// let data = [1.0; 1024];
///
/// // Create a 2D array view from borrowed data
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
///
/// assert!(
///     a2d.scalar_sum() == 1024.0
/// );
/// ```
pub fn aview1(xs: &[A]) -> ArrayView1 {
    ArrayView::from(xs)
}

/// Create a two-dimensional array view with elements borrowing `xs`.
pub fn aview2<A, V: FixedInitializer<Elem=A>>(xs: &[V]) -> ArrayView2 {
    let cols = V::len();
    let rows = xs.len();
    let data = unsafe {
        slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows)
    };
    let dim = Ix2(rows, cols);
    unsafe {
        let strides = dim.default_strides();
        ArrayView::new_(data.as_ptr(), dim, strides)
    }
}

/// Create a one-dimensional read-write array view with elements borrowing `xs`.
///
/// ```
/// #[macro_use(s)]
/// extern crate ndarray;
///
/// use ndarray::aview_mut1;
///
/// // Create an array view over some data, then slice it and modify it.
/// fn main() {
///     let mut data = [0; 1024];
///     {
///         let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
///         a.slice_mut(s![.., ..;3]).fill(5);
///     }
///     assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
/// }
/// ```
pub fn aview_mut1(xs: &mut [A]) -> ArrayViewMut1 {
    ArrayViewMut::from(xs)
}

/// Fixed-size array used for array initialization
pub unsafe trait FixedInitializer {
    type Elem;
    fn as_init_slice(&self) -> &[Self::Elem];
    fn len() -> usize;
}

macro_rules! impl_arr_init {
    (__impl $n: expr) => (
        unsafe impl<T> FixedInitializer for [T;  $n] {
            type Elem = T;
            fn as_init_slice(&self) -> &[T] { self }
            fn len() -> usize { $n }
        }
    );
    () => ();
    ($n: expr, $($m:expr,)*) => (
        impl_arr_init!(__impl $n);
        impl_arr_init!($($m,)*);
    )

}

impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);

/// Create a two-dimensional array with elements from `xs`.
///
/// ```
/// use ndarray::arr2;
///
/// let a = arr2(&[[1, 2, 3],
///                [4, 5, 6]]);
/// assert!(
///     a.shape() == [2, 3]
/// );
/// ```
pub fn arr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> Array2
    where V: Clone,
{
    Array2::from(xs.to_vec())
}

impl From<Vec> for Array1 {
    fn from(xs: Vec) -> Self {
        Array1::from_vec(xs)
    }
}

impl From<Vec<V>> for Array2
    where V: FixedInitializer<Elem = A>
{
    fn from(mut xs: Vec<V>) -> Self {
        let (m, n) = (xs.len(), V::len());
        let dim = Ix2(m, n);
        let ptr = xs.as_mut_ptr();
        let len = xs.len();
        let cap = xs.capacity();
        forget(xs);
        unsafe {
            let v = if size_of::() == 0 {
                Vec::from_raw_parts(ptr as *mut A, len * V::len(), cap)
            } else {
                Vec::from_raw_parts(ptr as *mut A, len * V::len(), cap * V::len())
            };
            ArrayBase::from_shape_vec_unchecked(dim, v)
        }
    }
}

impl From<Vec<V>> for Array3
    where V: FixedInitializer<Elem=U>,
          U: FixedInitializer<Elem=A>
{
    fn from(mut xs: Vec<V>) -> Self {
        let dim = Ix3(xs.len(), V::len(), U::len());
        let ptr = xs.as_mut_ptr();
        let len = xs.len();
        let cap = xs.capacity();
        forget(xs);
        unsafe {
            let v = if size_of::() == 0 {
                Vec::from_raw_parts(ptr as *mut A, len * V::len(), cap)
            } else {
                let len = len * V::len() * U::len();
                let cap = cap * V::len() * U::len();
                Vec::from_raw_parts(ptr as *mut A, len, cap)
            };
            ArrayBase::from_shape_vec_unchecked(dim, v)
        }
    }
}

/// Create a two-dimensional array with elements from `xs`.
///
pub fn rcarr2<A: Clone, V: Clone + FixedInitializer<Elem = A>>(xs: &[V]) -> RcArray {
    arr2(xs).into_shared()
}

/// Create a three-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
/// ```
/// use ndarray::arr3;
///
/// let a = arr3(&[[[1, 2],
///                 [3, 4]],
///                [[5, 6],
///                 [7, 8]],
///                [[9, 0],
///                 [1, 2]]]);
/// assert!(
///     a.shape() == [3, 2, 2]
/// );
/// ```
pub fn arr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> Array3
    where V: Clone,
          U: Clone,
{
    Array3::from(xs.to_vec())
}

/// Create a three-dimensional array with elements from `xs`.
pub fn rcarr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> RcArray
    where V: Clone, U: Clone,
{
    arr3(xs).into_shared()
}
<|endoftext|>


<commit_before>//! Byte container optionally encoded as UTF-8.

use std::{str, string, fmt};
use std::str::MaybeOwned;
use std::default::Default;
use std::path::BytesContainer;

#[deriving(Clone)]
pub enum MaybeUTF8 {
    UTF8(String),
    Bytes(Vec<u8>),
}

impl MaybeUTF8 {
    pub fn new() -> MaybeUTF8 {
        MaybeUTF8::UTF8(String::new())
    }

    pub fn from_str(s: String) -> MaybeUTF8 {
        MaybeUTF8::UTF8(s)
    }

    pub fn from_bytes(v: Vec<u8>) -> MaybeUTF8 {
        MaybeUTF8::Bytes(v)
    }

    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.as_bytes(),
            MaybeUTF8::Bytes(ref v) => v.as_slice(),
        }
    }

    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        match *self {
            MaybeUTF8::UTF8(ref s) => Some(s.as_slice()),
            MaybeUTF8::Bytes(ref v) => str::from_utf8(v.as_slice()),
        }
    }

    pub fn map_as_maybe_owned<'a>(&'a self,
                                  as_maybe_owned: |&'a [u8]| -> MaybeOwned<'a>) -> MaybeOwned<'a> {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.as_slice().into_maybe_owned(),
            MaybeUTF8::Bytes(ref v) => as_maybe_owned(v.as_slice()),
        }
    }

    pub fn as_maybe_owned<'a>(&'a self) -> MaybeOwned<'a> {
        self.map_as_maybe_owned(String::from_utf8_lossy)
    }

    pub fn into_str(self) -> Result<String, MaybeUTF8> {
        match self {
            MaybeUTF8::UTF8(s) => Ok(s),
            MaybeUTF8::Bytes(v) => match String::from_utf8(v) {
                Ok(s) => Ok(s),
                Err(v) => Err(MaybeUTF8::Bytes(v)),
            },
        }
    }

    pub fn map_into_str(self, into_str: |Vec<u8>| -> String) -> String {
        match self {
            MaybeUTF8::UTF8(s) => s,
            MaybeUTF8::Bytes(v) => into_str(v),
        }
    }

    pub fn into_str_lossy(self) -> String {
        self.map_into_str(|v| match String::from_utf8_lossy(v.as_slice()) {
            // `v` is definitely UTF-8, so do not make a copy!
            str::Slice(_) => unsafe {string::raw::from_utf8(v)},
            str::Owned(s) => s,
        })
    }

    pub fn into_bytes(self) -> Vec<u8> {
        match self {
            MaybeUTF8::UTF8(s) => s.into_bytes(),
            MaybeUTF8::Bytes(v) => v,
        }
    }

    pub fn len(&self) -> uint {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.len(),
            MaybeUTF8::Bytes(ref v) => v.len(),
        }
    }

    pub fn clear(&mut self) {
        match *self {
            MaybeUTF8::UTF8(ref mut s) => s.clear(),
            MaybeUTF8::Bytes(ref mut v) => v.clear(),
        }
    }
}

impl PartialEq for MaybeUTF8 {
    fn eq(&self, other: &MaybeUTF8) -> bool {
        self.as_bytes().eq(other.as_bytes())
    }
}

impl Eq for MaybeUTF8 {
}

impl PartialOrd for MaybeUTF8 {
    fn partial_cmp(&self, other: &MaybeUTF8) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}

impl Ord for MaybeUTF8 {
    fn cmp(&self, other: &MaybeUTF8) -> Ordering {
        self.as_bytes().cmp(other.as_bytes())
    }
}

impl BytesContainer for MaybeUTF8 {
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        self.as_bytes()
    }

    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
        self.as_str()
    }

    fn is_str(_: Option<&MaybeUTF8>) -> bool {
        false
    }
}

impl<T:BytesContainer> Equiv<T> for MaybeUTF8 {
    fn equiv(&self, other: &T) -> bool {
        self.as_bytes() == other.container_as_bytes()
    }
}

// a workaround for multiple `FromIterator` implementations with differing type params
trait MaybeUTF8FromIterator {
    fn maybe_utf8_from_iter<I:Iterator<Self>>(iterator: I) -> MaybeUTF8;
}

impl MaybeUTF8FromIterator for char {
    fn maybe_utf8_from_iter<I:Iterator<char>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8::from_str(FromIterator::from_iter(iterator))
    }
}

impl MaybeUTF8FromIterator for u8 {
    fn maybe_utf8_from_iter<I:Iterator<u8>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8::from_bytes(FromIterator::from_iter(iterator))
    }
}

impl<T:MaybeUTF8FromIterator> FromIterator<T> for MaybeUTF8 {
    fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8FromIterator::maybe_utf8_from_iter(iterator)
    }
}

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

impl fmt::Show for MaybeUTF8 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(self.as_bytes())
    }
}

<commit_msg>language changes: MaybeOwned is deprecated.<commit_after>//! Byte container optionally encoded as UTF-8.

use std::{str, borrow, fmt};
use std::str::CowString;
use std::default::Default;
use std::path::BytesContainer;

#[deriving(Clone)]
pub enum MaybeUTF8 {
    UTF8(String),
    Bytes(Vec<u8>),
}

impl MaybeUTF8 {
    pub fn new() -> MaybeUTF8 {
        MaybeUTF8::UTF8(String::new())
    }

    pub fn from_str(s: String) -> MaybeUTF8 {
        MaybeUTF8::UTF8(s)
    }

    pub fn from_bytes(v: Vec<u8>) -> MaybeUTF8 {
        MaybeUTF8::Bytes(v)
    }

    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.as_bytes(),
            MaybeUTF8::Bytes(ref v) => v.as_slice(),
        }
    }

    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
        match *self {
            MaybeUTF8::UTF8(ref s) => Some(s.as_slice()),
            MaybeUTF8::Bytes(ref v) => str::from_utf8(v.as_slice()),
        }
    }

    pub fn map_as_cow<'a>(&'a self,
                                  as_cow: |&'a [u8]| -> CowString<'a>) -> CowString<'a> {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.as_slice().into_cow(),
            MaybeUTF8::Bytes(ref v) => as_cow(v.as_slice()),
        }
    }

    pub fn as_cow<'a>(&'a self) -> CowString<'a> {
        self.map_as_cow(String::from_utf8_lossy)
    }

    pub fn into_str(self) -> Result<String, MaybeUTF8> {
        match self {
            MaybeUTF8::UTF8(s) => Ok(s),
            MaybeUTF8::Bytes(v) => match String::from_utf8(v) {
                Ok(s) => Ok(s),
                Err(v) => Err(MaybeUTF8::Bytes(v)),
            },
        }
    }

    pub fn map_into_str(self, into_str: |Vec<u8>| -> String) -> String {
        match self {
            MaybeUTF8::UTF8(s) => s,
            MaybeUTF8::Bytes(v) => into_str(v),
        }
    }

    pub fn into_str_lossy(self) -> String {
        self.map_into_str(|v| match String::from_utf8_lossy(v.as_slice()) {
            // `v` is definitely UTF-8, so do not make a copy!
            borrow::Borrowed(_) => unsafe {String::from_utf8_unchecked(v)},
            borrow::Owned(s) => s,
        })
    }

    pub fn into_bytes(self) -> Vec<u8> {
        match self {
            MaybeUTF8::UTF8(s) => s.into_bytes(),
            MaybeUTF8::Bytes(v) => v,
        }
    }

    pub fn len(&self) -> uint {
        match *self {
            MaybeUTF8::UTF8(ref s) => s.len(),
            MaybeUTF8::Bytes(ref v) => v.len(),
        }
    }

    pub fn clear(&mut self) {
        match *self {
            MaybeUTF8::UTF8(ref mut s) => s.clear(),
            MaybeUTF8::Bytes(ref mut v) => v.clear(),
        }
    }
}

impl PartialEq for MaybeUTF8 {
    fn eq(&self, other: &MaybeUTF8) -> bool {
        self.as_bytes().eq(other.as_bytes())
    }
}

impl Eq for MaybeUTF8 {
}

impl PartialOrd for MaybeUTF8 {
    fn partial_cmp(&self, other: &MaybeUTF8) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}

impl Ord for MaybeUTF8 {
    fn cmp(&self, other: &MaybeUTF8) -> Ordering {
        self.as_bytes().cmp(other.as_bytes())
    }
}

impl BytesContainer for MaybeUTF8 {
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        self.as_bytes()
    }

    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
        self.as_str()
    }

    fn is_str(_: Option<&MaybeUTF8>) -> bool {
        false
    }
}

impl<T:BytesContainer> Equiv<T> for MaybeUTF8 {
    fn equiv(&self, other: &T) -> bool {
        self.as_bytes() == other.container_as_bytes()
    }
}

// a workaround for multiple `FromIterator` implementations with differing type params
trait MaybeUTF8FromIterator {
    fn maybe_utf8_from_iter<I:Iterator<Self>>(iterator: I) -> MaybeUTF8;
}

impl MaybeUTF8FromIterator for char {
    fn maybe_utf8_from_iter<I:Iterator<char>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8::from_str(FromIterator::from_iter(iterator))
    }
}

impl MaybeUTF8FromIterator for u8 {
    fn maybe_utf8_from_iter<I:Iterator<u8>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8::from_bytes(FromIterator::from_iter(iterator))
    }
}

impl<T:MaybeUTF8FromIterator> FromIterator<T> for MaybeUTF8 {
    fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeUTF8 {
        MaybeUTF8FromIterator::maybe_utf8_from_iter(iterator)
    }
}

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

impl fmt::Show for MaybeUTF8 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(self.as_bytes())
    }
}

<|endoftext|>


<commit_before>//! implements the board representation

use std::vec;
use std::collections::VecMap;

use super::super::color::{Color, White, Black};
use super::super::piece::{self, Piece, King};
use super::super::square::Square;

use super::bitboard::BitBoard;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Board {
    data: VecMap<BitBoard>,
    white_data: BitBoard,
    black_data: BitBoard,
    empty_data: BitBoard,
}

impl Board {
    pub fn new() -> Board {
        let mut ans = VecMap::new();
        for x in piece::ALL.iter() {
            ans.insert(*x as usize, BitBoard::new());
        }
        Board {
            data: ans,
            white_data: BitBoard::new(),
            black_data: BitBoard::new(),
            empty_data: BitBoard::new_full(),
        }
    }

    fn piece_data(&self, p: Piece) -> &BitBoard {
        self.data.get(&(p as usize)).unwrap()
    }
    fn piece_data_mut(&mut self, p: Piece) -> &mut BitBoard {
        self.data.get_mut(&(p as usize)).unwrap()
    }

    fn color_data(&self, c: Color) -> &BitBoard {
        match c {
            White => &self.white_data,
            Black => &self.black_data,
        }
    }
    fn color_data_mut(&mut self, c: Color) -> &mut BitBoard {
        match c {
            White => &mut self.white_data,
            Black => &mut self.black_data,
        }
    }

    pub fn at(&self, s: Square) -> Option<Piece> {
        for x in piece::ALL.iter() {
            if self.is_piece_at(*x, s) {
                return Some(*x);
            }
        }
        None
    }
    pub fn is_piece_at(&self, p: Piece, s: Square) -> bool { self.piece_data(p).at(s) }
    pub fn is_empty_at(&self, s: Square) -> bool { self.empty_data.at(s) }
    pub fn is_color_at(&self, s: Square, c: Color) -> bool { self.color_data(c).at(s) }

    pub fn set_at(&mut self, s: Square, p: Piece) {
        debug_assert!(self.is_empty_at(s), "set_at(), s = {}", s);
        self.piece_data_mut(p).set_at(s);
        self.color_data_mut(p.color()).set_at(s);
        self.empty_data.remove_at(s);
    }
    pub fn remove_at(&mut self, s: Square, p: Piece) {
        debug_assert!(self.is_piece_at(p, s), "remove_at(), s = {}", s);
        self.piece_data_mut(p).remove_at(s);
        self.color_data_mut(p.color()).remove_at(s);
        self.empty_data.set_at(s);
    }

    pub fn king_square(&self, c: Color) -> Square {
        let curr_king = Piece::new(c, King);
        self.piece_data(curr_king).iter().next().unwrap()
    }

    fn piece_vec(&self) -> Vec<(Piece, Square)> {
        let mut ans: Vec<(Piece, Square)> = Vec::new();
        for p in piece::ALL.iter() {
            ans.extend(self.piece_data(*p).iter().map( |s: Square| (*p, s)  ) );
        }
        ans
    }
    pub fn iter(&self) -> Iter { Iter(self.piece_vec().into_iter()) }
}

pub struct Iter(vec::IntoIter<(Piece, Square)>);
impl Iterator for Iter {
    type Item = (Piece, Square);
    fn next(&mut self) -> Option<(Piece, Square)> { self.0.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
impl DoubleEndedIterator for Iter {
    fn next_back(&mut self) -> Option<(Piece, Square)> { self.0.next_back() }
}
impl ExactSizeIterator for Iter {}
<commit_msg>Add more logging for set_at() and remove_at()<commit_after>//! implements the board representation

use std::vec;
use std::collections::VecMap;

use super::super::color::{Color, White, Black};
use super::super::piece::{self, Piece, King};
use super::super::square::Square;

use super::bitboard::BitBoard;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Board {
    data: VecMap<BitBoard>,
    white_data: BitBoard,
    black_data: BitBoard,
    empty_data: BitBoard,
}

impl Board {
    pub fn new() -> Board {
        let mut ans = VecMap::new();
        for x in piece::ALL.iter() {
            ans.insert(*x as usize, BitBoard::new());
        }
        Board {
            data: ans,
            white_data: BitBoard::new(),
            black_data: BitBoard::new(),
            empty_data: BitBoard::new_full(),
        }
    }

    fn piece_data(&self, p: Piece) -> &BitBoard {
        self.data.get(&(p as usize)).unwrap()
    }
    fn piece_data_mut(&mut self, p: Piece) -> &mut BitBoard {
        self.data.get_mut(&(p as usize)).unwrap()
    }

    fn color_data(&self, c: Color) -> &BitBoard {
        match c {
            White => &self.white_data,
            Black => &self.black_data,
        }
    }
    fn color_data_mut(&mut self, c: Color) -> &mut BitBoard {
        match c {
            White => &mut self.white_data,
            Black => &mut self.black_data,
        }
    }

    pub fn at(&self, s: Square) -> Option<Piece> {
        for x in piece::ALL.iter() {
            if self.is_piece_at(*x, s) {
                return Some(*x);
            }
        }
        None
    }
    pub fn is_piece_at(&self, p: Piece, s: Square) -> bool { self.piece_data(p).at(s) }
    pub fn is_empty_at(&self, s: Square) -> bool { self.empty_data.at(s) }
    pub fn is_color_at(&self, s: Square, c: Color) -> bool { self.color_data(c).at(s) }

    pub fn set_at(&mut self, s: Square, p: Piece) {
        debug_assert!(self.is_empty_at(s), "set_at(), s = {:?}, p = {:?}", s, p);
        self.piece_data_mut(p).set_at(s);
        self.color_data_mut(p.color()).set_at(s);
        self.empty_data.remove_at(s);
    }
    pub fn remove_at(&mut self, s: Square, p: Piece) {
        debug_assert!(self.is_piece_at(p, s), "remove_at(), s = {:?}, p = {:?}", s, p);
        self.piece_data_mut(p).remove_at(s);
        self.color_data_mut(p.color()).remove_at(s);
        self.empty_data.set_at(s);
    }

    pub fn king_square(&self, c: Color) -> Square {
        let curr_king = Piece::new(c, King);
        self.piece_data(curr_king).iter().next().unwrap()
    }

    fn piece_vec(&self) -> Vec<(Piece, Square)> {
        let mut ans: Vec<(Piece, Square)> = Vec::new();
        for p in piece::ALL.iter() {
            ans.extend(self.piece_data(*p).iter().map( |s: Square| (*p, s)  ) );
        }
        ans
    }
    pub fn iter(&self) -> Iter { Iter(self.piece_vec().into_iter()) }
}

pub struct Iter(vec::IntoIter<(Piece, Square)>);
impl Iterator for Iter {
    type Item = (Piece, Square);
    fn next(&mut self) -> Option<(Piece, Square)> { self.0.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
impl DoubleEndedIterator for Iter {
    fn next_back(&mut self) -> Option<(Piece, Square)> { self.0.next_back() }
}
impl ExactSizeIterator for Iter {}
<|endoftext|>


<commit_before>extern crate libc;

use array::Array;
use defines::AfError;
use defines::ColorMap;
use self::libc::{c_int, c_uint, c_double};

type MutWndHandle = *mut self::libc::c_ulonglong;
type WndHandle    = self::libc::c_ulonglong;
type AfArray   = self::libc::c_longlong;
type CellPtr      = *const self::libc::c_void;

#[allow(dead_code)]
extern {
    fn af_create_window(out: MutWndHandle, w: c_int, h: c_int, title: *const u8) -> c_int;
    fn af_set_position(wnd: WndHandle, x: c_uint, y: c_uint) -> c_int;
    fn af_set_title(wnd: WndHandle, title: *const u8) -> c_int;
    fn af_draw_image(wnd: WndHandle, arr: AfArray, props: CellPtr) -> c_int;
    fn af_draw_plot(wnd: WndHandle, x: AfArray, y: AfArray, props: CellPtr) -> c_int;
    fn af_grid(wnd: WndHandle, rows: c_int, cols: c_int) -> c_int;
    fn af_show(wnd: WndHandle) -> c_int;
    fn af_is_window_closed(out: *mut c_int, wnd: WndHandle) -> c_int;
    fn af_destroy_window(wnd: WndHandle) -> c_int;

    fn af_draw_hist(wnd: WndHandle, x: AfArray,
                    minval: c_double, maxval: c_double, props: CellPtr) -> c_int;
}

#[repr(C)]
pub struct Cell {
    pub row: i32,
    pub col: i32,
    pub title: String,
    pub cmap: ColorMap,
}

#[derive(Clone)]
pub struct Window {
    handle: u64,
    row: i32,
    col: i32,
    cmap: ColorMap,
}

impl From<u64> for Window {
    fn from(t: u64) -> Window {
        Window {handle: t, row: -1, col: -1, cmap: ColorMap::DEFAULT}
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            let err_val = af_destroy_window(self.handle);
            match err_val {
                0 => (),
                _ => panic!("Window object destruction failed with error code: {}", err_val),
            }
        }
    }
}

impl Window {
    #[allow(unused_mut)]
    pub fn new(width: i32, height: i32, title: String) -> Result<Window, AfError> {
        unsafe {
            let mut temp: u64 = 0;
            let err_val = af_create_window(&mut temp as MutWndHandle,
                                           width as c_int, height as c_int,
                                           title.clone().as_bytes().as_ptr() as *const u8);
            match err_val {
                0 => Ok(Window::from(temp)),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn set_position(&self, x: u32, y: u32) -> Result<(), AfError> {
        unsafe {
            let err_val = af_set_position(self.handle as WndHandle, x as c_uint, y as c_uint);
            match err_val {
                0 => Ok(()),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn set_title(&self, title: String) -> Result<(), AfError> {
        unsafe {
            let err_val = af_set_title(self.handle as WndHandle,
                                       title.clone().as_bytes().as_ptr() as *const u8);
            match err_val {
                0 => Ok(()),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn set_colormap(&mut self, cmap: ColorMap) {
        self.cmap = cmap;
    }

    pub fn is_closed(&self) -> Result<bool, AfError> {
        unsafe {
            let mut temp: i32 = 1;
            let err_val = af_is_window_closed(&mut temp as *mut c_int, self.handle as WndHandle);
            match err_val {
                0 => Ok(temp > 0),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn grid(&self, rows: i32, cols: i32) -> Result<(), AfError> {
        unsafe {
            let err_val = af_grid(self.handle as WndHandle, rows as c_int, cols as c_int);
            match err_val {
                0 => Ok(()),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn show(&mut self) -> Result<(), AfError> {
        unsafe {
            let err_val = af_show(self.handle as WndHandle);
            if err_val != 0 {
                return Err(AfError::from(err_val));
            }
            self.row = -1;
            self.col = -1;
            Ok(())
        }
    }

    pub fn set_view(&mut self, r: i32, c: i32) {
        self.row = r;
        self.col = c;
    }

    pub fn draw_image(&self, input: &Array, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_image(self.handle as WndHandle, input.get() as AfArray,
                                        cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }

    pub fn draw_plot(&self, x: &Array, y: &Array, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_plot(self.handle as WndHandle,
                                       x.get() as AfArray,
                                       y.get() as AfArray,
                                       cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }

    pub fn draw_hist(&self, hst: &Array, minval: f64, maxval: f64, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_hist(self.handle as WndHandle, hst.get() as AfArray,
                                       minval as c_double, maxval as c_double,
                                       cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }
}
<commit_msg>use CString and case using to_bytes_with_nul to be C compatible<commit_after>extern crate libc;

use array::Array;
use defines::AfError;
use defines::ColorMap;
use self::libc::{c_int, c_uint, c_double, c_char};
use std::ffi::CString;

type MutWndHandle = *mut self::libc::c_ulonglong;
type WndHandle    = self::libc::c_ulonglong;
type AfArray      = self::libc::c_longlong;
type CellPtr      = *const self::libc::c_void;

#[allow(dead_code)]
extern {
    fn af_create_window(out: MutWndHandle, w: c_int, h: c_int, title: *const c_char) -> c_int;
    fn af_set_position(wnd: WndHandle, x: c_uint, y: c_uint) -> c_int;
    fn af_set_title(wnd: WndHandle, title: *const c_char) -> c_int;
    fn af_draw_image(wnd: WndHandle, arr: AfArray, props: CellPtr) -> c_int;
    fn af_draw_plot(wnd: WndHandle, x: AfArray, y: AfArray, props: CellPtr) -> c_int;
    fn af_grid(wnd: WndHandle, rows: c_int, cols: c_int) -> c_int;
    fn af_show(wnd: WndHandle) -> c_int;
    fn af_is_window_closed(out: *mut c_int, wnd: WndHandle) -> c_int;
    fn af_destroy_window(wnd: WndHandle) -> c_int;
    fn af_draw_hist(wnd: WndHandle, x: AfArray,
                    minval: c_double, maxval: c_double, props: CellPtr) -> c_int;
}

#[repr(C)]
pub struct Cell {
    pub row: i32,
    pub col: i32,
    pub title: String,
    pub cmap: ColorMap,
}

#[derive(Clone)]
pub struct Window {
    handle: u64,
    row: i32,
    col: i32,
    cmap: ColorMap,
}

impl From<u64> for Window {
    fn from(t: u64) -> Window {
        Window {handle: t, row: -1, col: -1, cmap: ColorMap::DEFAULT}
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            let err_val = af_destroy_window(self.handle);
            match err_val {
                0 => (),
                _ => panic!("Window object destruction failed with error code: {}", err_val),
            }
        }
    }
}

impl Window {
    #[allow(unused_mut)]
    pub fn new(width: i32, height: i32, title: String) -> Result<Window, AfError> {
        unsafe {
            let mut temp: u64 = 0;
            let cstr_ret = CString::new(title.as_bytes());
            match cstr_ret {
                Ok(cstr) => {
                    let err_val = af_create_window(&mut temp as MutWndHandle
                                                   , width as c_int, height as c_int
                                                   , cstr.to_bytes_with_nul().as_ptr() as *const c_char);
                    match err_val {
                        0 => Ok(Window::from(temp)),
                        _ => Err(AfError::from(err_val)),
                    }
                },
                Err(_)   => Err(AfError::ERR_INTERNAL),
            }
        }
    }

    pub fn set_position(&self, x: u32, y: u32) -> Result<(), AfError> {
        unsafe {
            let err_val = af_set_position(self.handle as WndHandle, x as c_uint, y as c_uint);
            match err_val {
                0 => Ok(()),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn set_title(&self, title: String) -> Result<(), AfError> {
        unsafe {
            let cstr_ret = CString::new(title.as_bytes());
            match cstr_ret {
                Ok(cstr) => {
                    let err_val = af_set_title(self.handle as WndHandle
                                               , cstr.to_bytes_with_nul().as_ptr() as *const c_char);
                    match err_val {
                        0 => Ok(()),
                        _ => Err(AfError::from(err_val)),
                    }
                },
                Err(_)   => Err(AfError::ERR_INTERNAL),
            }
        }
    }

    pub fn set_colormap(&mut self, cmap: ColorMap) {
        self.cmap = cmap;
    }

    pub fn is_closed(&self) -> Result<bool, AfError> {
        unsafe {
            let mut temp: i32 = 1;
            let err_val = af_is_window_closed(&mut temp as *mut c_int, self.handle as WndHandle);
            match err_val {
                0 => Ok(temp > 0),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn grid(&self, rows: i32, cols: i32) -> Result<(), AfError> {
        unsafe {
            let err_val = af_grid(self.handle as WndHandle, rows as c_int, cols as c_int);
            match err_val {
                0 => Ok(()),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn show(&mut self) -> Result<(), AfError> {
        unsafe {
            let err_val = af_show(self.handle as WndHandle);
            if err_val != 0 {
                return Err(AfError::from(err_val));
            }
            self.row = -1;
            self.col = -1;
            Ok(())
        }
    }

    pub fn set_view(&mut self, r: i32, c: i32) {
        self.row = r;
        self.col = c;
    }

    pub fn draw_image(&self, input: &Array, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_image(self.handle as WndHandle, input.get() as AfArray,
                                        cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }

    pub fn draw_plot(&self, x: &Array, y: &Array, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_plot(self.handle as WndHandle,
                                       x.get() as AfArray,
                                       y.get() as AfArray,
                                       cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }

    pub fn draw_hist(&self, hst: &Array, minval: f64, maxval: f64, title: Option<String>) {
        let tstr = match title {
            Some(s) => s,
            None => format!("Cell({},{}))", self.col, self.row)
        };
        let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap};
        unsafe {
            let err_val = af_draw_hist(self.handle as WndHandle, hst.get() as AfArray,
                                       minval as c_double, maxval as c_double,
                                       cprops as *const Cell as CellPtr);
            match err_val {
                0 => (),
                _ => panic!("Rendering the image failed: {}", err_val),
            }
        }
    }
}
<|endoftext|>


<commit_before>/// Exercise 10.10: Write a program that calls sleep(60) in an infinite loop.
/// Every five times through the loop (every 5 minutes), fetch the current
/// time of day and print the tm_sec field. Run the program overnight and
/// explain the results. How would a program such as the cron daemon,
/// which runs every minute on the minute, handle this situation?

extern crate libc;
#[macro_use(cstr)]
extern crate apue;

use libc::{sleep, time, localtime, c_char};
use std::mem::uninitialized;
use std::ffi::CStr;
use apue::my_libc::strftime;

fn main() {
    unsafe {
        let mut buf: [c_char; 256] = uninitialized();
        let mut t = uninitialized();
        loop {
            sleep(60);
            time(&mut t);
            let tm = localtime(&t);
            strftime(buf.as_mut_ptr(), 256, cstr!("%a %b %e %H:%M:%S %Z %Y"), tm);
            println!("{:?}, tm_sec={}",
                     CStr::from_ptr(buf.as_ptr()),
                     (*tm).tm_sec);
        }
    }
}
<commit_msg>Add findings of Exercise 10.10<commit_after>/// Exercise 10.10: Write a program that calls sleep(60) in an infinite loop.
/// Every five times through the loop (every 5 minutes), fetch the current
/// time of day and print the tm_sec field. Run the program overnight and
/// explain the results. How would a program such as the cron daemon,
/// which runs every minute on the minute, handle this situation?
///
/// Answer: no effect, even after about 8 hours on a 4 core server.
/// The effect is probably quite improbable for multicore systems as the chance are high
/// that one core is idle.
///
/// To be really sure the process could
///
/// - sleep for 59 seconds and run sleep for the remaining time
/// - if woken up too late (check with time()) sleep for less then 60 seconds

extern crate libc;
#[macro_use(cstr)]
extern crate apue;

use libc::{sleep, time, localtime, c_char};
use std::mem::uninitialized;
use std::ffi::CStr;
use apue::my_libc::strftime;

fn main() {
    unsafe {
        let mut buf: [c_char; 256] = uninitialized();
        let mut t = uninitialized();
        loop {
            sleep(60);
            time(&mut t);
            let tm = localtime(&t);
            strftime(buf.as_mut_ptr(), 256, cstr!("%a %b %e %H:%M:%S %Z %Y"), tm);
            println!("{:?}, tm_sec={}",
                     CStr::from_ptr(buf.as_ptr()),
                     (*tm).tm_sec);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! Defines the structures needed for saving/restoring a RateLimiter.

use super::*;
use snapshot::Persist;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;

/// State for saving a TokenBucket.
#[derive(Versionize)]
pub struct TokenBucketState {
    size: u64,
    one_time_burst: u64,
    refill_time: u64,
    budget: u64,
    elapsed_ns: u64,
}

impl Persist<'_> for TokenBucket {
    type State = TokenBucketState;
    type ConstructorArgs = ();
    type Error = io::Error;

    fn save(&self) -> Self::State {
        TokenBucketState {
            size: self.size,
            one_time_burst: self.one_time_burst,
            refill_time: self.refill_time,
            budget: self.budget,
            elapsed_ns: self.last_update.elapsed().as_nanos() as u64,
        }
    }

    fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
        let now = Instant::now();
        let last_update = now
            .checked_sub(Duration::from_nanos(state.elapsed_ns))
            .unwrap_or(now);

        let mut token_bucket =
            TokenBucket::new(state.size, state.one_time_burst, state.refill_time)
                .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput))?;

        token_bucket.budget = state.budget;
        token_bucket.last_update = last_update;

        Ok(token_bucket)
    }
}

/// State for saving a RateLimiter.
#[derive(Versionize)]
pub struct RateLimiterState {
    ops: Option<TokenBucketState>,
    bandwidth: Option<TokenBucketState>,
}

impl Persist<'_> for RateLimiter {
    type State = RateLimiterState;
    type ConstructorArgs = ();
    type Error = io::Error;

    fn save(&self) -> Self::State {
        RateLimiterState {
            ops: self.ops.as_ref().map(|ops| ops.save()),
            bandwidth: self.bandwidth.as_ref().map(|bw| bw.save()),
        }
    }

    fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
        let rate_limiter = RateLimiter {
            // Safe to unwrap because TokenBucket::restore doesn't return errors.
            ops: state
                .ops
                .as_ref()
                .map(|ops| TokenBucket::restore((), ops).unwrap()),
            bandwidth: state
                .bandwidth
                .as_ref()
                .map(|bw| TokenBucket::restore((), bw).unwrap()),
            timer_fd: TimerFd::new_custom(ClockId::Monotonic, true, true)?,
            timer_active: false,
        };

        Ok(rate_limiter)
    }
}

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

    #[test]
    fn test_token_bucket_persistence() {
        let mut tb = TokenBucket::new(1000, 2000, 3000).unwrap();

        // Check that TokenBucket restores correctly if untouched.
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Check that TokenBucket restores correctly after partially consuming tokens.
        tb.reduce(100);
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Check that TokenBucket restores correctly after replenishing tokens.
        tb.replenish(100);
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Test serialization.
        let mut mem = vec![0; 4096];
        let version_map = VersionMap::new();
        tb.save()
            .serialize(&mut mem.as_mut_slice(), &version_map, 1)
            .unwrap();

        let restored_tb = TokenBucket::restore(
            (),
            &TokenBucketState::deserialize(&mut mem.as_slice(), &version_map, 1).unwrap(),
        )
        .unwrap();
        assert!(tb.partial_eq(&restored_tb));
    }

    #[test]
    fn test_rate_limiter_persistence() {
        let refill_time = 100_000;
        let mut rate_limiter = RateLimiter::new(100, 0, refill_time, 10, 0, refill_time).unwrap();

        // Check that RateLimiter restores correctly if untouched.
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
        assert_eq!(
            restored_rate_limiter.timer_fd.get_state(),
            TimerState::Disarmed
        );

        // Check that RateLimiter restores correctly after partially consuming tokens.
        rate_limiter.consume(10, TokenType::Bytes);
        rate_limiter.consume(10, TokenType::Ops);
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
        assert_eq!(
            restored_rate_limiter.timer_fd.get_state(),
            TimerState::Disarmed
        );

        // Check that RateLimiter restores correctly after totally consuming tokens.
        rate_limiter.consume(1000, TokenType::Bytes);
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));

        // Test serialization.
        let mut mem = vec![0; 4096];
        let version_map = VersionMap::new();
        rate_limiter
            .save()
            .serialize(&mut mem.as_mut_slice(), &version_map, 1)
            .unwrap();
        let restored_rate_limiter = RateLimiter::restore(
            (),
            &RateLimiterState::deserialize(&mut mem.as_slice(), &version_map, 1).unwrap(),
        )
        .unwrap();

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
    }
}
<commit_msg>Improved error handling for rate limiter<commit_after>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! Defines the structures needed for saving/restoring a RateLimiter.

use super::*;
use snapshot::Persist;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;

/// State for saving a TokenBucket.
#[derive(Versionize)]
pub struct TokenBucketState {
    size: u64,
    one_time_burst: u64,
    refill_time: u64,
    budget: u64,
    elapsed_ns: u64,
}

impl Persist<'_> for TokenBucket {
    type State = TokenBucketState;
    type ConstructorArgs = ();
    type Error = io::Error;

    fn save(&self) -> Self::State {
        TokenBucketState {
            size: self.size,
            one_time_burst: self.one_time_burst,
            refill_time: self.refill_time,
            budget: self.budget,
            elapsed_ns: self.last_update.elapsed().as_nanos() as u64,
        }
    }

    fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
        let now = Instant::now();
        let last_update = now
            .checked_sub(Duration::from_nanos(state.elapsed_ns))
            .unwrap_or(now);

        let mut token_bucket =
            TokenBucket::new(state.size, state.one_time_burst, state.refill_time)
                .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput))?;

        token_bucket.budget = state.budget;
        token_bucket.last_update = last_update;

        Ok(token_bucket)
    }
}

/// State for saving a RateLimiter.
#[derive(Versionize)]
pub struct RateLimiterState {
    ops: Option<TokenBucketState>,
    bandwidth: Option<TokenBucketState>,
}

impl Persist<'_> for RateLimiter {
    type State = RateLimiterState;
    type ConstructorArgs = ();
    type Error = io::Error;

    fn save(&self) -> Self::State {
        RateLimiterState {
            ops: self.ops.as_ref().map(|ops| ops.save()),
            bandwidth: self.bandwidth.as_ref().map(|bw| bw.save()),
        }
    }

    fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
        let rate_limiter = RateLimiter {
            ops: if let Some(ops) = state.ops.as_ref() {
                Some(TokenBucket::restore((), ops)?)
            } else {
                None
            },
            bandwidth: if let Some(bw) = state.bandwidth.as_ref() {
                Some(TokenBucket::restore((), bw)?)
            } else {
                None
            },
            timer_fd: TimerFd::new_custom(ClockId::Monotonic, true, true)?,
            timer_active: false,
        };

        Ok(rate_limiter)
    }
}

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

    #[test]
    fn test_token_bucket_persistence() {
        let mut tb = TokenBucket::new(1000, 2000, 3000).unwrap();

        // Check that TokenBucket restores correctly if untouched.
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Check that TokenBucket restores correctly after partially consuming tokens.
        tb.reduce(100);
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Check that TokenBucket restores correctly after replenishing tokens.
        tb.replenish(100);
        let restored_tb = TokenBucket::restore((), &tb.save()).unwrap();
        assert!(tb.partial_eq(&restored_tb));

        // Test serialization.
        let mut mem = vec![0; 4096];
        let version_map = VersionMap::new();
        tb.save()
            .serialize(&mut mem.as_mut_slice(), &version_map, 1)
            .unwrap();

        let restored_tb = TokenBucket::restore(
            (),
            &TokenBucketState::deserialize(&mut mem.as_slice(), &version_map, 1).unwrap(),
        )
        .unwrap();
        assert!(tb.partial_eq(&restored_tb));
    }

    #[test]
    fn test_rate_limiter_persistence() {
        let refill_time = 100_000;
        let mut rate_limiter = RateLimiter::new(100, 0, refill_time, 10, 0, refill_time).unwrap();

        // Check that RateLimiter restores correctly if untouched.
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
        assert_eq!(
            restored_rate_limiter.timer_fd.get_state(),
            TimerState::Disarmed
        );

        // Check that RateLimiter restores correctly after partially consuming tokens.
        rate_limiter.consume(10, TokenType::Bytes);
        rate_limiter.consume(10, TokenType::Ops);
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
        assert_eq!(
            restored_rate_limiter.timer_fd.get_state(),
            TimerState::Disarmed
        );

        // Check that RateLimiter restores correctly after totally consuming tokens.
        rate_limiter.consume(1000, TokenType::Bytes);
        let restored_rate_limiter =
            RateLimiter::restore((), &rate_limiter.save()).expect("Unable to restore rate limiter");

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));

        // Test serialization.
        let mut mem = vec![0; 4096];
        let version_map = VersionMap::new();
        rate_limiter
            .save()
            .serialize(&mut mem.as_mut_slice(), &version_map, 1)
            .unwrap();
        let restored_rate_limiter = RateLimiter::restore(
            (),
            &RateLimiterState::deserialize(&mut mem.as_slice(), &version_map, 1).unwrap(),
        )
        .unwrap();

        assert!(rate_limiter
            .ops()
            .unwrap()
            .partial_eq(&restored_rate_limiter.ops().unwrap()));
        assert!(rate_limiter
            .bandwidth()
            .unwrap()
            .partial_eq(&restored_rate_limiter.bandwidth().unwrap()));
    }
}
<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    gpu::arc::{ArcTexture, ArcTextureView},
    Color, Rect, WgpuContext,
};
use crate::{Context, GameError, GameResult};
use std::path::Path;
use std::{io::Read, num::NonZeroU32};

// maintaing a massive enum of all possible texture formats?
// screw that.
/// Describes the pixel format of an image.
pub type ImageFormat = wgpu::TextureFormat;

/// Describes the format of an encoded image.
pub type ImageEncodingFormat = ::image::ImageFormat;

/// Handle to an image stored in GPU memory.
#[derive(Debug, Clone)]
pub struct Image {
    pub(crate) texture: ArcTexture,
    pub(crate) view: ArcTextureView,
    pub(crate) format: ImageFormat,
    pub(crate) width: u32,
    pub(crate) height: u32,
    pub(crate) samples: u32,
}

impl Image {
    /// Creates a new image specifically for use with a [Canvas].
    pub fn new_canvas_image(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
    ) -> Self {
        Self::new(
            &gfx.wgpu,
            format,
            width,
            height,
            samples,
            wgpu::TextureUsages::RENDER_ATTACHMENT
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        )
    }

    /// Creates a new image initialized with given pixel data.
    pub fn from_pixels(
        gfx: &GraphicsContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        Self::from_pixels_wgpu(&gfx.wgpu, pixels, format, width, height)
    }

    pub(crate) fn from_pixels_wgpu(
        wgpu: &WgpuContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        let image = Self::new(
            wgpu,
            format,
            width,
            height,
            1,
            wgpu::TextureUsages::COPY_DST
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        );

        wgpu.queue.write_texture(
            image.texture.as_image_copy(),
            pixels,
            wgpu::ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(
                    NonZeroU32::new(format.describe().block_size as u32 * width).unwrap(),
                ),
                rows_per_image: None,
            },
            wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
        );

        image
    }

    /// A little helper function that creates a new `Image` that is just a solid square of the given size and color. Mainly useful for debugging.
    pub fn from_solid(gfx: &GraphicsContext, size: u32, color: Color) -> Self {
        let pixels = (0..(size * size))
            .flat_map(|_| {
                let (r, g, b, a) = color.to_rgba();
                [r, g, b, a]
            })
            .collect::<Vec<_>>();
        Self::from_pixels(
            gfx,
            &pixels,
            wgpu::TextureFormat::Rgba8UnormSrgb,
            size,
            size,
        )
    }

    /// Creates a new image initialized with pixel data loaded from an encoded image `Read` (e.g. PNG or JPEG).
    #[allow(unused_results)]
    pub fn from_path(ctx: &Context, path: impl AsRef<Path>, srgb: bool) -> GameResult<Self> {
        let mut encoded = Vec::new();
        ctx.fs.open(path)?.read_to_end(&mut encoded)?;
        let decoded = image::load_from_memory(&encoded[..])
            .map_err(|_| GameError::ResourceLoadError(String::from("failed to load image")))?;
        let rgba8 = decoded.to_rgba8();
        let (width, height) = (rgba8.width(), rgba8.height());

        Ok(Self::from_pixels(
            &ctx.gfx,
            rgba8.as_ref(),
            if srgb {
                ImageFormat::Rgba8UnormSrgb
            } else {
                ImageFormat::Rgba8Unorm
            },
            width,
            height,
        ))
    }

    fn new(
        wgpu: &WgpuContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
        usage: wgpu::TextureUsages,
    ) -> Self {
        assert!(width > 0);
        assert!(height > 0);
        assert!(samples > 0);

        let texture = ArcTexture::new(wgpu.device.create_texture(&wgpu::TextureDescriptor {
            label: None,
            size: wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: samples,
            dimension: wgpu::TextureDimension::D2,
            format,
            usage,
        }));

        let view =
            ArcTextureView::new(texture.as_ref().create_view(&wgpu::TextureViewDescriptor {
                label: None,
                format: Some(format),
                dimension: Some(wgpu::TextureViewDimension::D2),
                aspect: wgpu::TextureAspect::All,
                base_mip_level: 0,
                mip_level_count: Some(NonZeroU32::new(1).unwrap()),
                base_array_layer: 0,
                array_layer_count: Some(NonZeroU32::new(1).unwrap()),
            }));

        Image {
            texture,
            view,
            format,
            width,
            height,
            samples,
        }
    }

    /// Returns the underlying [`wgpu::Texture`] and [`wgpu::TextureView`] for this [`Image`].
    #[inline]
    pub fn wgpu(&self) -> (&wgpu::Texture, &wgpu::TextureView) {
        (&self.texture, &self.view)
    }

    /// Reads the pixels of this `ImageView` and returns as `Vec<u8>`.
    /// The format matches the GPU image format.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn to_pixels(&self, gfx: &GraphicsContext) -> GameResult<Vec<u8>> {
        let block_size = self.format.describe().block_size as u64;

        let buffer = gfx.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: block_size * self.width as u64 * self.height as u64,
            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
            mapped_at_creation: false,
        });

        let cmd = {
            let mut encoder = gfx
                .wgpu
                .device
                .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
            encoder.copy_texture_to_buffer(
                self.texture.as_image_copy(),
                wgpu::ImageCopyBuffer {
                    buffer: &buffer,
                    layout: wgpu::ImageDataLayout {
                        offset: 0,
                        bytes_per_row: Some(
                            NonZeroU32::new(block_size as u32 * self.width).unwrap(),
                        ),
                        rows_per_image: None,
                    },
                },
                wgpu::Extent3d {
                    width: self.width,
                    height: self.height,
                    depth_or_array_layers: 1,
                },
            );
            encoder.finish()
        };

        gfx.wgpu.queue.submit([cmd]);

        // wait...
        let fut = buffer.slice(..).map_async(wgpu::MapMode::Read);
        gfx.wgpu.device.poll(wgpu::Maintain::Wait);
        pollster::block_on(fut)?;

        let out = buffer.slice(..).get_mapped_range().to_vec();
        Ok(out)
    }

    /// Encodes the `ImageView` to the given file format and return the encoded bytes.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn encode(
        &self,
        ctx: &Context,
        format: ImageEncodingFormat,
        path: impl AsRef<std::path::Path>,
    ) -> GameResult {
        let color = match self.format {
            ImageFormat::Rgba8Unorm | ImageFormat::Rgba8UnormSrgb => ::image::ColorType::Rgba8,
            ImageFormat::Bgra8Unorm | ImageFormat::Bgra8UnormSrgb => ::image::ColorType::Bgra8,
            ImageFormat::R8Unorm => ::image::ColorType::L8,
            ImageFormat::R16Unorm => ::image::ColorType::L16,
            format => {
                return Err(GameError::RenderError(format!(
                    "cannot ImageView::encode for the {:#?} GPU image format",
                    format
                )))
            }
        };

        let pixels = self.to_pixels(&ctx.gfx)?;
        let f = ctx.fs.create(path)?;
        let writer = &mut std::io::BufWriter::new(f);

        match format {
            ImageEncodingFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            ImageEncodingFormat::Bmp => ::image::bmp::BmpEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            _ => Err(GameError::RenderError(String::from(
                "cannot ImageView::encode for formats other than Png and Bmp",
            ))),
        }
    }

    /// Returns the image format of this image.
    #[inline]
    pub fn format(&self) -> ImageFormat {
        self.format
    }

    /// Returns the number of MSAA samples this image has.
    #[inline]
    pub fn samples(&self) -> u32 {
        self.samples
    }

    /// Returns the width (in pixels) of the image.
    #[inline]
    pub fn width(&self) -> u32 {
        self.width
    }

    /// Returns the height (in pixels) of the image.
    #[inline]
    pub fn height(&self) -> u32 {
        self.height
    }

    /// Helper function that calculates a sub-rectangle of this image in UV coordinates, given pixel coordinates.
    pub fn uv_rect(&self, x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x as f32 / self.width as f32,
            y: y as f32 / self.height as f32,
            w: w as f32 / self.width as f32,
            h: h as f32 / self.height as f32,
        }
    }
}

/// An image which is sized relative to the screen.
/// This is primarily for canvas images.
#[derive(Debug, Clone)]
pub struct ScreenImage {
    image: Image,
    format: wgpu::TextureFormat,
    size: (f32, f32),
    samples: u32,
}

impl ScreenImage {
    /// Creates a new [ScreenImage] with the given parameters.
    ///
    /// `width` and `height` specify the fraction of the framebuffer width and height that the [Image] will have.
    /// For example, `width = 1.0` and `height = 1.0` means the image will be the same size as the framebuffer.
    ///
    /// If `format` is `None` then the format will be inferred from the surface format.
    pub fn new(
        gfx: &GraphicsContext,
        format: impl Into<Option<ImageFormat>>,
        width: f32,
        height: f32,
        samples: u32,
    ) -> Self {
        assert!(width > 0.);
        assert!(height > 0.);
        assert!(samples > 0);

        let format = format
            .into()
            .unwrap_or(gfx.surface_format);

        ScreenImage {
            image: Self::create(gfx, format, (width, height), samples),
            format,
            size: (width, height),
            samples,
        }
    }

    /// Returns the inner [Image], also recreating it if the framebuffer has been resized.
    pub fn image(&mut self, gfx: &GraphicsContext) -> Image {
        if Self::size(gfx, self.size) != (self.image.width(), self.image.height()) {
            self.image = Self::create(gfx, self.format, self.size, self.samples);
        }
        self.image.clone()
    }

    fn size(gfx: &GraphicsContext, (width, height): (f32, f32)) -> (u32, u32) {
        let size = gfx.window.inner_size();
        let width = (size.width as f32 * width) as u32;
        let height = (size.height as f32 * height) as u32;
        (width, height)
    }

    fn create(
        gfx: &GraphicsContext,
        format: wgpu::TextureFormat,
        size: (f32, f32),
        samples: u32,
    ) -> Image {
        let (width, height) = Self::size(gfx, size);
        Image::new_canvas_image(gfx, format, width, height, samples)
    }
}
<commit_msg>add explicit error for to_pixels on MSAA images. wgpu should already throw an error when this happens, but this should be more user friendly<commit_after>//!

use super::{
    context::GraphicsContext,
    gpu::arc::{ArcTexture, ArcTextureView},
    Color, Rect, WgpuContext,
};
use crate::{Context, GameError, GameResult};
use std::path::Path;
use std::{io::Read, num::NonZeroU32};

// maintaing a massive enum of all possible texture formats?
// screw that.
/// Describes the pixel format of an image.
pub type ImageFormat = wgpu::TextureFormat;

/// Describes the format of an encoded image.
pub type ImageEncodingFormat = ::image::ImageFormat;

/// Handle to an image stored in GPU memory.
#[derive(Debug, Clone)]
pub struct Image {
    pub(crate) texture: ArcTexture,
    pub(crate) view: ArcTextureView,
    pub(crate) format: ImageFormat,
    pub(crate) width: u32,
    pub(crate) height: u32,
    pub(crate) samples: u32,
}

impl Image {
    /// Creates a new image specifically for use with a [Canvas].
    pub fn new_canvas_image(
        gfx: &GraphicsContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
    ) -> Self {
        Self::new(
            &gfx.wgpu,
            format,
            width,
            height,
            samples,
            wgpu::TextureUsages::RENDER_ATTACHMENT
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        )
    }

    /// Creates a new image initialized with given pixel data.
    pub fn from_pixels(
        gfx: &GraphicsContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        Self::from_pixels_wgpu(&gfx.wgpu, pixels, format, width, height)
    }

    pub(crate) fn from_pixels_wgpu(
        wgpu: &WgpuContext,
        pixels: &[u8],
        format: ImageFormat,
        width: u32,
        height: u32,
    ) -> Self {
        let image = Self::new(
            wgpu,
            format,
            width,
            height,
            1,
            wgpu::TextureUsages::COPY_DST
                | wgpu::TextureUsages::TEXTURE_BINDING
                | wgpu::TextureUsages::COPY_SRC,
        );

        wgpu.queue.write_texture(
            image.texture.as_image_copy(),
            pixels,
            wgpu::ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(
                    NonZeroU32::new(format.describe().block_size as u32 * width).unwrap(),
                ),
                rows_per_image: None,
            },
            wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
        );

        image
    }

    /// A little helper function that creates a new `Image` that is just a solid square of the given size and color. Mainly useful for debugging.
    pub fn from_solid(gfx: &GraphicsContext, size: u32, color: Color) -> Self {
        let pixels = (0..(size * size))
            .flat_map(|_| {
                let (r, g, b, a) = color.to_rgba();
                [r, g, b, a]
            })
            .collect::<Vec<_>>();
        Self::from_pixels(
            gfx,
            &pixels,
            wgpu::TextureFormat::Rgba8UnormSrgb,
            size,
            size,
        )
    }

    /// Creates a new image initialized with pixel data loaded from an encoded image `Read` (e.g. PNG or JPEG).
    #[allow(unused_results)]
    pub fn from_path(ctx: &Context, path: impl AsRef<Path>, srgb: bool) -> GameResult<Self> {
        let mut encoded = Vec::new();
        ctx.fs.open(path)?.read_to_end(&mut encoded)?;
        let decoded = image::load_from_memory(&encoded[..])
            .map_err(|_| GameError::ResourceLoadError(String::from("failed to load image")))?;
        let rgba8 = decoded.to_rgba8();
        let (width, height) = (rgba8.width(), rgba8.height());

        Ok(Self::from_pixels(
            &ctx.gfx,
            rgba8.as_ref(),
            if srgb {
                ImageFormat::Rgba8UnormSrgb
            } else {
                ImageFormat::Rgba8Unorm
            },
            width,
            height,
        ))
    }

    fn new(
        wgpu: &WgpuContext,
        format: ImageFormat,
        width: u32,
        height: u32,
        samples: u32,
        usage: wgpu::TextureUsages,
    ) -> Self {
        assert!(width > 0);
        assert!(height > 0);
        assert!(samples > 0);

        let texture = ArcTexture::new(wgpu.device.create_texture(&wgpu::TextureDescriptor {
            label: None,
            size: wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: samples,
            dimension: wgpu::TextureDimension::D2,
            format,
            usage,
        }));

        let view =
            ArcTextureView::new(texture.as_ref().create_view(&wgpu::TextureViewDescriptor {
                label: None,
                format: Some(format),
                dimension: Some(wgpu::TextureViewDimension::D2),
                aspect: wgpu::TextureAspect::All,
                base_mip_level: 0,
                mip_level_count: Some(NonZeroU32::new(1).unwrap()),
                base_array_layer: 0,
                array_layer_count: Some(NonZeroU32::new(1).unwrap()),
            }));

        Image {
            texture,
            view,
            format,
            width,
            height,
            samples,
        }
    }

    /// Returns the underlying [`wgpu::Texture`] and [`wgpu::TextureView`] for this [`Image`].
    #[inline]
    pub fn wgpu(&self) -> (&wgpu::Texture, &wgpu::TextureView) {
        (&self.texture, &self.view)
    }

    /// Reads the pixels of this `ImageView` and returns as `Vec<u8>`.
    /// The format matches the GPU image format.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn to_pixels(&self, gfx: &GraphicsContext) -> GameResult<Vec<u8>> {
        if self.samples > 1 {
            return Err(GameError::RenderError(String::from(
                "cannot read the pixels of a multisampled image; resolve this image with a canvas",
            )));
        }

        let block_size = self.format.describe().block_size as u64;

        let buffer = gfx.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: block_size * self.width as u64 * self.height as u64,
            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
            mapped_at_creation: false,
        });

        let cmd = {
            let mut encoder = gfx
                .wgpu
                .device
                .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
            encoder.copy_texture_to_buffer(
                self.texture.as_image_copy(),
                wgpu::ImageCopyBuffer {
                    buffer: &buffer,
                    layout: wgpu::ImageDataLayout {
                        offset: 0,
                        bytes_per_row: Some(
                            NonZeroU32::new(block_size as u32 * self.width).unwrap(),
                        ),
                        rows_per_image: None,
                    },
                },
                wgpu::Extent3d {
                    width: self.width,
                    height: self.height,
                    depth_or_array_layers: 1,
                },
            );
            encoder.finish()
        };

        gfx.wgpu.queue.submit([cmd]);

        // wait...
        let fut = buffer.slice(..).map_async(wgpu::MapMode::Read);
        gfx.wgpu.device.poll(wgpu::Maintain::Wait);
        pollster::block_on(fut)?;

        let out = buffer.slice(..).get_mapped_range().to_vec();
        Ok(out)
    }

    /// Encodes the `ImageView` to the given file format and return the encoded bytes.
    ///
    /// **This is a very expensive operation - call sparingly.**
    pub fn encode(
        &self,
        ctx: &Context,
        format: ImageEncodingFormat,
        path: impl AsRef<std::path::Path>,
    ) -> GameResult {
        let color = match self.format {
            ImageFormat::Rgba8Unorm | ImageFormat::Rgba8UnormSrgb => ::image::ColorType::Rgba8,
            ImageFormat::Bgra8Unorm | ImageFormat::Bgra8UnormSrgb => ::image::ColorType::Bgra8,
            ImageFormat::R8Unorm => ::image::ColorType::L8,
            ImageFormat::R16Unorm => ::image::ColorType::L16,
            format => {
                return Err(GameError::RenderError(format!(
                    "cannot ImageView::encode for the {:#?} GPU image format",
                    format
                )))
            }
        };

        let pixels = self.to_pixels(&ctx.gfx)?;
        let f = ctx.fs.create(path)?;
        let writer = &mut std::io::BufWriter::new(f);

        match format {
            ImageEncodingFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            ImageEncodingFormat::Bmp => ::image::bmp::BmpEncoder::new(writer)
                .encode(&pixels, self.width, self.height, color)
                .map_err(Into::into),
            _ => Err(GameError::RenderError(String::from(
                "cannot ImageView::encode for formats other than Png and Bmp",
            ))),
        }
    }

    /// Returns the image format of this image.
    #[inline]
    pub fn format(&self) -> ImageFormat {
        self.format
    }

    /// Returns the number of MSAA samples this image has.
    #[inline]
    pub fn samples(&self) -> u32 {
        self.samples
    }

    /// Returns the width (in pixels) of the image.
    #[inline]
    pub fn width(&self) -> u32 {
        self.width
    }

    /// Returns the height (in pixels) of the image.
    #[inline]
    pub fn height(&self) -> u32 {
        self.height
    }

    /// Helper function that calculates a sub-rectangle of this image in UV coordinates, given pixel coordinates.
    pub fn uv_rect(&self, x: u32, y: u32, w: u32, h: u32) -> Rect {
        Rect {
            x: x as f32 / self.width as f32,
            y: y as f32 / self.height as f32,
            w: w as f32 / self.width as f32,
            h: h as f32 / self.height as f32,
        }
    }
}

/// An image which is sized relative to the screen.
/// This is primarily for canvas images.
#[derive(Debug, Clone)]
pub struct ScreenImage {
    image: Image,
    format: wgpu::TextureFormat,
    size: (f32, f32),
    samples: u32,
}

impl ScreenImage {
    /// Creates a new [ScreenImage] with the given parameters.
    ///
    /// `width` and `height` specify the fraction of the framebuffer width and height that the [Image] will have.
    /// For example, `width = 1.0` and `height = 1.0` means the image will be the same size as the framebuffer.
    ///
    /// If `format` is `None` then the format will be inferred from the surface format.
    pub fn new(
        gfx: &GraphicsContext,
        format: impl Into<Option<ImageFormat>>,
        width: f32,
        height: f32,
        samples: u32,
    ) -> Self {
        assert!(width > 0.);
        assert!(height > 0.);
        assert!(samples > 0);

        let format = format.into().unwrap_or(gfx.surface_format);

        ScreenImage {
            image: Self::create(gfx, format, (width, height), samples),
            format,
            size: (width, height),
            samples,
        }
    }

    /// Returns the inner [Image], also recreating it if the framebuffer has been resized.
    pub fn image(&mut self, gfx: &GraphicsContext) -> Image {
        if Self::size(gfx, self.size) != (self.image.width(), self.image.height()) {
            self.image = Self::create(gfx, self.format, self.size, self.samples);
        }
        self.image.clone()
    }

    fn size(gfx: &GraphicsContext, (width, height): (f32, f32)) -> (u32, u32) {
        let size = gfx.window.inner_size();
        let width = (size.width as f32 * width) as u32;
        let height = (size.height as f32 * height) as u32;
        (width, height)
    }

    fn create(
        gfx: &GraphicsContext,
        format: wgpu::TextureFormat,
        size: (f32, f32),
        samples: u32,
    ) -> Image {
        let (width, height) = Self::size(gfx, size);
        Image::new_canvas_image(gfx, format, width, height, samples)
    }
}
<|endoftext|>