<commit_before>#![allow(dead_code)] // until raw_ops are implemented

use libc::c_float;
use libc::c_int;
use libc::c_uchar;
use libc::c_void;
use libc::size_t;
use std::ffi::{CStr, CString};
use std::os::raw::c_void as std_c_void;
use std::ptr;

use crate::eager::{Context, TensorHandle};
use crate::{AnyTensor, DataType, Result, Shape, Status};

use tensorflow_sys as tf;

/// Description of the TensorFlow op to execute.
struct Op {
    inner: *mut tf::TFE_Op,
}
impl_drop!(Op, TFE_DeleteOp);

impl Op {
    fn new(ctx: &Context, op_or_function_name: &str) -> Result<Op> {
        let status = Status::new();

        let op_or_function_name = CString::new(op_or_function_name)?;
        let inner = unsafe { tf::TFE_NewOp(ctx.inner, op_or_function_name.as_ptr(), status.inner) };
        if inner.is_null() {
            return Err(status);
        }
        Ok(Self { inner })
    }

    #[allow(dead_code)]
    fn get_name(&self) -> Result<&str> {
        let status = Status::new();

        let name = unsafe {
            let name = tf::TFE_OpGetName(self.inner, status.inner);
            CStr::from_ptr(name)
        };
        if status.is_ok() {
            return Ok(name.to_str()?);
        }
        Err(status)
    }

    /// Context may not be outlive over the lifetime of `op'
    #[allow(dead_code)]
    fn get_context(&self) -> &Context {
        unimplemented!()
    }

    /// Adds an input to this operation.
    fn add_input(&mut self, input: &TensorHandle) -> Result<()> {
        let status = Status::new();
        unsafe {
            tf::TFE_OpAddInput(self.inner, input.inner, status.inner);
        };
        status.into_result()
    }

    /// Set the device where this operation is computed.
    fn set_device(&mut self, device_name: &str) -> Result<()> {
        let status = Status::new();
        let c_device_name = CString::new(device_name)?;
        unsafe {
            tf::TFE_OpSetDevice(self.inner, c_device_name.as_ptr(), status.inner);
        }
        status.into_result()
    }

    /// Get the device where this operation is computed.
    fn get_device(&self) -> Result<&str> {
        let status = Status::new();
        let device_name = unsafe {
            // The returned string remains valid throughout the lifetime of 'op'.
            let device_name = tf::TFE_OpGetDevice(self.inner, status.inner);
            CStr::from_ptr(device_name)
        };
        if status.is_ok() {
            return Ok(device_name.to_str()?);
        }
        Err(status)
    }

    /// Adds multiple inputs to this operation.
    #[allow(dead_code)]
    fn add_input_list(&mut self, inputs: &[TensorHandle]) -> Result<()> {
        let status = Status::new();
        unsafe {
            let mut inputs: Vec<*mut tf::TFE_TensorHandle> =
                inputs.iter().map(|v| v.inner).collect();
            tf::TFE_OpAddInputList(
                self.inner,
                inputs.as_mut_ptr(),
                inputs.len() as c_int,
                status.inner,
            );
        };
        status.into_result()
    }

    /// Sets the value of a string attribute.
    fn set_attr_string(&mut self, attr_name: &str, value: &str) -> Result<()> {
        let attr_name = CString::new(attr_name)?;
        let c_value = value.as_bytes();
        unsafe {
            tf::TFE_OpSetAttrString(
                self.inner,
                attr_name.as_ptr(),
                c_value.as_ptr() as *const std_c_void,
                c_value.len() as size_t,
            );
        }
        Ok(())
    }

    /// Sets the value of an attribute which holds a list of strings.
    fn set_attr_string_list<S: AsRef<str>>(&mut self, attr_name: &str, values: &[S]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let bytes: Vec<&[u8]> = values.iter().map(|x| x.as_ref().as_bytes()).collect();
        let ptrs: Vec<*const c_void> = bytes.iter().map(|x| x.as_ptr() as *const c_void).collect();
        let lens: Vec<size_t> = bytes.iter().map(|x| x.len() as size_t).collect();
        unsafe {
            tf::TFE_OpSetAttrStringList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_ptr() as *const *const std_c_void,
                lens.as_ptr(),
                ptrs.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets an int-valued attribute.
    fn set_attr_int(&mut self, attr_name: &str, value: i64) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrInt(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of ints.
    fn set_attr_int_list(&mut self, attr_name: &str, value: &[i64]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrIntList(
                self.inner,
                c_attr_name.as_ptr(),
                value.as_ptr(),
                value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a float-valued attribute.
    fn set_attr_float(&mut self, attr_name: &str, value: f32) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrFloat(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of floats.
    fn set_attr_float_list(&mut self, attr_name: &str, value: &[f32]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        // Allow trivial_numeric_casts here because f32 is not necessarily equal to c_float.
        let c_value: Vec<c_float> = value.iter().map(|x| *x as c_float).collect();
        unsafe {
            tf::TFE_OpSetAttrFloatList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a boolean-valued attribute.
    fn set_attr_bool(&mut self, attr_name: &str, value: bool) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrBool(self.inner, c_attr_name.as_ptr(), if value { 1 } else { 0 });
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of booleans.
    fn set_attr_bool_list(&mut self, attr_name: &str, value: &[bool]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<c_uchar> = value.iter().map(|x| if *x { 1 } else { 0 }).collect();
        unsafe {
            tf::TFE_OpSetAttrBoolList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets a type-valued attribute.
    fn set_attr_type(&mut self, attr_name: &str, value: DataType) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrType(self.inner, c_attr_name.as_ptr(), value.to_c());
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of types.
    fn set_attr_type_list(&mut self, attr_name: &str, value: &[DataType]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<tf::TF_DataType> = value.iter().map(|x| x.to_c()).collect();
        unsafe {
            tf::TFE_OpSetAttrTypeList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a shape-valued attribute.
    fn set_attr_shape(&mut self, attr_name: &str, value: &Shape) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            match value.0 {
                None => tf::TFE_OpSetAttrShape(
                    self.inner,
                    c_attr_name.as_ptr(),
                    ptr::null(),
                    -1,
                    status.inner,
                ),
                Some(ref dims) => {
                    let c_dims: Vec<i64> = dims.iter().map(|x| (*x).unwrap_or(-1)).collect();
                    tf::TFE_OpSetAttrShape(
                        self.inner,
                        c_attr_name.as_ptr(),
                        c_dims.as_ptr(),
                        c_dims.len() as i32,
                        status.inner,
                    );
                }
            }
        }
        status.into_result()
    }

    /// Sets an attribute which holds an array of shapes.
    fn set_attr_shape_list(&mut self, attr_name: &str, value: &[Shape]) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        // Convert Option<i64> in each shape to i64 with None becoming -1.
        let c_dims: Vec<Option<Vec<i64>>> = value
            .iter()
            .map(|x| {
                x.0.as_ref()
                    .map(|dims| dims.iter().map(|x| (*x).unwrap_or(-1)).collect())
            })
            .collect();
        let mut ptrs: Vec<*const i64> = c_dims
            .iter()
            .map(|x| match *x {
                None => ptr::null(),
                Some(ref dims) => dims.as_ptr(),
            })
            .collect();
        let lens: Vec<c_int> = value
            .iter()
            .map(|x| match x.0 {
                None => -1,
                Some(ref dims) => dims.len() as c_int,
            })
            .collect();
        unsafe {
            tf::TFE_OpSetAttrShapeList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_mut_ptr(),
                lens.as_ptr(),
                ptrs.len() as c_int,
                status.inner,
            );
        }
        status.into_result()
    }

    /// Sets a tensor-valued attribute.
    fn set_attr_any_tensor(&mut self, attr_name: &str, value: &dyn AnyTensor) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let mut status = Status::new();
        unsafe {
            tf::TFE_OpSetAttrTensor(
                self.inner,
                c_attr_name.as_ptr(),
                value.inner()?,
                status.inner(),
            );
        }
        status.into_result()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::eager::{Context, ContextOptions, TensorHandle};
    use crate::Tensor;

    // Tentative implementation of raw_ops for unit testing.
    mod raw_ops {
        use super::*;
        use crate::eager::TensorHandle;

        /// Add
        #[derive(::std::fmt::Debug)]
        pub struct Add {
            T: ::std::option::Option<crate::DataType>,
        }

        impl ::std::default::Default for Add {
            fn default() -> Self {
                Self { T: None }
            }
        }

        impl Add {
            /// Creates a new `Add`.
            pub fn new() -> Self {
                Self::default()
            }

            /// Sets the `T` attribute.
            pub fn T<ArgType: ::std::convert::Into<crate::DataType>>(
                mut self,
                value: ArgType,
            ) -> Self {
                self.T = ::std::option::Option::Some(value.into());
                self
            }

            /// Execute add.
            pub fn call<'a>(
                &self,
                ctx: &'a crate::eager::Context,
                x: &TensorHandle,
                y: &TensorHandle,
            ) -> Result<TensorHandle<'a>> {
                let status = crate::Status::new();

                // Define Op

                let op_name = "Add";
                let mut op = Op::new(ctx, op_name)?;

                // Required input arguments
                op.add_input(&x)?;
                op.add_input(&y)?;

                // Attributes
                if let ::std::option::Option::Some(value) = &self.T {
                    let attr_name = "T";
                    op.set_attr_type(attr_name, *value)?;
                }

                // Execute Op
                let mut num_output = 1;
                let mut res = [std::ptr::null_mut::<tensorflow_sys::TFE_TensorHandle>(); 1];
                unsafe {
                    tf::TFE_Execute(
                        op.inner,
                        res.as_mut_ptr(),
                        (&mut num_output) as *mut i32,
                        status.inner,
                    );
                };
                if status.is_ok() {
                    let ret = TensorHandle::from_tensor_handle(ctx, res[0]);
                    return Ok(ret);
                }
                Err(status)
            }
        }

        /// add with default options.
        pub fn add<'a>(
            ctx: &'a crate::eager::Context,
            x: &TensorHandle,
            y: &TensorHandle,
        ) -> Result<TensorHandle<'a>> {
            let op = Add::new();
            op.call(ctx, x, y)
        }
    }

    #[test]
    fn test_add() {
        use raw_ops::add;

        let ctx = Context::new(ContextOptions::new()).unwrap();
        let x = Tensor::new(&[2, 2]).with_values(&[1i32, 2, 3, 4]).unwrap();
        let h_x = TensorHandle::new(&ctx, &x).unwrap();
        let h_y = h_x.copy_sharing_tensor().unwrap();
        let h_z = add(&ctx, &h_x, &h_y).unwrap();
        let z: crate::Tensor<i32> = h_z.resolve().unwrap();
        assert_eq!(&z[..], &[2i32, 4, 6, 8]);
    }
}
<commit_msg>add unittest for Op executed on GPU<commit_after>#![allow(dead_code)] // until raw_ops are implemented

use libc::c_float;
use libc::c_int;
use libc::c_uchar;
use libc::c_void;
use libc::size_t;
use std::ffi::{CStr, CString};
use std::os::raw::c_void as std_c_void;
use std::ptr;

use crate::eager::{Context, TensorHandle};
use crate::{AnyTensor, DataType, Result, Shape, Status};

use tensorflow_sys as tf;

/// Description of the TensorFlow op to execute.
struct Op {
    inner: *mut tf::TFE_Op,
}
impl_drop!(Op, TFE_DeleteOp);

impl Op {
    fn new(ctx: &Context, op_or_function_name: &str) -> Result<Op> {
        let status = Status::new();

        let op_or_function_name = CString::new(op_or_function_name)?;
        let inner = unsafe { tf::TFE_NewOp(ctx.inner, op_or_function_name.as_ptr(), status.inner) };
        if inner.is_null() {
            return Err(status);
        }
        Ok(Self { inner })
    }

    #[allow(dead_code)]
    fn get_name(&self) -> Result<&str> {
        let status = Status::new();

        let name = unsafe {
            let name = tf::TFE_OpGetName(self.inner, status.inner);
            CStr::from_ptr(name)
        };
        if status.is_ok() {
            return Ok(name.to_str()?);
        }
        Err(status)
    }

    /// Context may not be outlive over the lifetime of `op'
    #[allow(dead_code)]
    fn get_context(&self) -> &Context {
        unimplemented!()
    }

    /// Adds an input to this operation.
    fn add_input(&mut self, input: &TensorHandle) -> Result<()> {
        let status = Status::new();
        unsafe {
            tf::TFE_OpAddInput(self.inner, input.inner, status.inner);
        };
        status.into_result()
    }

    /// Set the device where this operation is computed.
    fn set_device(&mut self, device_name: &str) -> Result<()> {
        let status = Status::new();
        let c_device_name = CString::new(device_name)?;
        unsafe {
            tf::TFE_OpSetDevice(self.inner, c_device_name.as_ptr(), status.inner);
        }
        status.into_result()
    }

    /// Get the device where this operation is computed.
    fn get_device(&self) -> Result<&str> {
        let status = Status::new();
        let device_name = unsafe {
            // The returned string remains valid throughout the lifetime of 'op'.
            let device_name = tf::TFE_OpGetDevice(self.inner, status.inner);
            CStr::from_ptr(device_name)
        };
        if status.is_ok() {
            return Ok(device_name.to_str()?);
        }
        Err(status)
    }

    /// Adds multiple inputs to this operation.
    #[allow(dead_code)]
    fn add_input_list(&mut self, inputs: &[TensorHandle]) -> Result<()> {
        let status = Status::new();
        unsafe {
            let mut inputs: Vec<*mut tf::TFE_TensorHandle> =
                inputs.iter().map(|v| v.inner).collect();
            tf::TFE_OpAddInputList(
                self.inner,
                inputs.as_mut_ptr(),
                inputs.len() as c_int,
                status.inner,
            );
        };
        status.into_result()
    }

    /// Sets the value of a string attribute.
    fn set_attr_string(&mut self, attr_name: &str, value: &str) -> Result<()> {
        let attr_name = CString::new(attr_name)?;
        let c_value = value.as_bytes();
        unsafe {
            tf::TFE_OpSetAttrString(
                self.inner,
                attr_name.as_ptr(),
                c_value.as_ptr() as *const std_c_void,
                c_value.len() as size_t,
            );
        }
        Ok(())
    }

    /// Sets the value of an attribute which holds a list of strings.
    fn set_attr_string_list<S: AsRef<str>>(&mut self, attr_name: &str, values: &[S]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let bytes: Vec<&[u8]> = values.iter().map(|x| x.as_ref().as_bytes()).collect();
        let ptrs: Vec<*const c_void> = bytes.iter().map(|x| x.as_ptr() as *const c_void).collect();
        let lens: Vec<size_t> = bytes.iter().map(|x| x.len() as size_t).collect();
        unsafe {
            tf::TFE_OpSetAttrStringList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_ptr() as *const *const std_c_void,
                lens.as_ptr(),
                ptrs.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets an int-valued attribute.
    fn set_attr_int(&mut self, attr_name: &str, value: i64) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrInt(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of ints.
    fn set_attr_int_list(&mut self, attr_name: &str, value: &[i64]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrIntList(
                self.inner,
                c_attr_name.as_ptr(),
                value.as_ptr(),
                value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a float-valued attribute.
    fn set_attr_float(&mut self, attr_name: &str, value: f32) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrFloat(self.inner, c_attr_name.as_ptr(), value);
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of floats.
    fn set_attr_float_list(&mut self, attr_name: &str, value: &[f32]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        // Allow trivial_numeric_casts here because f32 is not necessarily equal to c_float.
        let c_value: Vec<c_float> = value.iter().map(|x| *x as c_float).collect();
        unsafe {
            tf::TFE_OpSetAttrFloatList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a boolean-valued attribute.
    fn set_attr_bool(&mut self, attr_name: &str, value: bool) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrBool(self.inner, c_attr_name.as_ptr(), if value { 1 } else { 0 });
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of booleans.
    fn set_attr_bool_list(&mut self, attr_name: &str, value: &[bool]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<c_uchar> = value.iter().map(|x| if *x { 1 } else { 0 }).collect();
        unsafe {
            tf::TFE_OpSetAttrBoolList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as c_int,
            );
        }
        Ok(())
    }

    /// Sets a type-valued attribute.
    fn set_attr_type(&mut self, attr_name: &str, value: DataType) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            tf::TFE_OpSetAttrType(self.inner, c_attr_name.as_ptr(), value.to_c());
        }
        Ok(())
    }

    /// Sets an attribute which holds an array of types.
    fn set_attr_type_list(&mut self, attr_name: &str, value: &[DataType]) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let c_value: Vec<tf::TF_DataType> = value.iter().map(|x| x.to_c()).collect();
        unsafe {
            tf::TFE_OpSetAttrTypeList(
                self.inner,
                c_attr_name.as_ptr(),
                c_value.as_ptr(),
                c_value.len() as i32,
            );
        }
        Ok(())
    }

    /// Sets a shape-valued attribute.
    fn set_attr_shape(&mut self, attr_name: &str, value: &Shape) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        unsafe {
            match value.0 {
                None => tf::TFE_OpSetAttrShape(
                    self.inner,
                    c_attr_name.as_ptr(),
                    ptr::null(),
                    -1,
                    status.inner,
                ),
                Some(ref dims) => {
                    let c_dims: Vec<i64> = dims.iter().map(|x| (*x).unwrap_or(-1)).collect();
                    tf::TFE_OpSetAttrShape(
                        self.inner,
                        c_attr_name.as_ptr(),
                        c_dims.as_ptr(),
                        c_dims.len() as i32,
                        status.inner,
                    );
                }
            }
        }
        status.into_result()
    }

    /// Sets an attribute which holds an array of shapes.
    fn set_attr_shape_list(&mut self, attr_name: &str, value: &[Shape]) -> Result<()> {
        let status = Status::new();

        let c_attr_name = CString::new(attr_name)?;
        // Convert Option<i64> in each shape to i64 with None becoming -1.
        let c_dims: Vec<Option<Vec<i64>>> = value
            .iter()
            .map(|x| {
                x.0.as_ref()
                    .map(|dims| dims.iter().map(|x| (*x).unwrap_or(-1)).collect())
            })
            .collect();
        let mut ptrs: Vec<*const i64> = c_dims
            .iter()
            .map(|x| match *x {
                None => ptr::null(),
                Some(ref dims) => dims.as_ptr(),
            })
            .collect();
        let lens: Vec<c_int> = value
            .iter()
            .map(|x| match x.0 {
                None => -1,
                Some(ref dims) => dims.len() as c_int,
            })
            .collect();
        unsafe {
            tf::TFE_OpSetAttrShapeList(
                self.inner,
                c_attr_name.as_ptr(),
                ptrs.as_mut_ptr(),
                lens.as_ptr(),
                ptrs.len() as c_int,
                status.inner,
            );
        }
        status.into_result()
    }

    /// Sets a tensor-valued attribute.
    fn set_attr_any_tensor(&mut self, attr_name: &str, value: &dyn AnyTensor) -> Result<()> {
        let c_attr_name = CString::new(attr_name)?;
        let mut status = Status::new();
        unsafe {
            tf::TFE_OpSetAttrTensor(
                self.inner,
                c_attr_name.as_ptr(),
                value.inner()?,
                status.inner(),
            );
        }
        status.into_result()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::eager::{Context, ContextOptions, TensorHandle};
    use crate::Tensor;

    // Tentative implementation of raw_ops for unit testing.
    mod raw_ops {
        use super::*;
        use crate::eager::TensorHandle;

        /// Add
        #[derive(::std::fmt::Debug)]
        pub struct Add {
            T: ::std::option::Option<crate::DataType>,
            device_name: ::std::option::Option<String>,
        }

        impl ::std::default::Default for Add {
            fn default() -> Self {
                Self {
                    T: None,
                    device_name: None,
                }
            }
        }

        impl Add {
            /// Creates a new `Add`.
            pub fn new() -> Self {
                Self::default()
            }

            /// Sets the `T` attribute.
            pub fn T<ArgType: ::std::convert::Into<crate::DataType>>(
                mut self,
                value: ArgType,
            ) -> Self {
                self.T = ::std::option::Option::Some(value.into());
                self
            }

            pub fn set_device(&mut self, device_name: &str) {
                self.device_name = ::std::option::Option::Some(device_name.to_string());
            }

            /// Execute add.
            pub fn call<'a>(
                &self,
                ctx: &'a crate::eager::Context,
                x: &TensorHandle,
                y: &TensorHandle,
            ) -> Result<TensorHandle<'a>> {
                let status = crate::Status::new();

                // Define Op

                let op_name = "Add";
                let mut op = Op::new(ctx, op_name)?;

                // Required input arguments
                op.add_input(&x)?;
                op.add_input(&y)?;

                // Attributes
                if let ::std::option::Option::Some(value) = &self.T {
                    let attr_name = "T";
                    op.set_attr_type(attr_name, *value)?;
                }

                // Device
                if let ::std::option::Option::Some(device_name) = &self.device_name {
                    op.set_device(device_name)?;
                }

                // Execute Op
                let mut num_output = 1;
                let mut res = [std::ptr::null_mut::<tensorflow_sys::TFE_TensorHandle>(); 1];
                unsafe {
                    tf::TFE_Execute(
                        op.inner,
                        res.as_mut_ptr(),
                        (&mut num_output) as *mut i32,
                        status.inner,
                    );
                };
                if status.is_ok() {
                    let ret = TensorHandle::from_tensor_handle(ctx, res[0]);
                    return Ok(ret);
                }
                Err(status)
            }
        }

        /// add with default options.
        pub fn add<'a>(
            ctx: &'a crate::eager::Context,
            x: &TensorHandle,
            y: &TensorHandle,
        ) -> Result<TensorHandle<'a>> {
            let op = Add::new();
            op.call(ctx, x, y)
        }
    }

    #[test]
    fn test_add() {
        use raw_ops::add;

        let ctx = Context::new(ContextOptions::new()).unwrap();
        let x = Tensor::new(&[2, 2]).with_values(&[1i32, 2, 3, 4]).unwrap();
        let h_x = TensorHandle::new(&ctx, &x).unwrap();
        let h_y = h_x.copy_sharing_tensor().unwrap();
        let h_z = add(&ctx, &h_x, &h_y).unwrap();
        let z: crate::Tensor<i32> = h_z.resolve().unwrap();
        assert_eq!(&z[..], &[2i32, 4, 6, 8]);
    }

    #[cfg(feature = "tensorflow_gpu")]
    #[test]
    fn test_add_gpu() {
        use raw_ops::Add;

        let target_device = "/job:localhost/replica:0/task:0/device:GPU:0";

        let ctx = Context::new(ContextOptions::new()).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 x = Tensor::new(&[2, 2])
            .with_values(&[1.0f32, 2.0, 3.0, 4.0])
            .unwrap();
        let h = TensorHandle::new(&ctx, &x).unwrap();
        // Copy to GPU. This creates a new handle managed by the context `ctx`.
        let h_gpu = h.copy_to_device(&ctx, target_device).unwrap();

        let mut add = Add::new();
        add.set_device(target_device);

        let h_z_gpu = add.call(&ctx, &h, &h_gpu).unwrap();
        assert!(h_z_gpu.device_name().unwrap() == target_device);

        let z: crate::Tensor<f32> = h_z_gpu.resolve().unwrap();
        let expected = [2.0f32, 4.0, 6.0, 8.0];
        for (v0, v1) in z.iter().zip(&expected) {
            assert!((v0 - v1).abs() < f32::EPSILON);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Initialise upgrade.rs<commit_after><|endoftext|>


<commit_before><commit_msg>for serde sample fixed Deserialization.<commit_after><|endoftext|>


<commit_before>// cargo bench

#![feature(test)]

extern crate test;

use std::io::Write;
use std::{f32, f64};
use test::{black_box, Bencher};

macro_rules! benches {
    ($($name:ident($value:expr),)*) => {
        mod bench_ryu {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = ryu::Buffer::new();

                    b.iter(move || {
                        let value = black_box($value);
                        let formatted = buf.format_finite(value);
                        black_box(formatted);
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = Vec::with_capacity(20);

                    b.iter(|| {
                        buf.clear();
                        let value = black_box($value);
                        write!(&mut buf, "{}", value).unwrap();
                        black_box(buf.as_slice());
                    });
                }
            )*
        }
    }
}

benches!(
    bench_0_f64(0f64),
    bench_short_f64(0.1234f64),
    bench_e_f64(2.718281828459045f64),
    bench_max_f64(f64::MAX),
    bench_0_f32(0f32),
    bench_short_f32(0.1234f32),
    bench_e_f32(2.718281828459045f32),
    bench_max_f32(f32::MAX),
);
<commit_msg>Tweak formatting of macros in benchmark<commit_after>// cargo bench

#![feature(test)]

extern crate test;

use std::io::Write;
use std::{f32, f64};
use test::{black_box, Bencher};

macro_rules! benches {
    ($($name:ident($value:expr),)*) => {
        mod bench_ryu {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = ryu::Buffer::new();

                    b.iter(move || {
                        let value = black_box($value);
                        let formatted = buf.format_finite(value);
                        black_box(formatted);
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = Vec::with_capacity(20);

                    b.iter(|| {
                        buf.clear();
                        let value = black_box($value);
                        write!(&mut buf, "{}", value).unwrap();
                        black_box(buf.as_slice());
                    });
                }
            )*
        }
    };
}

benches! {
    bench_0_f64(0f64),
    bench_short_f64(0.1234f64),
    bench_e_f64(2.718281828459045f64),
    bench_max_f64(f64::MAX),
    bench_0_f32(0f32),
    bench_short_f32(0.1234f32),
    bench_e_f32(2.718281828459045f32),
    bench_max_f32(f32::MAX),
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write};
use std::path::Path;
use std::str::FromStr;
use strum_macros::{AsRefStr, EnumString};
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};

static ABOUT: &str = "Report or omit repeated lines.";
pub mod options {
    pub static ALL_REPEATED: &str = "all-repeated";
    pub static CHECK_CHARS: &str = "check-chars";
    pub static COUNT: &str = "count";
    pub static IGNORE_CASE: &str = "ignore-case";
    pub static REPEATED: &str = "repeated";
    pub static SKIP_FIELDS: &str = "skip-fields";
    pub static SKIP_CHARS: &str = "skip-chars";
    pub static UNIQUE: &str = "unique";
    pub static ZERO_TERMINATED: &str = "zero-terminated";
    pub static GROUP: &str = "group";
}

static ARG_FILES: &str = "files";

#[derive(PartialEq, Clone, Copy, AsRefStr, EnumString)]
#[strum(serialize_all = "snake_case")]
enum Delimiters {
    Append,
    Prepend,
    Separate,
    Both,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) {
        let mut first_line_printed = false;
        let mut group_count = 1;
        let line_terminator = self.get_line_terminator();
        let mut lines = reader.split(line_terminator).map(get_line_string);
        let mut line = match lines.next() {
            Some(l) => l,
            None => return,
        };

        // compare current `line` with consecutive lines (`next_line`) of the input
        // and if needed, print `line` based on the command line options provided
        for next_line in lines {
            if self.cmp_keys(&line, &next_line) {
                if (group_count == 1 && !self.repeats_only)
                    || (group_count > 1 && !self.uniques_only)
                {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                }
                line = next_line;
                group_count = 1;
            } else {
                if self.all_repeated {
                    self.print_line(writer, &line, group_count, first_line_printed);
                    first_line_printed = true;
                    line = next_line;
                }
                group_count += 1;
            }
        }
        if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
            self.print_line(writer, &line, group_count, first_line_printed);
            first_line_printed = true;
        }
        if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
            && first_line_printed
        {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            let mut i = 0;
            let mut char_indices = line.char_indices();
            for _ in 0..skip_fields {
                if char_indices.find(|(_, c)| !c.is_whitespace()) == None {
                    return "";
                }
                match char_indices.find(|(_, c)| c.is_whitespace()) {
                    None => return "",

                    Some((next_field_i, _)) => i = next_field_i,
                }
            }
            &line[i..]
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            b'\n'
        }
    }

    fn cmp_keys(&self, first: &str, second: &str) -> bool {
        self.cmp_key(first, |first_iter| {
            self.cmp_key(second, |second_iter| first_iter.ne(second_iter))
        })
    }

    fn cmp_key<F>(&self, line: &str, mut closure: F) -> bool
    where
        F: FnMut(&mut dyn Iterator<Item = char>) -> bool,
    {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: avoid doing any work if there is no need to skip or map to lower-case
            if !self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars());
            }

            // fast path: avoid skipping
            if self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars().flat_map(|c| c.to_uppercase()));
            }

            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return closure(&mut fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            closure(
                &mut fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .flat_map(|c| c.to_uppercase()),
            )
        } else {
            closure(&mut fields_to_check.chars())
        }
    }

    fn should_print_delimiter(&self, group_count: usize, first_line_printed: bool) -> bool {
        // if no delimiter option is selected then no other checks needed
        self.delimiters != Delimiters::None
            // print delimiter only before the first line of a group, not between lines of a group
            && group_count == 1
            // if at least one line has been output before current group then print delimiter
            && (first_line_printed
                // or if we need to prepend delimiter then print it even at the start of the output
                || self.delimiters == Delimiters::Prepend
                // the 'both' delimit mode should prepend and append delimiters
                || self.delimiters == Delimiters::Both)
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        first_line_printed: bool,
    ) {
        let line_terminator = self.get_line_terminator();

        if self.should_print_delimiter(count, first_line_printed) {
            crash_if_err!(1, writer.write_all(&[line_terminator]));
        }

        crash_if_err!(
            1,
            if self.show_counts {
                writer.write_all(format!("{:7} {}", count, line).as_bytes())
            } else {
                writer.write_all(line.as_bytes())
            }
        );
        crash_if_err!(1, writer.write_all(&[line_terminator]));
    }
}

fn get_line_string(io_line: Result<Vec<u8>>) -> String {
    let line_bytes = crash_if_err!(1, io_line);
    crash_if_err!(1, String::from_utf8(line_bytes))
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
    matches.value_of(opt_name).map(|arg_str| {
        let opt_val: Option<T> = arg_str.parse().ok();
        opt_val.unwrap_or_else(|| {
            crash!(
                1,
                "Invalid argument for {}: {}",
                opt_name,
                arg_str.maybe_quote()
            )
        })
    })
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [OUTPUT]]...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from(
        "Filter adjacent matching lines from INPUT (or standard input),\n\
        writing to OUTPUT (or standard output).
        Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\
        You may want to sort the input first, or use 'sort -u' without 'uniq'.\n",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (in_file_name, out_file_name) = match files.len() {
        0 => ("-".to_owned(), "-".to_owned()),
        1 => (files[0].clone(), "-".to_owned()),
        2 => (files[0].clone(), files[1].clone()),
        _ => {
            // Cannot happen as clap will fail earlier
            return Err(USimpleError::new(1, format!("Extra operand: {}", files[2])));
        }
    };

    let uniq = Uniq {
        repeats_only: matches.is_present(options::REPEATED)
            || matches.is_present(options::ALL_REPEATED),
        uniques_only: matches.is_present(options::UNIQUE),
        all_repeated: matches.is_present(options::ALL_REPEATED)
            || matches.is_present(options::GROUP),
        delimiters: get_delimiter(&matches),
        show_counts: matches.is_present(options::COUNT),
        skip_fields: opt_parsed(options::SKIP_FIELDS, &matches),
        slice_start: opt_parsed(options::SKIP_CHARS, &matches),
        slice_stop: opt_parsed(options::CHECK_CHARS, &matches),
        ignore_case: matches.is_present(options::IGNORE_CASE),
        zero_terminated: matches.is_present(options::ZERO_TERMINATED),
    };
    uniq.print_uniq(
        &mut open_input_file(in_file_name),
        &mut open_output_file(out_file_name),
    );

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ALL_REPEATED)
                .short("D")
                .long(options::ALL_REPEATED)
                .possible_values(&[
                    Delimiters::None.as_ref(), Delimiters::Prepend.as_ref(), Delimiters::Separate.as_ref()
                ])
                .help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
                .value_name("delimit-method")
                .min_values(0)
                .max_values(1),
        )
        .arg(
            Arg::with_name(options::GROUP)
                .long(options::GROUP)
                .possible_values(&[
                    Delimiters::Separate.as_ref(), Delimiters::Prepend.as_ref(),
                    Delimiters::Append.as_ref(), Delimiters::Both.as_ref()
                ])
                .help("show all items, separating groups with an empty line. [default: separate]")
                .value_name("group-method")
                .min_values(0)
                .max_values(1)
                .conflicts_with_all(&[
                    options::REPEATED,
                    options::ALL_REPEATED,
                    options::UNIQUE,
                ]),
        )
        .arg(
            Arg::with_name(options::CHECK_CHARS)
                .short("w")
                .long(options::CHECK_CHARS)
                .help("compare no more than N characters in lines")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::COUNT)
                .short("c")
                .long(options::COUNT)
                .help("prefix lines by the number of occurrences"),
        )
        .arg(
            Arg::with_name(options::IGNORE_CASE)
                .short("i")
                .long(options::IGNORE_CASE)
                .help("ignore differences in case when comparing"),
        )
        .arg(
            Arg::with_name(options::REPEATED)
                .short("d")
                .long(options::REPEATED)
                .help("only print duplicate lines"),
        )
        .arg(
            Arg::with_name(options::SKIP_CHARS)
                .short("s")
                .long(options::SKIP_CHARS)
                .help("avoid comparing the first N characters")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::SKIP_FIELDS)
                .short("f")
                .long(options::SKIP_FIELDS)
                .help("avoid comparing the first N fields")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::UNIQUE)
                .short("u")
                .long(options::UNIQUE)
                .help("only print unique lines"),
        )
        .arg(
            Arg::with_name(options::ZERO_TERMINATED)
                .short("z")
                .long(options::ZERO_TERMINATED)
                .help("end lines with 0 byte, not newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .max_values(2),
        )
}

fn get_delimiter(matches: &ArgMatches) -> Delimiters {
    let value = matches
        .value_of(options::ALL_REPEATED)
        .or_else(|| matches.value_of(options::GROUP));
    if let Some(delimiter_arg) = value {
        crash_if_err!(1, Delimiters::from_str(delimiter_arg))
    } else if matches.is_present(options::GROUP) {
        Delimiters::Separate
    } else {
        Delimiters::None
    }
}

fn open_input_file(in_file_name: String) -> BufReader<Box<dyn Read + 'static>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path);
        let r = crash_if_err!(1, in_file);
        Box::new(r) as Box<dyn Read>
    };
    BufReader::new(in_file)
}

fn open_output_file(out_file_name: String) -> BufWriter<Box<dyn Write + 'static>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<dyn Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let in_file = File::create(&path);
        let w = crash_if_err!(1, in_file);
        Box::new(w) as Box<dyn Write>
    };
    BufWriter::new(out_file)
}
<commit_msg>uniq: use UResult<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File;
use std::io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::str::FromStr;
use strum_macros::{AsRefStr, EnumString};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};

static ABOUT: &str = "Report or omit repeated lines.";
pub mod options {
    pub static ALL_REPEATED: &str = "all-repeated";
    pub static CHECK_CHARS: &str = "check-chars";
    pub static COUNT: &str = "count";
    pub static IGNORE_CASE: &str = "ignore-case";
    pub static REPEATED: &str = "repeated";
    pub static SKIP_FIELDS: &str = "skip-fields";
    pub static SKIP_CHARS: &str = "skip-chars";
    pub static UNIQUE: &str = "unique";
    pub static ZERO_TERMINATED: &str = "zero-terminated";
    pub static GROUP: &str = "group";
}

static ARG_FILES: &str = "files";

#[derive(PartialEq, Clone, Copy, AsRefStr, EnumString)]
#[strum(serialize_all = "snake_case")]
enum Delimiters {
    Append,
    Prepend,
    Separate,
    Both,
    None,
}

struct Uniq {
    repeats_only: bool,
    uniques_only: bool,
    all_repeated: bool,
    delimiters: Delimiters,
    show_counts: bool,
    skip_fields: Option<usize>,
    slice_start: Option<usize>,
    slice_stop: Option<usize>,
    ignore_case: bool,
    zero_terminated: bool,
}

macro_rules! write_line_terminator {
    ($writer:expr, $line_terminator:expr) => {
        $writer
            .write_all(&[$line_terminator])
            .map_err_context(|| "Could not write line terminator".to_string())
    };
}

impl Uniq {
    pub fn print_uniq<R: Read, W: Write>(
        &self,
        reader: &mut BufReader<R>,
        writer: &mut BufWriter<W>,
    ) -> UResult<()> {
        let mut first_line_printed = false;
        let mut group_count = 1;
        let line_terminator = self.get_line_terminator();
        let mut lines = reader.split(line_terminator).map(get_line_string);
        let mut line = match lines.next() {
            Some(l) => l?,
            None => return Ok(()),
        };

        // compare current `line` with consecutive lines (`next_line`) of the input
        // and if needed, print `line` based on the command line options provided
        for next_line in lines {
            let next_line = next_line?;
            if self.cmp_keys(&line, &next_line) {
                if (group_count == 1 && !self.repeats_only)
                    || (group_count > 1 && !self.uniques_only)
                {
                    self.print_line(writer, &line, group_count, first_line_printed)?;
                    first_line_printed = true;
                }
                line = next_line;
                group_count = 1;
            } else {
                if self.all_repeated {
                    self.print_line(writer, &line, group_count, first_line_printed)?;
                    first_line_printed = true;
                    line = next_line;
                }
                group_count += 1;
            }
        }
        if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
            self.print_line(writer, &line, group_count, first_line_printed)?;
            first_line_printed = true;
        }
        if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
            && first_line_printed
        {
            write_line_terminator!(writer, line_terminator)?;
        }
        Ok(())
    }

    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
        if let Some(skip_fields) = self.skip_fields {
            let mut i = 0;
            let mut char_indices = line.char_indices();
            for _ in 0..skip_fields {
                if char_indices.find(|(_, c)| !c.is_whitespace()) == None {
                    return "";
                }
                match char_indices.find(|(_, c)| c.is_whitespace()) {
                    None => return "",

                    Some((next_field_i, _)) => i = next_field_i,
                }
            }
            &line[i..]
        } else {
            line
        }
    }

    fn get_line_terminator(&self) -> u8 {
        if self.zero_terminated {
            0
        } else {
            b'\n'
        }
    }

    fn cmp_keys(&self, first: &str, second: &str) -> bool {
        self.cmp_key(first, |first_iter| {
            self.cmp_key(second, |second_iter| first_iter.ne(second_iter))
        })
    }

    fn cmp_key<F>(&self, line: &str, mut closure: F) -> bool
    where
        F: FnMut(&mut dyn Iterator<Item = char>) -> bool,
    {
        let fields_to_check = self.skip_fields(line);
        let len = fields_to_check.len();
        let slice_start = self.slice_start.unwrap_or(0);
        let slice_stop = self.slice_stop.unwrap_or(len);
        if len > 0 {
            // fast path: avoid doing any work if there is no need to skip or map to lower-case
            if !self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars());
            }

            // fast path: avoid skipping
            if self.ignore_case && slice_start == 0 && slice_stop == len {
                return closure(&mut fields_to_check.chars().flat_map(|c| c.to_uppercase()));
            }

            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
            if !self.ignore_case {
                return closure(&mut fields_to_check.chars().skip(slice_start).take(slice_stop));
            }

            closure(
                &mut fields_to_check
                    .chars()
                    .skip(slice_start)
                    .take(slice_stop)
                    .flat_map(|c| c.to_uppercase()),
            )
        } else {
            closure(&mut fields_to_check.chars())
        }
    }

    fn should_print_delimiter(&self, group_count: usize, first_line_printed: bool) -> bool {
        // if no delimiter option is selected then no other checks needed
        self.delimiters != Delimiters::None
            // print delimiter only before the first line of a group, not between lines of a group
            && group_count == 1
            // if at least one line has been output before current group then print delimiter
            && (first_line_printed
                // or if we need to prepend delimiter then print it even at the start of the output
                || self.delimiters == Delimiters::Prepend
                // the 'both' delimit mode should prepend and append delimiters
                || self.delimiters == Delimiters::Both)
    }

    fn print_line<W: Write>(
        &self,
        writer: &mut BufWriter<W>,
        line: &str,
        count: usize,
        first_line_printed: bool,
    ) -> UResult<()> {
        let line_terminator = self.get_line_terminator();

        if self.should_print_delimiter(count, first_line_printed) {
            write_line_terminator!(writer, line_terminator)?;
        }

        if self.show_counts {
            writer.write_all(format!("{:7} {}", count, line).as_bytes())
        } else {
            writer.write_all(line.as_bytes())
        }
        .map_err_context(|| "Failed to write line".to_string())?;

        write_line_terminator!(writer, line_terminator)
    }
}

fn get_line_string(io_line: io::Result<Vec<u8>>) -> UResult<String> {
    let line_bytes = io_line.map_err_context(|| "failed to split lines".to_string())?;
    String::from_utf8(line_bytes)
        .map_err(|e| USimpleError::new(1, format!("failed to convert line to utf8: {}", e)))
}

fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> UResult<Option<T>> {
    Ok(match matches.value_of(opt_name) {
        Some(arg_str) => Some(arg_str.parse().map_err(|_| {
            USimpleError::new(
                1,
                format!(
                    "Invalid argument for {}: {}",
                    opt_name,
                    arg_str.maybe_quote()
                ),
            )
        })?),
        None => None,
    })
}

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [OUTPUT]]...",
        uucore::execution_phrase()
    )
}

fn get_long_usage() -> String {
    String::from(
        "Filter adjacent matching lines from INPUT (or standard input),\n\
        writing to OUTPUT (or standard output).
        Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\
        You may want to sort the input first, or use 'sort -u' without 'uniq'.\n",
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (in_file_name, out_file_name) = match files.len() {
        0 => ("-".to_owned(), "-".to_owned()),
        1 => (files[0].clone(), "-".to_owned()),
        2 => (files[0].clone(), files[1].clone()),
        _ => {
            unreachable!() // Cannot happen as clap will fail earlier
        }
    };

    let uniq = Uniq {
        repeats_only: matches.is_present(options::REPEATED)
            || matches.is_present(options::ALL_REPEATED),
        uniques_only: matches.is_present(options::UNIQUE),
        all_repeated: matches.is_present(options::ALL_REPEATED)
            || matches.is_present(options::GROUP),
        delimiters: get_delimiter(&matches),
        show_counts: matches.is_present(options::COUNT),
        skip_fields: opt_parsed(options::SKIP_FIELDS, &matches)?,
        slice_start: opt_parsed(options::SKIP_CHARS, &matches)?,
        slice_stop: opt_parsed(options::CHECK_CHARS, &matches)?,
        ignore_case: matches.is_present(options::IGNORE_CASE),
        zero_terminated: matches.is_present(options::ZERO_TERMINATED),
    };
    uniq.print_uniq(
        &mut open_input_file(in_file_name)?,
        &mut open_output_file(out_file_name)?,
    )
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ALL_REPEATED)
                .short("D")
                .long(options::ALL_REPEATED)
                .possible_values(&[
                    Delimiters::None.as_ref(), Delimiters::Prepend.as_ref(), Delimiters::Separate.as_ref()
                ])
                .help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
                .value_name("delimit-method")
                .min_values(0)
                .max_values(1),
        )
        .arg(
            Arg::with_name(options::GROUP)
                .long(options::GROUP)
                .possible_values(&[
                    Delimiters::Separate.as_ref(), Delimiters::Prepend.as_ref(),
                    Delimiters::Append.as_ref(), Delimiters::Both.as_ref()
                ])
                .help("show all items, separating groups with an empty line. [default: separate]")
                .value_name("group-method")
                .min_values(0)
                .max_values(1)
                .conflicts_with_all(&[
                    options::REPEATED,
                    options::ALL_REPEATED,
                    options::UNIQUE,
                ]),
        )
        .arg(
            Arg::with_name(options::CHECK_CHARS)
                .short("w")
                .long(options::CHECK_CHARS)
                .help("compare no more than N characters in lines")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::COUNT)
                .short("c")
                .long(options::COUNT)
                .help("prefix lines by the number of occurrences"),
        )
        .arg(
            Arg::with_name(options::IGNORE_CASE)
                .short("i")
                .long(options::IGNORE_CASE)
                .help("ignore differences in case when comparing"),
        )
        .arg(
            Arg::with_name(options::REPEATED)
                .short("d")
                .long(options::REPEATED)
                .help("only print duplicate lines"),
        )
        .arg(
            Arg::with_name(options::SKIP_CHARS)
                .short("s")
                .long(options::SKIP_CHARS)
                .help("avoid comparing the first N characters")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::SKIP_FIELDS)
                .short("f")
                .long(options::SKIP_FIELDS)
                .help("avoid comparing the first N fields")
                .value_name("N"),
        )
        .arg(
            Arg::with_name(options::UNIQUE)
                .short("u")
                .long(options::UNIQUE)
                .help("only print unique lines"),
        )
        .arg(
            Arg::with_name(options::ZERO_TERMINATED)
                .short("z")
                .long(options::ZERO_TERMINATED)
                .help("end lines with 0 byte, not newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .max_values(2),
        )
}

fn get_delimiter(matches: &ArgMatches) -> Delimiters {
    let value = matches
        .value_of(options::ALL_REPEATED)
        .or_else(|| matches.value_of(options::GROUP));
    if let Some(delimiter_arg) = value {
        Delimiters::from_str(delimiter_arg).unwrap() // All possible values for ALL_REPEATED are &str's of Delimiters
    } else if matches.is_present(options::GROUP) {
        Delimiters::Separate
    } else {
        Delimiters::None
    }
}

fn open_input_file(in_file_name: String) -> UResult<BufReader<Box<dyn Read + 'static>>> {
    let in_file = if in_file_name == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let path = Path::new(&in_file_name[..]);
        let in_file = File::open(&path)
            .map_err_context(|| format!("Could not open {}", in_file_name.maybe_quote()))?;
        Box::new(in_file) as Box<dyn Read>
    };
    Ok(BufReader::new(in_file))
}

fn open_output_file(out_file_name: String) -> UResult<BufWriter<Box<dyn Write + 'static>>> {
    let out_file = if out_file_name == "-" {
        Box::new(stdout()) as Box<dyn Write>
    } else {
        let path = Path::new(&out_file_name[..]);
        let out_file = File::create(&path)
            .map_err_context(|| format!("Could not create {}", out_file_name.maybe_quote()))?;
        Box::new(out_file) as Box<dyn Write>
    };
    Ok(BufWriter::new(out_file))
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::{HashMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Eq + Copy + Hash> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Hash> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) -> VectorClock<S> {
        *self.map.entry(server).or_insert(0) += 1;
        self.clone()
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) -> StandardVectorClock {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &StandardVectorClock) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> StandardVectorClock {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<commit_msg>use binary tree for clock inner map so we can impelement Hash trait for vector clock naturally<commit_after>use std::hash::Hash;
use std::collections::{BTreeMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash)]
pub struct VectorClock<S: Ord + Eq + Copy> {
    map: BTreeMap<S, u64>
}

impl <S: Eq + Copy + Ord> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Ord> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Ord + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: BTreeMap::new()
        }
    }

    pub fn inc(&mut self, server: S) -> VectorClock<S> {
        *self.map.entry(server).or_insert(0) += 1;
        self.clone()
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) -> StandardVectorClock {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &StandardVectorClock) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> StandardVectorClock {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<|endoftext|>


<commit_before>use core::*;
use walker::*;

macro_rules! unwrap_text {
    ($s:ident, $e:expr) => {{
        match *$e.1 {
            Epiq::Text(ref t) => t,
            _ => {
                let from = $s.printer_printed($e.0);
                panic!("{}からtextは取り出せません", from);
            },
        }
    }}
}

macro_rules! unwrap_nmbr {
    ($s:ident, $e:expr) => {{
        match *$e.1 {
            Epiq::Uit8(n) => n,
            _ => {
                let from = $s.printer_printed($e.0);
                panic!("{}からnmbrは取り出せません", from);
            },
        }
    }}
}

macro_rules! first_nmbr {
    ($s:ident, $e:expr) => {{
        let first = $s.first($e.clone());
        unwrap_nmbr!($s, first)
    }}
}

macro_rules! second_nmbr {
    ($s:ident, $e:expr) => {{
        let first = $s.second($e.clone());
        unwrap_nmbr!($s, first)
    }}
}

impl Walker {
    pub fn eq_nmbr(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);

        let new_epiq = if n1 == n2 { Epiq::Tval } else { Epiq::Fval };

        alloc_node!(self, new_epiq)
    }

    pub fn eq_text(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let t1 = self.first(args.clone());
        let text1 = unwrap_text!(self, t1);

        let t2 = self.second(args.clone());
        let text2 = unwrap_text!(self, t2);

        let new_epiq = if text1 == text2 { Epiq::Tval } else { Epiq::Fval };
        alloc_node!(self, new_epiq)
    }

    pub fn print(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let t = self.first(args.clone());
        let text = unwrap_text!(self, t);

        print!("{}", text);

        self.get_epiq(UNIT_INDX)
    }

    pub fn decrement(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n = first_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n - 1))
    }

    pub fn plus(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n1 + n2))
    }

    pub fn minus(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n1 - n2))
    }

    pub fn le_or_eq_nmbr(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);

        let new_epiq = if n1 <= n2 { Epiq::Tval } else { Epiq::Fval };

        alloc_node!(self, new_epiq)
    }

    pub fn concat(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        self.concat_internal(args, "")
    }

    fn concat_internal(&self, args: Node<Rc<Epiq>>, accum: &str) -> Node<Rc<Epiq>> {
        let t = self.first(args.clone());
        let text = match *t.1 {
            Epiq::Text(ref tt) => tt,
            Epiq::Name(ref tt) => tt,
            _ => {
                let from = self.printer_printed(t.0);
                panic!("{}からtextは取り出せません", from);
            },
        };

        let accuming = accum.to_string() + text;
        match *self.qval(args.clone()).1 {
            Epiq::Unit => alloc_node!(self, Epiq::Text(accuming)),
            _ => self.concat_internal(self.qval(args.clone()), &accuming),
        }
    }

    pub fn dbqt(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        alloc_node!(self, Epiq::Text("\"".to_string()))
    }

    fn first(&self, piq: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        self.pval(piq.clone())
    }

    fn second(&self, piq: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let second_lpiq = self.qval(piq);
        self.pval(second_lpiq)
    }

}
<commit_msg>power up concat (use Name adn Uit8 now)<commit_after>use core::*;
use walker::*;

macro_rules! unwrap_text {
    ($s:ident, $e:expr) => {{
        match *$e.1 {
            Epiq::Text(ref t) => t,
            _ => {
                let from = $s.printer_printed($e.0);
                panic!("{}からtextは取り出せません", from);
            },
        }
    }}
}

macro_rules! unwrap_nmbr {
    ($s:ident, $e:expr) => {{
        match *$e.1 {
            Epiq::Uit8(n) => n,
            _ => {
                let from = $s.printer_printed($e.0);
                panic!("{}からnmbrは取り出せません", from);
            },
        }
    }}
}

macro_rules! first_nmbr {
    ($s:ident, $e:expr) => {{
        let first = $s.first($e.clone());
        unwrap_nmbr!($s, first)
    }}
}

macro_rules! second_nmbr {
    ($s:ident, $e:expr) => {{
        let first = $s.second($e.clone());
        unwrap_nmbr!($s, first)
    }}
}

impl Walker {
    pub fn eq_nmbr(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);

        let new_epiq = if n1 == n2 { Epiq::Tval } else { Epiq::Fval };

        alloc_node!(self, new_epiq)
    }

    pub fn eq_text(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let t1 = self.first(args.clone());
        let text1 = unwrap_text!(self, t1);

        let t2 = self.second(args.clone());
        let text2 = unwrap_text!(self, t2);

        let new_epiq = if text1 == text2 { Epiq::Tval } else { Epiq::Fval };
        alloc_node!(self, new_epiq)
    }

    pub fn eq_name(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let t1 = self.first(args.clone());
        let name1 = unwrap_name!(self, t1);

        let t2 = self.second(args.clone());
        let name2 = unwrap_name!(self, t2);

        let new_epiq = if name1 == name2 { Epiq::Tval } else { Epiq::Fval };
        alloc_node!(self, new_epiq)
    }

    pub fn print(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let t = self.first(args.clone());
        let text = unwrap_text!(self, t);

        print!("{}", text);

        self.get_epiq(UNIT_INDX)
    }

    pub fn decrement(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n = first_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n - 1))
    }

    pub fn plus(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n1 + n2))
    }

    pub fn minus(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);
        alloc_node!(self, Epiq::Uit8(n1 - n2))
    }

    pub fn le_or_eq_nmbr(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let n1 = first_nmbr!(self, args);
        let n2 = second_nmbr!(self, args);

        let new_epiq = if n1 <= n2 { Epiq::Tval } else { Epiq::Fval };

        alloc_node!(self, new_epiq)
    }

    pub fn concat(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        self.concat_internal(args, "")
    }

    fn concat_internal(&self, args: Node<Rc<Epiq>>, accum: &str) -> Node<Rc<Epiq>> {
        let t = self.first(args.clone());
        let text = match *t.1 {
            Epiq::Text(ref tt) => tt.clone(),
            Epiq::Name(ref tt) => tt.clone(),
            Epiq::Uit8(n) => n.to_string(),
            _ => {
                let from = self.printer_printed(t.0);
                panic!("{}からtextは取り出せません", from);
            },
        };

        let accuming = accum.to_string() + &text;
        match *self.qval(args.clone()).1 {
            Epiq::Unit => alloc_node!(self, Epiq::Text(accuming)),
            _ => self.concat_internal(self.qval(args.clone()), &accuming),
        }
    }

    pub fn dbqt(&self, args: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        alloc_node!(self, Epiq::Text("\"".to_string()))
    }

    fn first(&self, piq: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        self.pval(piq.clone())
    }

    fn second(&self, piq: Node<Rc<Epiq>>) -> Node<Rc<Epiq>> {
        let second_lpiq = self.qval(piq);
        self.pval(second_lpiq)
    }

}
<|endoftext|>