<commit_before>use core::cell::Cell;
use hil::i2c::{self, I2CClient, Error};
use common::{List, ListLink, ListNode};
use common::take_cell::TakeCell;

pub struct MuxI2C<'a> {
    i2c: &'a i2c::I2CController,
    devices: List<'a, I2CDevice<'a>>,
    enabled: Cell<usize>,
    inflight: TakeCell<&'a I2CDevice<'a>>
}

impl<'a> I2CClient for MuxI2C<'a> {
    fn command_complete(&self, buffer: &'static mut [u8], error: Error) {
        self.inflight.take().map(move |device| {
            device.command_complete(buffer, error);
        });
        self.do_next_op();
    }
}

impl<'a> MuxI2C<'a> {
    pub const fn new(i2c: &'a i2c::I2CController) -> MuxI2C<'a> {
        MuxI2C {
            i2c: i2c,
            devices: List::new(),
            enabled: Cell::new(0),
            inflight: TakeCell::empty()
        }
    }
    fn enable(&self) {
        let enabled = self.enabled.get();
        self.enabled.set(enabled);
        if enabled == 0 {
            self.i2c.enable();
        }
    }

    fn disable(&self) {
        let enabled = self.enabled.get();
        self.enabled.set(enabled - 1);
        if enabled == 1 {
            self.i2c.disable();
        }
    }

    fn do_next_op(&self) {
        if self.inflight.is_none() {
            let mnode = self.devices.iter().find(|node| {
                 node.operation.get() != Op::Idle
            });
            mnode.map(|node| {
                node.buffer.take().map(|buf| {
                    match node.operation.get() {
                        Op::Write(len) =>
                            self.i2c.write(node.addr, buf, len),
                        Op::Read(len) =>
                            self.i2c.read(node.addr, buf, len),
                        Op::WriteRead(wlen, rlen) =>
                            self.i2c.write_read(node.addr,
                                        buf, wlen, rlen),
                        Op::Idle => {} // Can't get here...
                    }
                });
                node.operation.set(Op::Idle);
                self.inflight.replace(node);
            });
        }
    }
}

#[derive(Copy, Clone,PartialEq)]
enum Op {
    Idle,
    Write(u8),
    Read(u8),
    WriteRead(u8, u8)
}

pub struct I2CDevice<'a> {
    mux: &'a MuxI2C<'a>,
    addr: u8,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>,
    operation: Cell<Op>,
    next: ListLink<'a, I2CDevice<'a>>,
    client: Cell<Option<&'a I2CClient>>
}

impl<'a> I2CDevice <'a> {
    pub const fn new(mux: &'a MuxI2C<'a>, addr: u8) -> I2CDevice<'a> {
        I2CDevice {
            mux: mux,
            addr: addr,
            enabled: Cell::new(false),
            buffer: TakeCell::empty(),
            operation: Cell::new(Op::Idle),
            next: ListLink::empty(),
            client: Cell::new(None)
        }
    }

    pub fn set_client(&'a self, client: &'a I2CClient) {
        self.mux.devices.push_head(self);
        self.client.set(Some(client));
    }
}

impl<'a> I2CClient for I2CDevice<'a> {
    fn command_complete(&self, buffer: &'static mut [u8], error: Error) {
        self.client.get().map(move |client| {
            client.command_complete(buffer, error);
        });
    }
}

impl<'a> ListNode<'a, I2CDevice<'a>> for I2CDevice<'a> {
    fn next(&'a self) -> &'a ListLink<'a, I2CDevice<'a>> {
        &self.next
    }
}

impl<'a> i2c::I2CDevice for I2CDevice<'a> {
    fn enable(&self) {
        if !self.enabled.get() {
            self.mux.enable();
        }
    }

    fn disable(&self) {
        if self.enabled.get() {
            self.mux.disable();
        }
    }

    fn write_read(&self,  data: &'static mut [u8],
                    write_len: u8, read_len: u8) {
        self.buffer.replace(data);
        self.operation.set(Op::WriteRead(write_len, read_len));
        self.mux.do_next_op();
    }

    fn write(&self, data: &'static mut [u8], len: u8) {
        self.buffer.replace(data);
        self.operation.set(Op::Write(len));
        self.mux.do_next_op();
    }

    fn read(&self, buffer: &'static mut [u8], len: u8) {
        self.buffer.replace(buffer);
        self.operation.set(Op::Read(len));
        self.mux.do_next_op();
    }
}

<commit_msg>Properly account for enable/disable in virtual I2C<commit_after>use core::cell::Cell;
use hil::i2c::{self, I2CClient, Error};
use common::{List, ListLink, ListNode};
use common::take_cell::TakeCell;

pub struct MuxI2C<'a> {
    i2c: &'a i2c::I2CController,
    devices: List<'a, I2CDevice<'a>>,
    enabled: Cell<usize>,
    inflight: TakeCell<&'a I2CDevice<'a>>
}

impl<'a> I2CClient for MuxI2C<'a> {
    fn command_complete(&self, buffer: &'static mut [u8], error: Error) {
        self.inflight.take().map(move |device| {
            device.command_complete(buffer, error);
        });
        self.do_next_op();
    }
}

impl<'a> MuxI2C<'a> {
    pub const fn new(i2c: &'a i2c::I2CController) -> MuxI2C<'a> {
        MuxI2C {
            i2c: i2c,
            devices: List::new(),
            enabled: Cell::new(0),
            inflight: TakeCell::empty()
        }
    }

    fn enable(&self) {
        let enabled = self.enabled.get();
        self.enabled.set(enabled + 1);
        if enabled == 0 {
            self.i2c.enable();
        }
    }

    fn disable(&self) {
        let enabled = self.enabled.get();
        self.enabled.set(enabled - 1);
        if enabled == 1 {
            self.i2c.disable();
        }
    }

    fn do_next_op(&self) {
        if self.inflight.is_none() {
            let mnode = self.devices.iter().find(|node| {
                 node.operation.get() != Op::Idle
            });
            mnode.map(|node| {
                node.buffer.take().map(|buf| {
                    match node.operation.get() {
                        Op::Write(len) =>
                            self.i2c.write(node.addr, buf, len),
                        Op::Read(len) =>
                            self.i2c.read(node.addr, buf, len),
                        Op::WriteRead(wlen, rlen) =>
                            self.i2c.write_read(node.addr,
                                        buf, wlen, rlen),
                        Op::Idle => {} // Can't get here...
                    }
                });
                node.operation.set(Op::Idle);
                self.inflight.replace(node);
            });
        }
    }
}

#[derive(Copy, Clone,PartialEq)]
enum Op {
    Idle,
    Write(u8),
    Read(u8),
    WriteRead(u8, u8)
}

pub struct I2CDevice<'a> {
    mux: &'a MuxI2C<'a>,
    addr: u8,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>,
    operation: Cell<Op>,
    next: ListLink<'a, I2CDevice<'a>>,
    client: Cell<Option<&'a I2CClient>>
}

impl<'a> I2CDevice <'a> {
    pub const fn new(mux: &'a MuxI2C<'a>, addr: u8) -> I2CDevice<'a> {
        I2CDevice {
            mux: mux,
            addr: addr,
            enabled: Cell::new(false),
            buffer: TakeCell::empty(),
            operation: Cell::new(Op::Idle),
            next: ListLink::empty(),
            client: Cell::new(None)
        }
    }

    pub fn set_client(&'a self, client: &'a I2CClient) {
        self.mux.devices.push_head(self);
        self.client.set(Some(client));
    }
}

impl<'a> I2CClient for I2CDevice<'a> {
    fn command_complete(&self, buffer: &'static mut [u8], error: Error) {
        self.client.get().map(move |client| {
            client.command_complete(buffer, error);
        });
    }
}

impl<'a> ListNode<'a, I2CDevice<'a>> for I2CDevice<'a> {
    fn next(&'a self) -> &'a ListLink<'a, I2CDevice<'a>> {
        &self.next
    }
}

impl<'a> i2c::I2CDevice for I2CDevice<'a> {
    fn enable(&self) {
        if !self.enabled.get() {
            self.enabled.set(true);
            self.mux.enable();
        }
    }

    fn disable(&self) {
        if self.enabled.get() {
            self.enabled.set(false);
            self.mux.disable();
        }
    }

    fn write_read(&self,  data: &'static mut [u8],
                    write_len: u8, read_len: u8) {
        self.buffer.replace(data);
        self.operation.set(Op::WriteRead(write_len, read_len));
        self.mux.do_next_op();
    }

    fn write(&self, data: &'static mut [u8], len: u8) {
        self.buffer.replace(data);
        self.operation.set(Op::Write(len));
        self.mux.do_next_op();
    }

    fn read(&self, buffer: &'static mut [u8], len: u8) {
        self.buffer.replace(buffer);
        self.operation.set(Op::Read(len));
        self.mux.do_next_op();
    }
}

<|endoftext|>


<commit_before>use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use tensorflow_sys as tf;

use crate::eager::Context;
use crate::{AnyTensor, DataType, Result, Status, Tensor, TensorType};

/// A handle to a tensor on a device.
///
/// Constructing a TensorHandle requires a reference to an execute context so that the
/// generated handle will not out live the context.
/// ```
/// # use tensorflow::Tensor;
/// use tensorflow::eager::{ContextOptions, Context, TensorHandle};
///
/// let opts = ContextOptions::new();
/// let ctx = Context::new(opts).unwrap();
///
/// let t = Tensor::from(&[3i32]);
/// let h = TensorHandle::new(&ctx, &t).unwrap();
/// let v: Tensor<i32> = h.resolve().unwrap();
/// assert_eq!(&v[..], &[3i32]);
/// ```
///
/// Since TensorHandle cannot be alive beyond the lifetime of the context, the following
/// code will not compile.
/// ```compile_fail
/// # use tensorflow::Tensor;
/// use tensorflow::eager::{ContextOptions, Context, TensorHandle};
///
/// let h = {
///     let opts = ContextOptions::new();
///     let ctx = Context::new(opts).unwrap();
///
///     let t = Tensor::from(&[3i32]);
///     let h = TensorHandle::new(&ctx, &t).unwrap();
///     h
/// };
/// ```
#[derive(Debug)]
pub struct TensorHandle<'a> {
    inner: *mut tf::TFE_TensorHandle,
    // TensorHandle should not live longer than a given context.
    ctx: PhantomData<&'a Context>,
}

impl<'a> Drop for TensorHandle<'a> {
    fn drop(&mut self) {
        unsafe {
            tf::TFE_DeleteTensorHandle(self.inner);
        }
    }
}

impl<'a> TensorHandle<'a> {
    /// Create a TensorHandle from the input Tensor
    pub fn new<T: TensorType>(_ctx: &'a Context, t: &Tensor<T>) -> Result<TensorHandle<'a>> {
        let status = Status::new();
        let inner = unsafe { tf::TFE_NewTensorHandle(t.inner()?, status.inner) };

        if inner.is_null() {
            Err(status)
        } else {
            Ok(TensorHandle {
                inner,
                ctx: PhantomData,
            })
        }
    }

    /// Return the DataType that corresponds to this type.
    pub fn data_type(&self) -> DataType {
        unsafe { DataType::from_c(tf::TFE_TensorHandleDataType(self.inner)) }
    }

    /// Return the number of dimensions.
    ///
    /// This function will block till the operation that produces the TensorHandle has completed.
    pub fn num_dims(&self) -> Result<usize> {
        let status = Status::new();
        let num_dims = unsafe { tf::TFE_TensorHandleNumDims(self.inner, status.inner) };
        if status.is_ok() {
            // num_dims >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(num_dims as usize)
        } else {
            Err(status)
        }
    }

    /// Return the number of elements
    pub fn num_elements(&self) -> Result<u64> {
        let status = Status::new();
        let num_elements = unsafe { tf::TFE_TensorHandleNumElements(self.inner, status.inner) };
        if status.is_ok() {
            // num_elements >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(num_elements as u64)
        } else {
            Err(status)
        }
    }

    /// Return the number of elements for a given dim_index.
    ///
    /// This function will block till the operation that produces the TensorHandle has completed.
    pub fn dim(&self, dim_index: i32) -> Result<u64> {
        let status = Status::new();
        let dim = unsafe { tf::TFE_TensorHandleDim(self.inner, dim_index, status.inner) };
        if status.is_ok() {
            // dim >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(dim as u64)
        } else {
            Err(status)
        }
    }

    /// Return the device of the operation that produced the current TensorHandle.
    ///
    /// If the TensorHandle was produced by a copy, returns the destination device of the copy.
    /// Note that the returned device name is not always the device holding the tensor handle's memory.
    /// If you want the latter, use backing_device_name.
    ///
    /// This function will block till the operation that produces the current TensorHandle has completed.
    pub fn device_name(&self) -> Result<String> {
        let status = Status::new();
        unsafe {
            let device_name = tf::TFE_TensorHandleDeviceName(self.inner, status.inner);
            if status.is_ok() {
                Ok(CStr::from_ptr(device_name).to_str()?.to_string())
            } else {
                Err(status)
            }
        }
    }

    /// Returns the name of the device in whose memory underlying the current TensorHandle resides.
    ///
    /// This function will block till the operation that produces the current TensorHandle has completed.
    pub fn backing_device_name(&self) -> Result<String> {
        let status = Status::new();
        unsafe {
            let device_name = tf::TFE_TensorHandleBackingDeviceName(self.inner, status.inner);
            if status.is_ok() {
                Ok(CStr::from_ptr(device_name).to_str()?.to_string())
            } else {
                Err(status)
            }
        }
    }

    /// Return a new TensorHandle that shares the underlying tensor with the current TensorHandle.
    pub fn copy_sharing_tensor(&self) -> Result<Self> {
        let status = Status::new();
        let inner = unsafe { tf::TFE_TensorHandleCopySharingTensor(self.inner, status.inner) };
        if status.is_ok() {
            Ok(Self {
                inner,
                ctx: self.ctx,
            })
        } else {
            Err(status)
        }
    }

    /// This function will block till the operation that produces the current TensorHandle has completed.
    /// The memory returned might alias the internal memory used by TensorFlow.
    /// Hence, callers should not mutate this memory.
    pub fn resolve<T: TensorType>(&self) -> Result<Tensor<T>> {
        let mut status = Status::new();
        let tf_tensor = unsafe { tf::TFE_TensorHandleResolve(self.inner, status.inner) };
        if !status.is_ok() {
            return Err(status);
        }
        if self.data_type() != T::data_type() {
            let msg = format!(
                "The expected data type ({}) and underlying data type ({}) did not match.",
                T::data_type(),
                self.data_type()
            );

            status.set_lossy(crate::Code::InvalidArgument, &msg);
            return Err(status);
        }

        // Safely unwrap since data_type was checked beforehand.
        unsafe { Ok(Tensor::from_tf_tensor(tf_tensor).unwrap()) }
    }

    /// Create a new TensorHandle with the same contents as the current TensorHandle but placed
    /// in the memory of the device name 'device_name'.
    /// If source and destination are the same device, then this creates a new handle
    /// that shares the underlying buffer. Otherwise, it currently requires at least
    /// one of the source or destination devices to be CPU (i.e., for the source or
    /// destination tensor to be placed in host memory).
    /// If async execution is enabled, the copy may be enqueued and the call will
    /// return "non-ready" TensorHandle. Else, this function returns after the copy has
    /// been done.
    pub fn copy_to_device<'b>(
        &self,
        ctx: &'b Context,
        device_name: &str,
    ) -> Result<TensorHandle<'b>> {
        let status = Status::new();

        let device_name = CString::new(device_name)?;
        unsafe {
            let inner = tf::TFE_TensorHandleCopyToDevice(
                self.inner,
                ctx.inner,
                device_name.as_ptr(),
                status.inner,
            );

            if status.is_ok() {
                Ok(TensorHandle {
                    inner,
                    ctx: PhantomData,
                })
            } else {
                Err(status)
            }
        }
    }
}

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

    #[test]
    fn test_tensor_handle() {
        let opts = ContextOptions::new();
        let ctx = Context::new(opts).unwrap();

        let t = Tensor::new(&[2, 3])
            .with_values(&[0_i32, 1, 2, 3, 4, 5])
            .unwrap();
        let h = TensorHandle::new(&ctx, &t).unwrap();

        assert_eq!(h.data_type(), DataType::Int32);
        assert_eq!(h.num_elements().unwrap(), 6);
        assert_eq!(h.num_dims().unwrap(), 2);
        assert_eq!(h.dim(0).unwrap(), 2);
        assert_eq!(h.dim(1).unwrap(), 3);
    }

    #[test]
    fn test_copy_sharing_tensor() {
        let opts = ContextOptions::new();
        let ctx = Context::new(opts).unwrap();

        let t = Tensor::new(&[2, 3])
            .with_values(&[0_i32, 1, 2, 3, 4, 5])
            .unwrap();
        let h = TensorHandle::new(&ctx, &t).unwrap();
        let h_copy = h.copy_sharing_tensor().unwrap();
        let t2 = h_copy.resolve::<i32>().unwrap();

        // t and t2 may share the same memory, but it's difficuly to check
        // since the `resolve` does not guarantee that.
        assert_eq!(&t[..], &t2[..]);
    }

    /// Following tests are disabled by default because it requires a GPU and some setup.
    ///
    /// To run this test, you need to pass the `-- --ignored` arguumnet to cargo test.
    /// ```sh
    /// cargo test --features "eager tensorflow_gpu" -- --ignored
    /// ```
    #[cfg(feature = "tensorflow_gpu")]
    mod gpu {
        use super::*;
        use crate::eager::ContextOptions;

        #[test]
        #[ignore]
        fn test_copy_to_device() {
            let values = [0_i32, 1, 2, 3];
            let target_device = "/job:localhost/replica:0/task:0/device:GPU:0";

            let opts = ContextOptions::new();
            let ctx = Context::new(opts).unwrap();
            let devices = ctx.device_list().unwrap();
            assert!(
                devices.iter().any(|d| d.device_type == "GPU"),
                "Skip test_copy_to_device because no GPU device was found"
            );

            let t = Tensor::new(&[2, 2]).with_values(&values).unwrap();
            let h = TensorHandle::new(&ctx, &t).unwrap();
            let h_gpu = TensorHandle::copy_to_device(&h, &ctx, target_device).unwrap();
            assert_eq!(h_gpu.device_name().unwrap(), target_device);
            let t2 = h_gpu.resolve::<i32>().unwrap();

            assert_eq!(&t[..], &t2[..]);
        }

        #[test]
        #[ignore]
        fn test_copy_to_device_lifetime() {
            let values = [0_i32, 1, 2, 3];
            let target_device = "/job:localhost/replica:0/task:0/device:GPU:0";

            let opts = ContextOptions::new();
            let ctx = Context::new(opts).unwrap();
            let devices = ctx.device_list().unwrap();
            assert!(
                devices.iter().any(|d| d.device_type == "GPU"),
                "Skip test_copy_to_device because no GPU device was found"
            );

            let h_gpu = {
                // Create a temporal Context
                let opts = ContextOptions::new();
                let ctx2 = Context::new(opts).unwrap();
                let t = Tensor::new(&[2, 2]).with_values(&values).unwrap();

                // Create a TensorHandle managed by the context `ctx2`.
                let h = TensorHandle::new(&ctx2, &t).unwrap();

                // Copy to GPU. This creates a new handle managed by the context `ctx`.
                h.copy_to_device(&ctx, target_device).unwrap()
            };
            assert_eq!(h_gpu.device_name().unwrap(), target_device);
            let t2 = h_gpu.resolve::<i32>().unwrap();

            assert_eq!(&values[..], &t2[..]);
        }
    }
}
<commit_msg>Refactor gpu related ut in the eager module.<commit_after>use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use tensorflow_sys as tf;

use crate::eager::Context;
use crate::{AnyTensor, DataType, Result, Status, Tensor, TensorType};

/// A handle to a tensor on a device.
///
/// Constructing a TensorHandle requires a reference to an execute context so that the
/// generated handle will not out live the context.
/// ```
/// # use tensorflow::Tensor;
/// use tensorflow::eager::{ContextOptions, Context, TensorHandle};
///
/// let opts = ContextOptions::new();
/// let ctx = Context::new(opts).unwrap();
///
/// let t = Tensor::from(&[3i32]);
/// let h = TensorHandle::new(&ctx, &t).unwrap();
/// let v: Tensor<i32> = h.resolve().unwrap();
/// assert_eq!(&v[..], &[3i32]);
/// ```
///
/// Since TensorHandle cannot be alive beyond the lifetime of the context, the following
/// code will not compile.
/// ```compile_fail
/// # use tensorflow::Tensor;
/// use tensorflow::eager::{ContextOptions, Context, TensorHandle};
///
/// let h = {
///     let opts = ContextOptions::new();
///     let ctx = Context::new(opts).unwrap();
///
///     let t = Tensor::from(&[3i32]);
///     let h = TensorHandle::new(&ctx, &t).unwrap();
///     h
/// };
/// ```
#[derive(Debug)]
pub struct TensorHandle<'a> {
    inner: *mut tf::TFE_TensorHandle,
    // TensorHandle should not live longer than a given context.
    ctx: PhantomData<&'a Context>,
}

impl<'a> Drop for TensorHandle<'a> {
    fn drop(&mut self) {
        unsafe {
            tf::TFE_DeleteTensorHandle(self.inner);
        }
    }
}

impl<'a> TensorHandle<'a> {
    /// Create a TensorHandle from the input Tensor
    pub fn new<T: TensorType>(_ctx: &'a Context, t: &Tensor<T>) -> Result<TensorHandle<'a>> {
        let status = Status::new();
        let inner = unsafe { tf::TFE_NewTensorHandle(t.inner()?, status.inner) };

        if inner.is_null() {
            Err(status)
        } else {
            Ok(TensorHandle {
                inner,
                ctx: PhantomData,
            })
        }
    }

    /// Return the DataType that corresponds to this type.
    pub fn data_type(&self) -> DataType {
        unsafe { DataType::from_c(tf::TFE_TensorHandleDataType(self.inner)) }
    }

    /// Return the number of dimensions.
    ///
    /// This function will block till the operation that produces the TensorHandle has completed.
    pub fn num_dims(&self) -> Result<usize> {
        let status = Status::new();
        let num_dims = unsafe { tf::TFE_TensorHandleNumDims(self.inner, status.inner) };
        if status.is_ok() {
            // num_dims >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(num_dims as usize)
        } else {
            Err(status)
        }
    }

    /// Return the number of elements
    pub fn num_elements(&self) -> Result<u64> {
        let status = Status::new();
        let num_elements = unsafe { tf::TFE_TensorHandleNumElements(self.inner, status.inner) };
        if status.is_ok() {
            // num_elements >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(num_elements as u64)
        } else {
            Err(status)
        }
    }

    /// Return the number of elements for a given dim_index.
    ///
    /// This function will block till the operation that produces the TensorHandle has completed.
    pub fn dim(&self, dim_index: i32) -> Result<u64> {
        let status = Status::new();
        let dim = unsafe { tf::TFE_TensorHandleDim(self.inner, dim_index, status.inner) };
        if status.is_ok() {
            // dim >= 0 when the status is ok, so we can safely cast it to u64.
            Ok(dim as u64)
        } else {
            Err(status)
        }
    }

    /// Return the device of the operation that produced the current TensorHandle.
    ///
    /// If the TensorHandle was produced by a copy, returns the destination device of the copy.
    /// Note that the returned device name is not always the device holding the tensor handle's memory.
    /// If you want the latter, use backing_device_name.
    ///
    /// This function will block till the operation that produces the current TensorHandle has completed.
    pub fn device_name(&self) -> Result<String> {
        let status = Status::new();
        unsafe {
            let device_name = tf::TFE_TensorHandleDeviceName(self.inner, status.inner);
            if status.is_ok() {
                Ok(CStr::from_ptr(device_name).to_str()?.to_string())
            } else {
                Err(status)
            }
        }
    }

    /// Returns the name of the device in whose memory underlying the current TensorHandle resides.
    ///
    /// This function will block till the operation that produces the current TensorHandle has completed.
    pub fn backing_device_name(&self) -> Result<String> {
        let status = Status::new();
        unsafe {
            let device_name = tf::TFE_TensorHandleBackingDeviceName(self.inner, status.inner);
            if status.is_ok() {
                Ok(CStr::from_ptr(device_name).to_str()?.to_string())
            } else {
                Err(status)
            }
        }
    }

    /// Return a new TensorHandle that shares the underlying tensor with the current TensorHandle.
    pub fn copy_sharing_tensor(&self) -> Result<Self> {
        let status = Status::new();
        let inner = unsafe { tf::TFE_TensorHandleCopySharingTensor(self.inner, status.inner) };
        if status.is_ok() {
            Ok(Self {
                inner,
                ctx: self.ctx,
            })
        } else {
            Err(status)
        }
    }

    /// This function will block till the operation that produces the current TensorHandle has completed.
    /// The memory returned might alias the internal memory used by TensorFlow.
    /// Hence, callers should not mutate this memory.
    pub fn resolve<T: TensorType>(&self) -> Result<Tensor<T>> {
        let mut status = Status::new();
        let tf_tensor = unsafe { tf::TFE_TensorHandleResolve(self.inner, status.inner) };
        if !status.is_ok() {
            return Err(status);
        }
        if self.data_type() != T::data_type() {
            let msg = format!(
                "The expected data type ({}) and underlying data type ({}) did not match.",
                T::data_type(),
                self.data_type()
            );

            status.set_lossy(crate::Code::InvalidArgument, &msg);
            return Err(status);
        }

        // Safely unwrap since data_type was checked beforehand.
        unsafe { Ok(Tensor::from_tf_tensor(tf_tensor).unwrap()) }
    }

    /// Create a new TensorHandle with the same contents as the current TensorHandle but placed
    /// in the memory of the device name 'device_name'.
    /// If source and destination are the same device, then this creates a new handle
    /// that shares the underlying buffer. Otherwise, it currently requires at least
    /// one of the source or destination devices to be CPU (i.e., for the source or
    /// destination tensor to be placed in host memory).
    /// If async execution is enabled, the copy may be enqueued and the call will
    /// return "non-ready" TensorHandle. Else, this function returns after the copy has
    /// been done.
    pub fn copy_to_device<'b>(
        &self,
        ctx: &'b Context,
        device_name: &str,
    ) -> Result<TensorHandle<'b>> {
        let status = Status::new();

        let device_name = CString::new(device_name)?;
        unsafe {
            let inner = tf::TFE_TensorHandleCopyToDevice(
                self.inner,
                ctx.inner,
                device_name.as_ptr(),
                status.inner,
            );

            if status.is_ok() {
                Ok(TensorHandle {
                    inner,
                    ctx: PhantomData,
                })
            } else {
                Err(status)
            }
        }
    }
}

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

    #[test]
    fn test_tensor_handle() {
        let opts = ContextOptions::new();
        let ctx = Context::new(opts).unwrap();

        let t = Tensor::new(&[2, 3])
            .with_values(&[0_i32, 1, 2, 3, 4, 5])
            .unwrap();
        let h = TensorHandle::new(&ctx, &t).unwrap();

        assert_eq!(h.data_type(), DataType::Int32);
        assert_eq!(h.num_elements().unwrap(), 6);
        assert_eq!(h.num_dims().unwrap(), 2);
        assert_eq!(h.dim(0).unwrap(), 2);
        assert_eq!(h.dim(1).unwrap(), 3);
    }

    #[test]
    fn test_copy_sharing_tensor() {
        let opts = ContextOptions::new();
        let ctx = Context::new(opts).unwrap();

        let t = Tensor::new(&[2, 3])
            .with_values(&[0_i32, 1, 2, 3, 4, 5])
            .unwrap();
        let h = TensorHandle::new(&ctx, &t).unwrap();
        let h_copy = h.copy_sharing_tensor().unwrap();
        let t2 = h_copy.resolve::<i32>().unwrap();

        // t and t2 may share the same memory, but it's difficuly to check
        // since the `resolve` does not guarantee that.
        assert_eq!(&t[..], &t2[..]);
    }

    /// Following tests are disabled by default because it requires a GPU and some setup.
    ///
    /// To run this test, you need to pass the `-- --ignored` arguumnet to cargo test.
    /// ```sh
    /// cargo test --features "eager tensorflow_gpu" -- --ignored
    /// ```
    #[cfg(feature = "tensorflow_gpu")]
    mod gpu {
        use super::*;
        use crate::eager::ContextOptions;

        #[test]
        #[ignore]
        fn test_copy_to_device() {
            let values = [0_i32, 1, 2, 3];

            let opts = ContextOptions::new();
            let ctx = Context::new(opts).unwrap();
            let devices = ctx.device_list().unwrap();
            let gpu_device = devices
                .iter()
                .find(|d| d.device_type == "GPU")
                .expect("No GPU device was found.");
            let target_device = &gpu_device.name;

            let t = Tensor::new(&[2, 2]).with_values(&values).unwrap();
            let h = TensorHandle::new(&ctx, &t).unwrap();
            let h_gpu = TensorHandle::copy_to_device(&h, &ctx, target_device).unwrap();
            assert_eq!(&h_gpu.device_name().unwrap(), target_device);
            let t2 = h_gpu.resolve::<i32>().unwrap();

            assert_eq!(&t[..], &t2[..]);
        }

        #[test]
        #[ignore]
        fn test_copy_to_device_lifetime() {
            let values = [0_i32, 1, 2, 3];

            let opts = ContextOptions::new();
            let ctx = Context::new(opts).unwrap();
            let devices = ctx.device_list().unwrap();
            let gpu_device = devices
                .iter()
                .find(|d| d.device_type == "GPU")
                .expect("No GPU device was found.");
            let target_device = &gpu_device.name;

            let h_gpu = {
                // Create a temporal Context
                let opts = ContextOptions::new();
                let ctx2 = Context::new(opts).unwrap();
                let t = Tensor::new(&[2, 2]).with_values(&values).unwrap();

                // Create a TensorHandle managed by the context `ctx2`.
                let h = TensorHandle::new(&ctx2, &t).unwrap();

                // Copy to GPU. This creates a new handle managed by the context `ctx`.
                h.copy_to_device(&ctx, target_device).unwrap()
            };
            assert_eq!(&h_gpu.device_name().unwrap(), target_device);
            let t2 = h_gpu.resolve::<i32>().unwrap();

            assert_eq!(&values[..], &t2[..]);
        }
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;

fn main() {
    match pkg_config::find_library("portaudio-2.0")
    {
        Ok(..) => {},
        Err(e) => println!("Cloud not find pkg-config ({})", e),
    }
}

<commit_msg>Revert "Do not require pkgconfig to succeed"<commit_after>extern crate pkg_config;

fn main() {
    match pkg_config::find_library("portaudio-2.0")
    {
        Ok(..) => {},
        Err(e) => panic!("{}", e),
    }
}

<|endoftext|>


<commit_before>//! `/dev/staticfs`
//! Static filesystem built into the kernel image
//! TODO: temporarily implemented with a disk driver

use d7staticfs::*;

use alloc::prelude::v1::*;
use hashbrown::HashMap;

use crate::driver::disk_io::DISK_IO;
use crate::filesystem::{
    result::*, CloseAction, FileClientId, FileOps, Leafness, Path, FILESYSTEM,
};
use crate::multitasking::WaitFor;

pub struct StaticFSLeaf {
    /// Sector on disk
    start_sector: u32,
    /// Size on disk, in bytes
    size_bytes: u64,
    /// Data, loaded when requested for the first time
    data: Option<Vec<u8>>,
    /// Readers and offsets to the data
    readers: HashMap<FileClientId, usize>,
}
impl StaticFSLeaf {
    fn new(start_sector: u32, size_bytes: u64) -> Self {
        Self {
            start_sector,
            size_bytes,
            data: None,
            readers: HashMap::new(),
        }
    }

    fn ensure_loaded(&mut self) {
        if self.data.is_none() {
            let mut dc = DISK_IO.lock();
            self.data = Some(
                dc.read(
                    self.start_sector as u64,
                    to_sectors_round_up(self.size_bytes),
                )
                .iter()
                .flatten()
                .take(self.size_bytes as usize)
                .cloned()
                .collect(),
            );
        }
    }
}
impl FileOps for StaticFSLeaf {
    fn leafness(&self) -> Leafness {
        Leafness::Leaf
    }

    fn read(&mut self, fc: FileClientId, buf: &mut [u8]) -> IoResult<usize> {
        self.ensure_loaded();
        let data = self.data.as_ref().unwrap();
        let offset = self.readers.get(&fc).copied().unwrap_or(0);
        let count = (data.len() - offset).min(buf.len());
        buf[..count].copy_from_slice(&data[offset..offset + count]);
        self.readers.insert(fc, offset + count);
        IoResult::success(count)
    }

    fn read_waiting_for(&mut self, fc: FileClientId) -> WaitFor {
        WaitFor::None
    }

    /// Remove reader when closing
    fn close(&mut self, fc: FileClientId) -> IoResult<CloseAction> {
        self.readers.remove(&fc);
        IoResult::success(CloseAction::Normal)
    }
}

/// Returns file list start sector
fn find_file_list() -> u32 {
    let mut dc = DISK_IO.lock();
    let mbr = dc.read(0, 1);
    u32::from_le_bytes([
        mbr[0][MBR_POSITION as usize + 0],
        mbr[0][MBR_POSITION as usize + 1],
        mbr[0][MBR_POSITION as usize + 2],
        mbr[0][MBR_POSITION as usize + 3],
    ])
}

/// Returns header body size, in bytes
fn load_header(file_list_sector: u32) -> u32 {
    let mut dc = DISK_IO.lock();
    let header = &dc.read(file_list_sector as u64, 1)[0][..16];

    // check magic and version
    assert_eq!(
        header[0..4],
        HEADER_MAGIC.to_le_bytes(),
        "StaticFS: Incorrect magic header"
    );
    assert_eq!(
        header[4..8],
        ONLY_VERSION.to_le_bytes(),
        "StaticFS: Incorrect version number"
    );

    u32::from_le_bytes([header[8], header[9], header[10], header[11]])
}

/// Returns file entries and their sector positions
fn load_file_entries() -> Vec<(FileEntry, u32)> {
    let base_sector = find_file_list();
    if base_sector == 0xd7cafed7 {
        panic!("StaticFS missing");
    }
    let header_body_size = load_header(base_sector) as u64;
    let sector_count = to_sectors_round_up(HEADER_SIZE_BYTES + header_body_size);
    let mut dc = DISK_IO.lock();
    let bytes: Vec<u8> = dc
        .read(base_sector as u64, sector_count)
        .iter()
        .flatten()
        .skip(HEADER_SIZE_BYTES as usize)
        .take(header_body_size as usize)
        .cloned()
        .collect();

    let file_list: Vec<FileEntry> =
        pinecone::from_bytes(&bytes[..]).expect("Could not deserialize staticfs file list");

    let mut result = Vec::new();
    let mut current_sector_offset = 0;
    for file in file_list {
        let size_sectors = file.size_sectors() as u32;
        result.push((
            file,
            base_sector + sector_count as u32 + current_sector_offset,
        ));
        current_sector_offset += size_sectors;
    }
    result
}

pub fn init() {
    let mut fs = FILESYSTEM.lock();
    let _ = fs
        .create_static_branch(Path::new("/mnt/staticfs"))
        .expect("Could not create /dev/staticfs");

    for (file_entry, pos) in load_file_entries() {
        assert!(!file_entry.name.is_empty());
        let leaf = StaticFSLeaf::new(pos, file_entry.size_bytes);
        fs.create_static(
            Path::new(&format!("/mnt/staticfs/{}", file_entry.name)),
            Box::new(leaf),
        )
        .expect("Could not create file under /mnt/staticfs");
    }
}
<commit_msg>Add Debug trait to StaticFSLeaf<commit_after>//! `/dev/staticfs`
//! Static filesystem built into the kernel image
//! TODO: temporarily implemented with a disk driver

use d7staticfs::*;

use alloc::prelude::v1::*;
use hashbrown::HashMap;

use crate::driver::disk_io::DISK_IO;
use crate::filesystem::{
    result::*, CloseAction, FileClientId, FileOps, Leafness, Path, FILESYSTEM,
};
use crate::multitasking::WaitFor;

#[derive(Debug)]
pub struct StaticFSLeaf {
    /// Sector on disk
    start_sector: u32,
    /// Size on disk, in bytes
    size_bytes: u64,
    /// Data, loaded when requested for the first time
    data: Option<Vec<u8>>,
    /// Readers and offsets to the data
    readers: HashMap<FileClientId, usize>,
}
impl StaticFSLeaf {
    fn new(start_sector: u32, size_bytes: u64) -> Self {
        Self {
            start_sector,
            size_bytes,
            data: None,
            readers: HashMap::new(),
        }
    }

    fn ensure_loaded(&mut self) {
        if self.data.is_none() {
            let mut dc = DISK_IO.lock();
            self.data = Some(
                dc.read(
                    self.start_sector as u64,
                    to_sectors_round_up(self.size_bytes),
                )
                .iter()
                .flatten()
                .take(self.size_bytes as usize)
                .cloned()
                .collect(),
            );
        }
    }
}
impl FileOps for StaticFSLeaf {
    fn leafness(&self) -> Leafness {
        Leafness::Leaf
    }

    fn read(&mut self, fc: FileClientId, buf: &mut [u8]) -> IoResult<usize> {
        self.ensure_loaded();
        let data = self.data.as_ref().unwrap();
        let offset = self.readers.get(&fc).copied().unwrap_or(0);
        let count = (data.len() - offset).min(buf.len());
        buf[..count].copy_from_slice(&data[offset..offset + count]);
        self.readers.insert(fc, offset + count);
        IoResult::success(count)
    }

    fn read_waiting_for(&mut self, fc: FileClientId) -> WaitFor {
        WaitFor::None
    }

    /// Remove reader when closing
    fn close(&mut self, fc: FileClientId) -> IoResult<CloseAction> {
        self.readers.remove(&fc);
        IoResult::success(CloseAction::Normal)
    }
}

/// Returns file list start sector
fn find_file_list() -> u32 {
    let mut dc = DISK_IO.lock();
    let mbr = dc.read(0, 1);
    u32::from_le_bytes([
        mbr[0][MBR_POSITION as usize + 0],
        mbr[0][MBR_POSITION as usize + 1],
        mbr[0][MBR_POSITION as usize + 2],
        mbr[0][MBR_POSITION as usize + 3],
    ])
}

/// Returns header body size, in bytes
fn load_header(file_list_sector: u32) -> u32 {
    let mut dc = DISK_IO.lock();
    let header = &dc.read(file_list_sector as u64, 1)[0][..16];

    // check magic and version
    assert_eq!(
        header[0..4],
        HEADER_MAGIC.to_le_bytes(),
        "StaticFS: Incorrect magic header"
    );
    assert_eq!(
        header[4..8],
        ONLY_VERSION.to_le_bytes(),
        "StaticFS: Incorrect version number"
    );

    u32::from_le_bytes([header[8], header[9], header[10], header[11]])
}

/// Returns file entries and their sector positions
fn load_file_entries() -> Vec<(FileEntry, u32)> {
    let base_sector = find_file_list();
    if base_sector == 0xd7cafed7 {
        panic!("StaticFS missing");
    }
    let header_body_size = load_header(base_sector) as u64;
    let sector_count = to_sectors_round_up(HEADER_SIZE_BYTES + header_body_size);
    let mut dc = DISK_IO.lock();
    let bytes: Vec<u8> = dc
        .read(base_sector as u64, sector_count)
        .iter()
        .flatten()
        .skip(HEADER_SIZE_BYTES as usize)
        .take(header_body_size as usize)
        .cloned()
        .collect();

    let file_list: Vec<FileEntry> =
        pinecone::from_bytes(&bytes[..]).expect("Could not deserialize staticfs file list");

    let mut result = Vec::new();
    let mut current_sector_offset = 0;
    for file in file_list {
        let size_sectors = file.size_sectors() as u32;
        result.push((
            file,
            base_sector + sector_count as u32 + current_sector_offset,
        ));
        current_sector_offset += size_sectors;
    }
    result
}

pub fn init() {
    let mut fs = FILESYSTEM.lock();
    let _ = fs
        .create_static_branch(Path::new("/mnt/staticfs"))
        .expect("Could not create /dev/staticfs");

    for (file_entry, pos) in load_file_entries() {
        assert!(!file_entry.name.is_empty());
        let leaf = StaticFSLeaf::new(pos, file_entry.size_bytes);
        fs.create_static(
            Path::new(&format!("/mnt/staticfs/{}", file_entry.name)),
            Box::new(leaf),
        )
        .expect("Could not create file under /mnt/staticfs");
    }
}
<|endoftext|>


<commit_before>//! Send record as msgpack.
//!
//! ## Usage
//!
//! This trait is used as follows:
//!
//! ```no_run
//! extern crate fruently;
//! use fruently::fluent::Fluent;
//! use std::collections::HashMap;
//! use fruently::forwardable::MsgpackForwardable;
//!
//! fn main() {
//!     let mut obj: HashMap<String, String> = HashMap::new();
//!     obj.insert("name".to_string(), "fruently".to_string());
//!     let fruently = Fluent::new("0.0.0.0:24224", "test");
//!     let _ = fruently.post(&obj);
//! }
//! ```

use std::net::ToSocketAddrs;
use rustc_serialize::Encodable;
use time;
use retry::retry_exponentially;
use record::Record;
use record::FluentError;
use forwardable::MsgpackForwardable;
use fluent::Fluent;

#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct Message<T: Encodable> {
    tag: String,
    timesec: i64,
    record: T,
}

impl<T: Encodable> Message<T> {
    pub fn new(tag: String, timesec: i64, record: T) -> Message<T> {
        Message {
            tag: tag,
            timesec: timesec,
            record: record,
        }
    }
}

impl<A: ToSocketAddrs> MsgpackForwardable for Fluent<A> {
    /// Post record into Fluentd. Without time version.
    fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.get_tag(), time, record);
        let message = record.to_message();
        let addr = self.get_addr();
        let (max, multiplier) = self.get_conf().build();
        match retry_exponentially(max,
                                  multiplier,
                                  || Fluent::closure_send_as_msgpack(addr, &message),
                                  |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature="fluentd")]
    use time;
    #[cfg(feature="fluentd")]
    use fluent::Fluent;

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::MsgpackForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust with msgpack!".to_string());
        let result = fruently.post(obj).is_ok();
        assert_eq!(true, result);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;
        use forwardable::MsgpackForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust with msgpack!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time).is_ok();
        assert_eq!(true, result);
    }
}
<commit_msg>test: Simplify<commit_after>//! Send record as msgpack.
//!
//! ## Usage
//!
//! This trait is used as follows:
//!
//! ```no_run
//! extern crate fruently;
//! use fruently::fluent::Fluent;
//! use std::collections::HashMap;
//! use fruently::forwardable::MsgpackForwardable;
//!
//! fn main() {
//!     let mut obj: HashMap<String, String> = HashMap::new();
//!     obj.insert("name".to_string(), "fruently".to_string());
//!     let fruently = Fluent::new("0.0.0.0:24224", "test");
//!     let _ = fruently.post(&obj);
//! }
//! ```

use std::net::ToSocketAddrs;
use rustc_serialize::Encodable;
use time;
use retry::retry_exponentially;
use record::Record;
use record::FluentError;
use forwardable::MsgpackForwardable;
use fluent::Fluent;

#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct Message<T: Encodable> {
    tag: String,
    timesec: i64,
    record: T,
}

impl<T: Encodable> Message<T> {
    pub fn new(tag: String, timesec: i64, record: T) -> Message<T> {
        Message {
            tag: tag,
            timesec: timesec,
            record: record,
        }
    }
}

impl<A: ToSocketAddrs> MsgpackForwardable for Fluent<A> {
    /// Post record into Fluentd. Without time version.
    fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.get_tag(), time, record);
        let message = record.to_message();
        let addr = self.get_addr();
        let (max, multiplier) = self.get_conf().build();
        match retry_exponentially(max,
                                  multiplier,
                                  || Fluent::closure_send_as_msgpack(addr, &message),
                                  |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
#[cfg(feature="fluentd")]
mod tests {
    use time;
    use fluent::Fluent;

    #[test]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::MsgpackForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust with msgpack!".to_string());
        let result = fruently.post(obj).is_ok();
        assert_eq!(true, result);
    }

    #[test]
    fn test_post_with_time() {
        use std::collections::HashMap;
        use forwardable::MsgpackForwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust with msgpack!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time).is_ok();
        assert_eq!(true, result);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
use serialize::json::{Json, ToJson};
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy};
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                if let Some(path_root) = value.path_root() {
                    let local_path_root = format!("{}/{}", rc.get_path(), path_root);
                    rc.set_local_path_root(local_path_root);
                }

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            local_rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            local_rc.set_local_var("@index".to_string(), i.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path.clone());
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), list[i].to_json());
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), k.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       k);
                                local_rc.set_path(new_path);
                            }

                            try!(t.render(c, r, &mut local_rc));
                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), k.to_json());
                                map.insert(bp_val.to_string(), obj.get(k).unwrap().to_json());
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(c, r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }

    #[cfg(feature = "serde_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                if let Some(path_root) = value.path_root() {
                    let local_path_root = format!("{}/{}", rc.get_path(), path_root);
                    rc.set_local_path_root(local_path_root);
                }

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(),
                                                   value::to_value(&(i == 0usize)));
                            local_rc.set_local_var("@last".to_string(),
                                                   value::to_value(&(i == len - 1)));
                            local_rc.set_local_var("@index".to_string(), value::to_value(&i));

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       i);
                                debug!("each value {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), value::to_value(&list[i]));
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), value::to_value(&first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), value::to_value(&k));
                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       k);
                                debug!("each value {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), value::to_value(&k));
                                map.insert(bp_val.to_string(),
                                           value::to_value(&obj.get(k).unwrap()));
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(c, r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                // rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use serialize::json::Json;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:\
                                    {{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(),
                   "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_each_with_parent() {

        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        let t0 = Template::compile("{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_nested_each_with_parent() {

        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let t0 = Template::compile("{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_nested_each() {

        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();
        let t0 = Template::compile("{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}".to_string())
            .ok()
            .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let t0 = Template::compile("{{#each this}}{{@key}}-{{value}}\n{{/each}}".to_owned())
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0",
                                   &({
                                       let mut rv = BTreeMap::new();
                                       rv.insert("foo".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "bar".to_owned());
                                           rv
                                       });
                                       rv.insert("".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "baz".to_owned());
                                           rv
                                       });
                                       rv
                                   }))
                           .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let t0 = Template::compile("{{#each a}}1{{else}}empty{{/each}}".to_owned()).unwrap();
        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        let m1 = btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 = btreemap!{
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let t0 = Template::compile("{{#each a as |i|}}{{i}}{{/each}}".to_owned()).unwrap();
        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        let m1 = btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        println!("render: {}", r0);
        assert_eq!(r0, "12345");
    }

}
<commit_msg>(fix) remove duplicate write<commit_after>use std::collections::BTreeMap;

#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
use serialize::json::{Json, ToJson};
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonTruthy};
use render::{Renderable, RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper {
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                if let Some(path_root) = value.path_root() {
                    let local_path_root = format!("{}/{}", rc.get_path(), path_root);
                    rc.set_local_path_root(local_path_root);
                }

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            local_rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            local_rc.set_local_var("@index".to_string(), i.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       i);
                                debug!("each path {:?}", new_path);
                                local_rc.set_path(new_path.clone());
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), list[i].to_json());
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), k.to_json());

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       k);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), k.to_json());
                                map.insert(bp_val.to_string(), obj.get(k).unwrap().to_json());
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(c, r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };

                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }

    #[cfg(feature = "serde_type")]
    fn call(&self,
            c: &Context,
            h: &Helper,
            r: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let value = try!(h.param(0)
                          .ok_or_else(|| RenderError::new("Param not found for helper \"each\"")));

        let template = h.template();

        match template {
            Some(t) => {
                rc.promote_local_vars();
                if let Some(path_root) = value.path_root() {
                    let local_path_root = format!("{}/{}", rc.get_path(), path_root);
                    rc.set_local_path_root(local_path_root);
                }

                debug!("each value {:?}", value.value());
                let rendered = match (value.value().is_truthy(), value.value()) {
                    (true, &Json::Array(ref list)) => {
                        let len = list.len();
                        for i in 0..len {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(),
                                                   value::to_value(&(i == 0usize)));
                            local_rc.set_local_var("@last".to_string(),
                                                   value::to_value(&(i == len - 1)));
                            local_rc.set_local_var("@index".to_string(), value::to_value(&i));

                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       i);
                                debug!("each value {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some(block_param) = h.block_param() {
                                let mut map = BTreeMap::new();
                                map.insert(block_param.to_string(), value::to_value(&list[i]));
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }
                        Ok(())
                    }
                    (true, &Json::Object(ref obj)) => {
                        let mut first: bool = true;
                        for k in obj.keys() {
                            let mut local_rc = rc.derive();
                            local_rc.set_local_var("@first".to_string(), value::to_value(&first));
                            if first {
                                first = false;
                            }

                            local_rc.set_local_var("@key".to_string(), value::to_value(&k));
                            if let Some(inner_path) = value.path() {
                                let new_path = format!("{}/{}.[{}]",
                                                       local_rc.get_path(),
                                                       inner_path,
                                                       k);
                                debug!("each value {:?}", new_path);
                                local_rc.set_path(new_path);
                            }

                            if let Some((bp_key, bp_val)) = h.block_param_pair() {
                                let mut map = BTreeMap::new();
                                map.insert(bp_key.to_string(), value::to_value(&k));
                                map.insert(bp_val.to_string(),
                                           value::to_value(&obj.get(k).unwrap()));
                                local_rc.push_block_context(&map);
                            }

                            try!(t.render(c, r, &mut local_rc));

                            if h.block_param().is_some() {
                                local_rc.pop_block_context();
                            }
                        }

                        Ok(())
                    }
                    (false, _) => {
                        if let Some(else_template) = h.inverse() {
                            try!(else_template.render(c, r, rc));
                        }
                        Ok(())
                    }
                    _ => {
                        Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
                    }
                };
                // rc.set_path(path);
                rc.demote_local_vars();
                rendered
            }
            None => Ok(()),
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    use serialize::json::Json;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:\
                                    {{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(),
                   "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m: BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_each_with_parent() {

        let json_str = r#"{"a":{"a":99,"c":[{"d":100},{"d":200}]}}"#;

        let data = Json::from_str(json_str).unwrap();
        // println!("data: {}", data);

        // previously, to access the parent in an each block,
        // a user would need to specify ../../b, as the path
        // that is computed includes the array index: ./a.c.[0]
        let t0 = Template::compile("{{#each a.c}} d={{d}} b={{../a.a}} {{/each}}".to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), " d=100 b=99  d=200 b=99 ".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_nested_each_with_parent() {

        let json_str = r#"{"a": [{"b": [{"d": 100}], "c": 200}]}"#;

        let data = Json::from_str(json_str).unwrap();
        let t0 = Template::compile("{{#each a}}{{#each b}}{{d}}:{{../c}}{{/each}}{{/each}}"
                                       .to_string())
                     .ok()
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "100:200".to_string());
    }

    #[test]
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn test_nested_each() {

        let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

        let data = Json::from_str(json_str).unwrap();
        let t0 = Template::compile("{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}".to_string())
            .ok()
            .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r1 = handlebars.render("t0", &data);
        assert_eq!(r1.ok().unwrap(), "12345".to_string());
    }

    #[test]
    fn test_nested_array() {
        let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0", &(vec![vec![1, 2, 3]]));

        assert_eq!(r0.ok().unwrap(), "123".to_string());
    }

    #[test]
    fn test_empty_key() {
        let t0 = Template::compile("{{#each this}}{{@key}}-{{value}}\n{{/each}}".to_owned())
                     .unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);

        let r0 = handlebars.render("t0",
                                   &({
                                       let mut rv = BTreeMap::new();
                                       rv.insert("foo".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "bar".to_owned());
                                           rv
                                       });
                                       rv.insert("".to_owned(), {
                                           let mut rv = BTreeMap::new();
                                           rv.insert("value".to_owned(), "baz".to_owned());
                                           rv
                                       });
                                       rv
                                   }))
                           .unwrap();

        let mut r0_sp: Vec<_> = r0.split('\n').collect();
        r0_sp.sort();

        assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
    }

    #[test]
    fn test_each_else() {
        let t0 = Template::compile("{{#each a}}1{{else}}empty{{/each}}".to_owned()).unwrap();
        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        let m1 = btreemap! {
            "a".to_string() => Vec::<String>::new(),
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        assert_eq!(r0, "empty");

        let m2 = btreemap!{
            "b".to_string() => Vec::<String>::new()
        };
        let r1 = handlebars.render("t0", &m2).unwrap();
        assert_eq!(r1, "empty");
    }

    #[test]
    fn test_block_param() {
        let t0 = Template::compile("{{#each a as |i|}}{{i}}{{/each}}".to_owned()).unwrap();
        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        let m1 = btreemap! {
            "a".to_string() => vec![1,2,3,4,5]
        };
        let r0 = handlebars.render("t0", &m1).unwrap();
        println!("render: {}", r0);
        assert_eq!(r0, "12345");
    }

}
<|endoftext|>