<commit_before>use std::marker::PhantomData;
use std::mem::size_of;
use webcore::value::{Reference, FromReference};
use webcore::try_from::TryInto;
use webapi::array_buffer::ArrayBuffer;

pub trait ArrayKind: Sized {
    fn is_typed_array( reference: &Reference ) -> bool;
    fn into_typed_array( slice: &[Self] ) -> TypedArray< Self >;
    fn from_typed_array( array: &TypedArray< Self > ) -> Vec< Self >;
}

macro_rules! arraykind {
    ($element_type:ty, $js_array_type:ident, $heap_type:ident) => {
        impl ArrayKind for $element_type {
            fn is_typed_array( reference: &Reference ) -> bool {
                instanceof!( *reference, $js_array_type )
            }

            fn into_typed_array( slice: &[Self] ) -> TypedArray< Self > {
                let slice_ptr = (slice.as_ptr() as usize / size_of::<$element_type>()) as i32;
                let raw = __js_raw_asm!(
                    concat!(
                        "return Module.STDWEB.acquire_rust_reference( ",
                        stringify!($heap_type),
                        ".slice( $0, $1 ) );"
                    ),
                    slice_ptr,
                    (slice_ptr + slice.len() as i32)
                );

                let reference = unsafe {
                    Reference::from_raw_unchecked( raw )
                };

                TypedArray::from_reference( reference ).unwrap()
            }

            fn from_typed_array( array: &TypedArray< Self > ) -> Vec< Self > {
                let length = array.len();
                let mut vector = Vec::with_capacity( length );
                let vec_ptr = (vector.as_ptr() as usize / size_of::<$element_type>()) as i32;

                js!( @(no_return)
                    var array = @{array};
                    var pointer = @{vec_ptr};
                    $heap_type.set( array, pointer );
                );

                unsafe {
                    vector.set_len( length );
                }

                vector
            }
        }

        impl From< TypedArray< $element_type > > for Vec< $element_type > {
            fn from( array: TypedArray< $element_type > ) -> Self {
                <$element_type>::from_typed_array( &array )
            }
        }

        impl< 'a > From< &'a TypedArray< $element_type > > for Vec< $element_type > {
            fn from( array: &'a TypedArray< $element_type > ) -> Self {
                <$element_type>::from_typed_array( array )
            }
        }
    }
}

arraykind!( i8, Int8Array, HEAP8 );
arraykind!( u8, Uint8Array, HEAPU8 );
arraykind!( i16, Int16Array, HEAP16 );
arraykind!( u16, Uint16Array, HEAPU16 );
arraykind!( i32, Int32Array, HEAP32 );
arraykind!( u32, Uint32Array, HEAPU32 );
arraykind!( f32, Float32Array, HEAPF32 );
arraykind!( f64, Float64Array, HEAPF64 );

/// JavaScript typed arrays are array-like objects and provide a mechanism for accessing raw binary data.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays)
pub struct TypedArray< T: ArrayKind >( Reference, PhantomData< T > );

reference_boilerplate! {
    impl< T > for TypedArray< T > where (T: ArrayKind)
}

impl< T: ArrayKind > FromReference for TypedArray< T > {
    #[inline]
    fn from_reference( reference: Reference ) -> Option< Self > {
        if T::is_typed_array( &reference ) {
            Some( TypedArray( reference, PhantomData ) )
        } else {
            None
        }
    }
}

impl< T: ArrayKind > TypedArray< T > {
    /// Returns the [TypedArray](struct.ArrayBuffer.html) referenced by this typed array.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/buffer)
    pub fn buffer( &self ) -> ArrayBuffer {
        js!( return @{self}.buffer; ).try_into().unwrap()
    }

    /// Returns the number of elements in the buffer.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/length)
    pub fn len( &self ) -> usize {
        let reference = self.as_ref();
        let length: i32 = js!( return @{reference}.length; ).try_into().unwrap();
        length as usize
    }

    /// Copies `self` into a new `Vec`.
    pub fn to_vec( &self ) -> Vec< T > {
        T::from_typed_array( self )
    }
}

impl< 'a, T: ArrayKind > From< &'a [T] > for TypedArray< T > {
    fn from( slice: &'a [T] ) -> Self {
        T::into_typed_array( slice )
    }
}

#[cfg(test)]
mod tests {
    macro_rules! arraykind_test {
        ($element_type: ident, $js_array_type: ident) => {
            mod $element_type {
                use super::super::TypedArray;
                use std;
                use webcore::try_from::TryInto;
                use webcore::value::Value;
                const ARRAY: &[$element_type] = &[
                    std::$element_type::MIN,
                    std::$element_type::MAX
                ];

                #[test]
                fn into() {
                    let typed_array: TypedArray< $element_type > = ARRAY.into();
                    assert_eq!(
                        js!( return @{&typed_array} instanceof $js_array_type; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}.length === @{ARRAY.len() as u32}; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}[0] === @{ARRAY[0]}; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}[1] === @{ARRAY[1]}; ),
                        Value::Bool( true )
                    );
                }

                #[test]
                fn from() {
                    let value = js!( return new $js_array_type( [@{ARRAY[0]}, @{ARRAY[1]}] ); );
                    let typed_array: TypedArray< $element_type > = value.try_into().unwrap();
                    let vec: Vec< $element_type > = typed_array.into();
                    assert_eq!( vec.len(), ARRAY.len() );
                    assert_eq!( vec, ARRAY);
                }
            }
        }
    }

    arraykind_test!(i8, Int8Array);
    arraykind_test!(u8, Uint8Array);
    arraykind_test!(i16, Int16Array);
    arraykind_test!(u16, Uint16Array);
    arraykind_test!(i32, Int32Array);
    arraykind_test!(u32, Uint32Array);
    arraykind_test!(f32, Float32Array);
    arraykind_test!(f64, Float64Array);
}
<commit_msg>Make `ArrayBuffer`s convertible to `TypedArray`s<commit_after>use std::marker::PhantomData;
use std::mem::size_of;
use webcore::value::{Reference, FromReference};
use webcore::try_from::TryInto;
use webapi::array_buffer::ArrayBuffer;

pub trait ArrayKind: Sized {
    fn is_typed_array( reference: &Reference ) -> bool;
    fn into_typed_array( slice: &[Self] ) -> TypedArray< Self >;
    fn into_typed_array_from_array_buffer( buffer: &ArrayBuffer ) -> TypedArray< Self >;
    fn from_typed_array( array: &TypedArray< Self > ) -> Vec< Self >;
}

macro_rules! arraykind {
    ($element_type:ty, $js_array_type:ident, $heap_type:ident) => {
        impl ArrayKind for $element_type {
            fn is_typed_array( reference: &Reference ) -> bool {
                instanceof!( *reference, $js_array_type )
            }

            fn into_typed_array( slice: &[Self] ) -> TypedArray< Self > {
                let slice_ptr = (slice.as_ptr() as usize / size_of::<$element_type>()) as i32;
                let raw = __js_raw_asm!(
                    concat!(
                        "return Module.STDWEB.acquire_rust_reference( ",
                        stringify!($heap_type),
                        ".slice( $0, $1 ) );"
                    ),
                    slice_ptr,
                    (slice_ptr + slice.len() as i32)
                );

                let reference = unsafe {
                    Reference::from_raw_unchecked( raw )
                };

                TypedArray::from_reference( reference ).unwrap()
            }

            fn into_typed_array_from_array_buffer( buffer: &ArrayBuffer ) -> TypedArray< Self > {
                let raw = __js_raw_asm!(
                    concat!(
                        "return Module.STDWEB.acquire_rust_reference( new ",
                        stringify!( $js_array_type ),
                        "( Module.STDWEB.acquire_js_reference( $0 ) )",
                        " );"
                    ),
                    buffer.as_ref().as_raw()
                );

                let reference = unsafe { Reference::from_raw_unchecked( raw ) };
                TypedArray::from_reference( reference ).unwrap()
            }

            fn from_typed_array( array: &TypedArray< Self > ) -> Vec< Self > {
                let length = array.len();
                let mut vector = Vec::with_capacity( length );
                let vec_ptr = (vector.as_ptr() as usize / size_of::<$element_type>()) as i32;

                js!( @(no_return)
                    var array = @{array};
                    var pointer = @{vec_ptr};
                    $heap_type.set( array, pointer );
                );

                unsafe {
                    vector.set_len( length );
                }

                vector
            }
        }

        impl From< TypedArray< $element_type > > for Vec< $element_type > {
            fn from( array: TypedArray< $element_type > ) -> Self {
                <$element_type>::from_typed_array( &array )
            }
        }

        impl< 'a > From< &'a TypedArray< $element_type > > for Vec< $element_type > {
            fn from( array: &'a TypedArray< $element_type > ) -> Self {
                <$element_type>::from_typed_array( array )
            }
        }
    }
}

arraykind!( i8, Int8Array, HEAP8 );
arraykind!( u8, Uint8Array, HEAPU8 );
arraykind!( i16, Int16Array, HEAP16 );
arraykind!( u16, Uint16Array, HEAPU16 );
arraykind!( i32, Int32Array, HEAP32 );
arraykind!( u32, Uint32Array, HEAPU32 );
arraykind!( f32, Float32Array, HEAPF32 );
arraykind!( f64, Float64Array, HEAPF64 );

/// JavaScript typed arrays are array-like objects and provide a mechanism for accessing raw binary data.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays)
pub struct TypedArray< T: ArrayKind >( Reference, PhantomData< T > );

reference_boilerplate! {
    impl< T > for TypedArray< T > where (T: ArrayKind)
}

impl< T: ArrayKind > FromReference for TypedArray< T > {
    #[inline]
    fn from_reference( reference: Reference ) -> Option< Self > {
        if T::is_typed_array( &reference ) {
            Some( TypedArray( reference, PhantomData ) )
        } else {
            None
        }
    }
}

impl< T: ArrayKind > TypedArray< T > {
    /// Returns the [TypedArray](struct.ArrayBuffer.html) referenced by this typed array.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/buffer)
    pub fn buffer( &self ) -> ArrayBuffer {
        js!( return @{self}.buffer; ).try_into().unwrap()
    }

    /// Returns the number of elements in the buffer.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/length)
    pub fn len( &self ) -> usize {
        let reference = self.as_ref();
        let length: i32 = js!( return @{reference}.length; ).try_into().unwrap();
        length as usize
    }

    /// Copies `self` into a new `Vec`.
    pub fn to_vec( &self ) -> Vec< T > {
        T::from_typed_array( self )
    }
}

impl< 'a, T: ArrayKind > From< &'a [T] > for TypedArray< T > {
    fn from( slice: &'a [T] ) -> Self {
        T::into_typed_array( slice )
    }
}

impl< T: ArrayKind > From< ArrayBuffer > for TypedArray< T > {
    fn from( buffer: ArrayBuffer ) -> Self {
        T::into_typed_array_from_array_buffer( &buffer )
    }
}

impl< 'a, T: ArrayKind > From< &'a ArrayBuffer > for TypedArray< T > {
    fn from( buffer: &'a ArrayBuffer ) -> Self {
        T::into_typed_array_from_array_buffer( buffer )
    }
}

#[cfg(test)]
mod tests {
    macro_rules! arraykind_test {
        ($element_type: ident, $js_array_type: ident) => {
            mod $element_type {
                use super::super::TypedArray;
                use std;
                use webcore::try_from::TryInto;
                use webcore::value::Value;
                use webapi::array_buffer::ArrayBuffer;

                const ARRAY: &[$element_type] = &[
                    std::$element_type::MIN,
                    std::$element_type::MAX
                ];

                #[test]
                fn into() {
                    let typed_array: TypedArray< $element_type > = ARRAY.into();
                    assert_eq!(
                        js!( return @{&typed_array} instanceof $js_array_type; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}.length === @{ARRAY.len() as u32}; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}[0] === @{ARRAY[0]}; ),
                        Value::Bool( true )
                    );
                    assert_eq!(
                        js!( return @{&typed_array}[1] === @{ARRAY[1]}; ),
                        Value::Bool( true )
                    );
                }

                #[test]
                fn from() {
                    let value = js!( return new $js_array_type( [@{ARRAY[0]}, @{ARRAY[1]}] ); );
                    let typed_array: TypedArray< $element_type > = value.try_into().unwrap();
                    let vec: Vec< $element_type > = typed_array.into();
                    assert_eq!( vec.len(), ARRAY.len() );
                    assert_eq!( vec, ARRAY);
                }

                #[test]
                fn from_array_buffer() {
                    let value = js!( return new $js_array_type( [@{ARRAY[0]}, @{ARRAY[1]}] ).buffer; );
                    let array_buffer: ArrayBuffer = value.try_into().unwrap();
                    let typed_array: TypedArray< $element_type > = array_buffer.into();
                    let vec: Vec< $element_type > = typed_array.into();
                    assert_eq!( vec.len(), ARRAY.len() );
                    assert_eq!( vec, ARRAY );
                }
            }
        }
    }

    arraykind_test!(i8, Int8Array);
    arraykind_test!(u8, Uint8Array);
    arraykind_test!(i16, Int16Array);
    arraykind_test!(u16, Uint16Array);
    arraykind_test!(i32, Int32Array);
    arraykind_test!(u32, Uint32Array);
    arraykind_test!(f32, Float32Array);
    arraykind_test!(f64, Float64Array);
}
<|endoftext|>


<commit_before>use {Point, Result};
use scanifc_sys;
use std::collections::VecDeque;
use std::path::Path;

// Cribbed from rivlib's examples.
const DEFAULT_WANT: u32 = 1024;
const DEFAULT_SYNC_TO_PPS: bool = true;

/// A builder for streams.
///
/// Allows configuration of the stream behavior.
#[derive(Debug)]
pub struct Builder {
    sync_to_pps: bool,
    uri: Uri,
    want: u32,
}

/// A stream of points, from an rxp file.
#[derive(Debug)]
pub struct Stream {
    buffer: VecDeque<Point>,
    handle: scanifc_sys::point3dstream_handle,
    want: u32,
}

#[derive(Debug, PartialEq)]
enum Uri {
    File(String),
    Rdtp(String),
}

impl Builder {
    /// Creates a new builder for the provided file path.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let builder = Builder::from_path("data/scan.rxp");
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Builder {
        Builder {
            sync_to_pps: DEFAULT_SYNC_TO_PPS,
            uri: Uri::from_path(path),
            want: DEFAULT_WANT,
        }
    }

    /// Creates a new builder for the provided rdtp uri.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let builder = Builder::from_rdtp("192.168.0.33/current?type=mon");
    /// ```
    pub fn from_rdtp(rdtp: &str) -> Builder {
        Builder {
            sync_to_pps: DEFAULT_SYNC_TO_PPS,
            uri: Uri::from_rdtp(rdtp),
            want: DEFAULT_WANT,
        }
    }

    /// Sets the `sync_to_pps` field.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let builder = Builder::from_path("data/scan.rxp").sync_to_pps(false);
    /// ```
    pub fn sync_to_pps(mut self, sync_to_pps: bool) -> Builder {
        self.sync_to_pps = sync_to_pps;
        self
    }

    /// Sets the number of points requested on each read.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let builder = Builder::from_path("data/scan.rxp").want(1);
    /// ```
    pub fn want(mut self, want: u32) -> Builder {
        self.want = want;
        self
    }

    /// Creates a stream from this builder.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let stream = Builder::from_path("data/scan.rxp").to_stream().unwrap();
    /// ```
    pub fn to_stream(&self) -> Result<Stream> {
        use std::ffi::CString;
        use std::ptr;

        let mut handle: scanifc_sys::point3dstream_handle = ptr::null_mut();
        let uri = CString::new(self.uri.as_str())?;
        scanifc_try!(scanifc_sys::scanifc_point3dstream_open(
            uri.as_ptr(),
            if self.sync_to_pps { 1 } else { 0 },
            &mut handle,
        ));
        Ok(Stream {
            buffer: VecDeque::new(),
            handle: handle,
            want: self.want,
        })
    }
}

impl Stream {
    /// Consumes this stream and returns a vector of points.
    ///
    /// If this stream is mid-read, the returned points will be only the remaining points in the
    /// stream.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Builder;
    /// let stream = Builder::from_path("data/scan.rxp").to_stream().unwrap();
    /// let points = stream.into_points().unwrap();
    /// ```
    pub fn into_points(self) -> Result<Vec<Point>> {
        self.collect()
    }

    fn fill_buffer(&mut self) -> Result<Option<()>> {
        if let Some(points) = self.read()? {
            self.buffer.extend(points.into_iter());
            Ok(Some(()))
        } else {
            Ok(None)
        }
    }

    fn read(&mut self) -> Result<Option<Vec<Point>>> {
        let mut pxyz32 = vec![Default::default(); self.want as usize];
        let mut pattributes = vec![Default::default(); self.want as usize];
        let mut ptime = vec![Default::default(); self.want as usize];
        let mut got = 0;
        let mut end_of_frame = 0;

        scanifc_try!(scanifc_sys::scanifc_point3dstream_read(
            self.handle,
            self.want,
            pxyz32.as_mut_ptr(),
            pattributes.as_mut_ptr(),
            ptime.as_mut_ptr(),
            &mut got,
            &mut end_of_frame,
        ));
        Ok(if got == 0 && end_of_frame == 0 {
            None
        } else {
            Some(
                pxyz32
                    .into_iter()
                    .zip(pattributes.into_iter())
                    .zip(ptime.into_iter())
                    .take(got as usize)
                    .map(|((xyz32, attributes), time)| {
                        Point::from((xyz32, attributes, time))
                    })
                    .collect(),
            )
        })
    }
}

impl Iterator for Stream {
    type Item = Result<Point>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(point) = self.buffer.pop_front() {
            Some(Ok(point))
        } else {
            match self.fill_buffer() {
                Ok(Some(())) => self.next(),
                Ok(None) => None,
                Err(err) => Some(Err(err)),
            }
        }
    }
}

impl Drop for Stream {
    fn drop(&mut self) {
        unsafe { scanifc_sys::scanifc_point3dstream_close(self.handle) };
    }
}

impl Uri {
    fn from_path<P: AsRef<Path>>(path: P) -> Uri {
        Uri::File(format!("file:{}", path.as_ref().display()))
    }

    fn from_rdtp(rdtp: &str) -> Uri {
        Uri::Rdtp(format!("rdtp://{}", rdtp))
    }

    fn as_str(&self) -> &str {
        match *self {
            Uri::File(ref s) | Uri::Rdtp(ref s) => s,
        }
    }
}

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

    #[test]
    fn uri_from_path() {
        let uri = Uri::from_path("a/path/to/a/file.rxp");
        assert_eq!(Uri::File("file:a/path/to/a/file.rxp".to_string()), uri);
    }

    #[test]
    fn uri_from_rdtp() {
        let uri = Uri::from_rdtp("192.168.0.33/current?type=mon");
        assert_eq!(
            Uri::Rdtp("rdtp://192.168.0.33/current?type=mon".to_string()),
            uri
        );
    }

    #[test]
    fn builder() {
        let stream = Builder::from_path("data/scan.rxp").to_stream().unwrap();
        assert_eq!(24390, stream.into_points().unwrap().len());
    }

    #[test]
    fn builder_sync_to_pps() {
        let stream = Builder::from_path("data/scan.rxp")
            .sync_to_pps(false)
            .to_stream()
            .unwrap();
        assert_eq!(24390, stream.into_points().unwrap().len());
    }

    #[test]
    fn builder_want() {
        let mut stream = Builder::from_path("data/scan.rxp")
            .want(1)
            .to_stream()
            .unwrap();
        assert_eq!(1, stream.read().unwrap().unwrap().len());
    }
}
<commit_msg>Change naming<commit_after>use {Point, Result};
use scanifc_sys;
use std::collections::VecDeque;
use std::path::Path;

// Cribbed from rivlib's examples.
const DEFAULT_WANT: u32 = 1024;
const DEFAULT_SYNC_TO_PPS: bool = true;

/// A stream of 3D points.
///
/// Follows the builder pattern to set the options for the stream.
#[derive(Debug)]
pub struct Stream {
    sync_to_pps: bool,
    uri: Uri,
    want: u32,
}

/// An open stream of points, used for reading.
#[derive(Debug)]
pub struct OpenStream {
    buffer: VecDeque<Point>,
    handle: scanifc_sys::point3dstream_handle,
    want: u32,
}

#[derive(Debug, PartialEq)]
enum Uri {
    File(String),
    Rdtp(String),
}

impl Stream {
    /// Creates a new builder for the provided file path.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let builder = Stream::from_path("data/scan.rxp");
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Stream {
        Stream {
            sync_to_pps: DEFAULT_SYNC_TO_PPS,
            uri: Uri::from_path(path),
            want: DEFAULT_WANT,
        }
    }

    /// Creates a new builder for the provided rdtp uri.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let builder = Stream::from_rdtp("192.168.0.33/current?type=mon");
    /// ```
    pub fn from_rdtp(rdtp: &str) -> Stream {
        Stream {
            sync_to_pps: DEFAULT_SYNC_TO_PPS,
            uri: Uri::from_rdtp(rdtp),
            want: DEFAULT_WANT,
        }
    }

    /// Sets the `sync_to_pps` field.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let builder = Stream::from_path("data/scan.rxp").sync_to_pps(false);
    /// ```
    pub fn sync_to_pps(mut self, sync_to_pps: bool) -> Stream {
        self.sync_to_pps = sync_to_pps;
        self
    }

    /// Sets the number of points requested on each read.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let builder = Stream::from_path("data/scan.rxp").want(1);
    /// ```
    pub fn want(mut self, want: u32) -> Stream {
        self.want = want;
        self
    }

    /// Creates a stream from this builder.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let stream = Stream::from_path("data/scan.rxp").open().unwrap();
    /// ```
    pub fn open(&self) -> Result<OpenStream> {
        use std::ffi::CString;
        use std::ptr;

        let mut handle: scanifc_sys::point3dstream_handle = ptr::null_mut();
        let uri = CString::new(self.uri.as_str())?;
        scanifc_try!(scanifc_sys::scanifc_point3dstream_open(
            uri.as_ptr(),
            if self.sync_to_pps { 1 } else { 0 },
            &mut handle,
        ));
        Ok(OpenStream {
            buffer: VecDeque::new(),
            handle: handle,
            want: self.want,
        })
    }
}

impl OpenStream {
    /// Consumes this stream and returns a vector of points.
    ///
    /// If this stream is mid-read, the returned points will be only the remaining points in the
    /// stream.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let stream = Stream::from_path("data/scan.rxp").open().unwrap();
    /// let points = stream.into_points().unwrap();
    /// ```
    pub fn into_points(self) -> Result<Vec<Point>> {
        self.collect()
    }

    fn fill_buffer(&mut self) -> Result<Option<()>> {
        if let Some(points) = self.read()? {
            self.buffer.extend(points.into_iter());
            Ok(Some(()))
        } else {
            Ok(None)
        }
    }

    fn read(&mut self) -> Result<Option<Vec<Point>>> {
        let mut pxyz32 = vec![Default::default(); self.want as usize];
        let mut pattributes = vec![Default::default(); self.want as usize];
        let mut ptime = vec![Default::default(); self.want as usize];
        let mut got = 0;
        let mut end_of_frame = 0;

        scanifc_try!(scanifc_sys::scanifc_point3dstream_read(
            self.handle,
            self.want,
            pxyz32.as_mut_ptr(),
            pattributes.as_mut_ptr(),
            ptime.as_mut_ptr(),
            &mut got,
            &mut end_of_frame,
        ));
        Ok(if got == 0 && end_of_frame == 0 {
            None
        } else {
            Some(
                pxyz32
                    .into_iter()
                    .zip(pattributes.into_iter())
                    .zip(ptime.into_iter())
                    .take(got as usize)
                    .map(|((xyz32, attributes), time)| {
                        Point::from((xyz32, attributes, time))
                    })
                    .collect(),
            )
        })
    }
}

impl Iterator for OpenStream {
    type Item = Result<Point>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(point) = self.buffer.pop_front() {
            Some(Ok(point))
        } else {
            match self.fill_buffer() {
                Ok(Some(())) => self.next(),
                Ok(None) => None,
                Err(err) => Some(Err(err)),
            }
        }
    }
}

impl Drop for OpenStream {
    fn drop(&mut self) {
        unsafe { scanifc_sys::scanifc_point3dstream_close(self.handle) };
    }
}

impl Uri {
    fn from_path<P: AsRef<Path>>(path: P) -> Uri {
        Uri::File(format!("file:{}", path.as_ref().display()))
    }

    fn from_rdtp(rdtp: &str) -> Uri {
        Uri::Rdtp(format!("rdtp://{}", rdtp))
    }

    fn as_str(&self) -> &str {
        match *self {
            Uri::File(ref s) | Uri::Rdtp(ref s) => s,
        }
    }
}

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

    #[test]
    fn uri_from_path() {
        let uri = Uri::from_path("a/path/to/a/file.rxp");
        assert_eq!(Uri::File("file:a/path/to/a/file.rxp".to_string()), uri);
    }

    #[test]
    fn uri_from_rdtp() {
        let uri = Uri::from_rdtp("192.168.0.33/current?type=mon");
        assert_eq!(
            Uri::Rdtp("rdtp://192.168.0.33/current?type=mon".to_string()),
            uri
        );
    }

    #[test]
    fn builder() {
        let stream = Stream::from_path("data/scan.rxp").open().unwrap();
        assert_eq!(24390, stream.into_points().unwrap().len());
    }

    #[test]
    fn builder_sync_to_pps() {
        let stream = Stream::from_path("data/scan.rxp")
            .sync_to_pps(false)
            .open()
            .unwrap();
        assert_eq!(24390, stream.into_points().unwrap().len());
    }

    #[test]
    fn builder_want() {
        let mut stream = Stream::from_path("data/scan.rxp").want(1).open().unwrap();
        assert_eq!(1, stream.read().unwrap().unwrap().len());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Linus Färnstrand <faern@faern.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets on a fake network managed
//! by in memory FIFO queues. Useful for writing tests.

use datalink::{self, EthernetDataLinkChannelIterator, EthernetDataLinkReceiver,
               EthernetDataLinkSender, NetworkInterface};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use std::io;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use std::time;
use util::MacAddr;

/// Configuration for the dummy datalink backend. Contains `std::sync::mpsc`
/// channels that are used to communicate with the fake network.
#[derive(Debug)]
pub struct Config {
    receiver: Receiver<io::Result<Box<[u8]>>>,
    inject_handle: Option<Sender<io::Result<Box<[u8]>>>>,

    sender: Sender<Box<[u8]>>,
    read_handle: Option<Receiver<Box<[u8]>>>,
}

impl Config {
    /// Creates a new `Config` with the given channels as the backing network.
    /// When using this constructor `inject_handle` and `read_handle` will return `None`.
    /// Those handles must be kept track of elsewhere.
    ///
    /// The `EthernetDataLinkChannelIterator` created by the dummy backend will read packets from
    /// `receiver`. Both network errors and data can be sent on this channel.
    /// When the `receiver` channel is closed (`Sender` is dropped)
    /// `EthernetDataLinkChannelIterator::next()` will sleep forever, simlating an idle network.
    ///
    /// The `EthernetDataLinkSender` created by the dummy backend will send all packets sent
    /// through `build_and_send()` and `send_to()` to the `sender` channel.
    pub fn new(receiver: Receiver<io::Result<Box<[u8]>>>, sender: Sender<Box<[u8]>>) -> Config {
        Config {
            receiver: receiver,
            inject_handle: None,
            sender: sender,
            read_handle: None,
        }
    }

    /// Get the `Sender` handle that can inject packets in the fake network.
    /// Only usable with `Config`s generated from `default()`
    pub fn inject_handle(&mut self) -> Option<Sender<io::Result<Box<[u8]>>>> {
        self.inject_handle.take()
    }

    /// Get the `Receiver` handle where packets sent to the fake network can be read.
    /// Only usable with `Config`s generated from `default()`
    pub fn read_handle(&mut self) -> Option<Receiver<Box<[u8]>>> {
        self.read_handle.take()
    }
}

impl<'a> From<&'a datalink::Config> for Config {
    /// Will not use the `datalink::Config`. This will simply call `dummy::Config::default()`.
    fn from(_config: &datalink::Config) -> Config {
        Config::default()
    }
}

impl Default for Config {
    /// Creates a default config with one input and one output channel. The handles used to inject
    /// to and read form the network can be fetched with `inject_handle()` and `read_handle()`
    fn default() -> Config {
        let (in_tx, in_rx) = mpsc::channel();
        let (out_tx, out_rx) = mpsc::channel();
        Config {
            receiver: in_rx,
            inject_handle: Some(in_tx),
            sender: out_tx,
            read_handle: Some(out_rx),
        }
    }
}

/// Create a data link channel backed by FIFO queues. Useful for debugging and testing.
/// See `Config` for how to inject and read packets on this fake network.
pub fn channel(_: &NetworkInterface, config: Config) -> io::Result<datalink::Channel> {
    let sender = Box::new(MockEthernetDataLinkSender { sender: config.sender });
    let receiver = Box::new(MockEthernetDataLinkReceiver { receiver: Some(config.receiver) });

    Ok(datalink::Channel::Ethernet(sender, receiver))
}

struct MockEthernetDataLinkSender {
    sender: Sender<Box<[u8]>>,
}

impl EthernetDataLinkSender for MockEthernetDataLinkSender {
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut buffer = vec![0; packet_size];
            {
                let pkg = match MutableEthernetPacket::new(&mut buffer[..]) {
                    Some(pkg) => pkg,
                    None => return None,
                };
                func(pkg);
            }
            // Send the data to the queue. Don't care if it's closed
            self.sender.send(buffer.into_boxed_slice()).unwrap_or(());
        }
        Some(Ok(()))
    }

    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        let buffer = packet.packet().to_vec();
        self.sender.send(buffer.into_boxed_slice()).unwrap_or(());
        Some(Ok(()))
    }
}

struct MockEthernetDataLinkReceiver {
    receiver: Option<Receiver<io::Result<Box<[u8]>>>>,
}

impl EthernetDataLinkReceiver for MockEthernetDataLinkReceiver {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(MockEthernetDataLinkChannelIterator {
            receiver: self.receiver.take().expect("Only one receiver allowed"),
            used_packets: vec![],
        })
    }
}

struct MockEthernetDataLinkChannelIterator {
    receiver: Receiver<io::Result<Box<[u8]>>>,
    used_packets: Vec<Box<[u8]>>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for MockEthernetDataLinkChannelIterator {
    fn next(&mut self) -> io::Result<EthernetPacket> {
        match self.receiver.recv() {
            Ok(result) => {
                // A network event happened. Might be a packet or a simulated error
                match result {
                    Ok(buffer) => {
                        self.used_packets.push(buffer);
                        let buffer_ref = &*self.used_packets[self.used_packets.len() - 1];
                        let packet = EthernetPacket::new(buffer_ref).unwrap();
                        Ok(packet)
                    }
                    Err(e) => Err(e),
                }
            }
            Err(_) => {
                // The channel supplying fake packets is broken. The user lost/destroyed their
                // inject_handle. This means there will never be any more packets sent to this
                // dummy network. To simulate an idle network we block and sleep forever here.
                loop {
                    thread::sleep(time::Duration::new(10, 0));
                }
            }
        }
    }
}

/// Get three fake interfaces generated with `dummy_interface(0..3)`.
pub fn interfaces() -> Vec<NetworkInterface> {
    (0..3).map(|i| dummy_interface(i)).collect()
}

/// Generates a fake `NetworkInterface`.
/// The name of the interface will be `ethX` where X is the integer `i`.
/// The index will be `i`.
/// The MAC will be `01:02:03:04:05:i`.
pub fn dummy_interface(i: u8) -> NetworkInterface {
    NetworkInterface {
        name: format!("eth{}", i),
        index: i as u32,
        mac: Some(MacAddr::new(1, 2, 3, 4, 5, i)),
        ips: Vec::new(),
        flags: 0,
    }
}

#[cfg(test)]
mod tests {
    use datalink::{EthernetDataLinkReceiver, EthernetDataLinkSender};
    use datalink::Channel::Ethernet;

    use packet::{MutablePacket, Packet};
    use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
    use std::io;
    use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
    use std::thread::{sleep, spawn};
    use std::time::Duration;

    #[test]
    fn send_too_small_packet_size() {
        let (_, _, mut tx, _) = create_net();
        // Check that it fails to send with too small packet sizes
        assert!(tx.build_and_send(1, 0, &mut |_| {}).is_none());
    }

    #[test]
    fn send_nothing() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending zero packets yields zero packets
        let mut builder = |_: MutableEthernetPacket| {
            panic!("Should not be called");
        };
        tx.build_and_send(0, 20, &mut builder).unwrap().unwrap();
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_one_packet() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending one packet yields one packet
        let mut builder = |mut pkg: MutableEthernetPacket| {
            assert_eq!(pkg.packet().len(), 20);
            pkg.packet_mut()[0] = 9;
            pkg.packet_mut()[19] = 201;
        };
        tx.build_and_send(1, 20, &mut builder).unwrap().unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[0], 9);
        assert_eq!(pkg[19], 201);
    }

    #[test]
    fn send_multiple_packets() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending multiple packets does the correct thing
        let mut closure_counter = 0;
        let mut builder = |mut pkg: MutableEthernetPacket| {
            pkg.packet_mut()[0] = closure_counter;
            closure_counter += 1;
        };
        tx.build_and_send(3, 20, &mut builder).unwrap().unwrap();
        for i in 0..3 {
            let pkg = read_handle.try_recv().expect("Expected a packet");
            assert_eq!(pkg[0], i);
        }
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_to() {
        let (_, read_handle, mut tx, _) = create_net();
        let mut buffer = vec![0; 20];
        buffer[1] = 34;
        buffer[18] = 76;
        let pkg = EthernetPacket::new(&buffer[..]).unwrap();

        tx.send_to(&pkg, None).unwrap().unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[1], 34);
        assert_eq!(pkg[18], 76);
    }

    #[test]
    fn read_nothing() {
        let (_, _, _, mut rx) = create_net();
        let (control_tx, control_rx) = mpsc::channel();
        spawn(move || {
            let mut rx_iter = rx.iter();
            rx_iter.next().expect("Should not happen 1");
            control_tx.send(()).expect("Should not happen 2");
        });
        sleep(Duration::new(0, 1_000_000));
        match control_rx.try_recv() {
            Ok(_) => panic!("Nothing should have arrived"),
            Err(TryRecvError::Disconnected) => panic!("Thread should not have quit"),
            Err(TryRecvError::Empty) => (),
        }
    }

    #[test]
    fn read_one_pkg() {
        let (inject_handle, _, _, mut rx) = create_net();

        let buffer = vec![0; 20];
        inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();

        let mut rx_iter = rx.iter();
        let pkg = rx_iter.next().expect("Expected a packet");
        assert_eq!(pkg.packet().len(), 20);
    }

    #[test]
    fn read_multiple_pkgs() {
        let (inject_handle, _, _, mut rx) = create_net();

        for i in 0..3 {
            let buffer = vec![i; 20];
            inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();
        }

        let mut rx_iter = rx.iter();
        {
            let pkg1 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg1.packet()[0], 0);
        }
        {
            let pkg2 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg2.packet()[0], 1);
        }
        {
            let pkg3 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg3.packet()[0], 2);
        }
    }

    fn create_net()
        -> (Sender<io::Result<Box<[u8]>>>,
            Receiver<Box<[u8]>>,
            Box<EthernetDataLinkSender>,
            Box<EthernetDataLinkReceiver>) {
        let interface = super::dummy_interface(56);
        let mut config = super::Config::default();
        let inject_handle = config.inject_handle().unwrap();
        let read_handle = config.read_handle().unwrap();

        let channel = super::channel(&interface, config);
        let (tx, rx) = match channel {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            _ => panic!("Not a valid channel returned"),
        };
        (inject_handle, read_handle, tx, rx)
    }
}
<commit_msg>Adapt dummy backend to &[u8] datalink<commit_after>// Copyright (c) 2016 Linus Färnstrand <faern@faern.net>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for sending and receiving data link layer packets on a fake network managed
//! by in memory FIFO queues. Useful for writing tests.

use datalink::{self, EthernetDataLinkChannelIterator, EthernetDataLinkReceiver,
               EthernetDataLinkSender, NetworkInterface};
use std::io;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use std::time;
use util::MacAddr;

/// Configuration for the dummy datalink backend. Contains `std::sync::mpsc`
/// channels that are used to communicate with the fake network.
#[derive(Debug)]
pub struct Config {
    receiver: Receiver<io::Result<Box<[u8]>>>,
    inject_handle: Option<Sender<io::Result<Box<[u8]>>>>,

    sender: Sender<Box<[u8]>>,
    read_handle: Option<Receiver<Box<[u8]>>>,
}

impl Config {
    /// Creates a new `Config` with the given channels as the backing network.
    /// When using this constructor `inject_handle` and `read_handle` will return `None`.
    /// Those handles must be kept track of elsewhere.
    ///
    /// The `EthernetDataLinkChannelIterator` created by the dummy backend will read packets from
    /// `receiver`. Both network errors and data can be sent on this channel.
    /// When the `receiver` channel is closed (`Sender` is dropped)
    /// `EthernetDataLinkChannelIterator::next()` will sleep forever, simlating an idle network.
    ///
    /// The `EthernetDataLinkSender` created by the dummy backend will send all packets sent
    /// through `build_and_send()` and `send_to()` to the `sender` channel.
    pub fn new(receiver: Receiver<io::Result<Box<[u8]>>>, sender: Sender<Box<[u8]>>) -> Config {
        Config {
            receiver: receiver,
            inject_handle: None,
            sender: sender,
            read_handle: None,
        }
    }

    /// Get the `Sender` handle that can inject packets in the fake network.
    /// Only usable with `Config`s generated from `default()`
    pub fn inject_handle(&mut self) -> Option<Sender<io::Result<Box<[u8]>>>> {
        self.inject_handle.take()
    }

    /// Get the `Receiver` handle where packets sent to the fake network can be read.
    /// Only usable with `Config`s generated from `default()`
    pub fn read_handle(&mut self) -> Option<Receiver<Box<[u8]>>> {
        self.read_handle.take()
    }
}

impl<'a> From<&'a datalink::Config> for Config {
    /// Will not use the `datalink::Config`. This will simply call `dummy::Config::default()`.
    fn from(_config: &datalink::Config) -> Config {
        Config::default()
    }
}

impl Default for Config {
    /// Creates a default config with one input and one output channel. The handles used to inject
    /// to and read form the network can be fetched with `inject_handle()` and `read_handle()`
    fn default() -> Config {
        let (in_tx, in_rx) = mpsc::channel();
        let (out_tx, out_rx) = mpsc::channel();
        Config {
            receiver: in_rx,
            inject_handle: Some(in_tx),
            sender: out_tx,
            read_handle: Some(out_rx),
        }
    }
}

/// Create a data link channel backed by FIFO queues. Useful for debugging and testing.
/// See `Config` for how to inject and read packets on this fake network.
pub fn channel(_: &NetworkInterface, config: Config) -> io::Result<datalink::Channel> {
    let sender = Box::new(MockEthernetDataLinkSender { sender: config.sender });
    let receiver = Box::new(MockEthernetDataLinkReceiver { receiver: Some(config.receiver) });

    Ok(datalink::Channel::Ethernet(sender, receiver))
}

struct MockEthernetDataLinkSender {
    sender: Sender<Box<[u8]>>,
}

impl EthernetDataLinkSender for MockEthernetDataLinkSender {
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(&mut [u8]))
        -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut buffer = vec![0; packet_size];
            func(&mut buffer);
            // Send the data to the queue. Don't care if it's closed
            self.sender.send(buffer.into_boxed_slice()).unwrap_or(());
        }
        Some(Ok(()))
    }

    fn send_to(&mut self,
               packet: &[u8],
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        let buffer = packet.to_vec();
        self.sender.send(buffer.into_boxed_slice()).unwrap_or(());
        Some(Ok(()))
    }
}

struct MockEthernetDataLinkReceiver {
    receiver: Option<Receiver<io::Result<Box<[u8]>>>>,
}

impl EthernetDataLinkReceiver for MockEthernetDataLinkReceiver {
    fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
        Box::new(MockEthernetDataLinkChannelIterator {
            receiver: self.receiver.take().expect("Only one receiver allowed"),
            used_packets: vec![],
        })
    }
}

struct MockEthernetDataLinkChannelIterator {
    receiver: Receiver<io::Result<Box<[u8]>>>,
    used_packets: Vec<Box<[u8]>>,
}

impl<'a> EthernetDataLinkChannelIterator<'a> for MockEthernetDataLinkChannelIterator {
    fn next(&mut self) -> io::Result<&[u8]> {
        match self.receiver.recv() {
            Ok(result) => {
                // A network event happened. Might be a packet or a simulated error
                match result {
                    Ok(buffer) => {
                        self.used_packets.push(buffer);
                        let buffer_ref = &*self.used_packets[self.used_packets.len() - 1];
                        Ok(buffer_ref)
                    }
                    Err(e) => Err(e),
                }
            }
            Err(_) => {
                // The channel supplying fake packets is broken. The user lost/destroyed their
                // inject_handle. This means there will never be any more packets sent to this
                // dummy network. To simulate an idle network we block and sleep forever here.
                loop {
                    thread::sleep(time::Duration::new(10, 0));
                }
            }
        }
    }
}

/// Get three fake interfaces generated with `dummy_interface(0..3)`.
pub fn interfaces() -> Vec<NetworkInterface> {
    (0..3).map(|i| dummy_interface(i)).collect()
}

/// Generates a fake `NetworkInterface`.
/// The name of the interface will be `ethX` where X is the integer `i`.
/// The index will be `i`.
/// The MAC will be `01:02:03:04:05:i`.
pub fn dummy_interface(i: u8) -> NetworkInterface {
    NetworkInterface {
        name: format!("eth{}", i),
        index: i as u32,
        mac: Some(MacAddr::new(1, 2, 3, 4, 5, i)),
        ips: Vec::new(),
        flags: 0,
    }
}

#[cfg(test)]
mod tests {
    use datalink::{EthernetDataLinkReceiver, EthernetDataLinkSender};
    use datalink::Channel::Ethernet;

    use std::io;
    use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
    use std::thread::{sleep, spawn};
    use std::time::Duration;

    #[test]
    fn send_nothing() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending zero packets yields zero packets
        let mut builder = |_: &mut [u8]| {
            panic!("Should not be called");
        };
        tx.build_and_send(0, 20, &mut builder).unwrap().unwrap();
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_one_packet() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending one packet yields one packet
        let mut builder = |pkg: &mut [u8]| {
            assert_eq!(pkg.len(), 20);
            pkg[0] = 9;
            pkg[19] = 201;
        };
        tx.build_and_send(1, 20, &mut builder).unwrap().unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[0], 9);
        assert_eq!(pkg[19], 201);
    }

    #[test]
    fn send_multiple_packets() {
        let (_, read_handle, mut tx, _) = create_net();
        // Check that sending multiple packets does the correct thing
        let mut closure_counter = 0;
        let mut builder = |pkg: &mut [u8]| {
            pkg[0] = closure_counter;
            closure_counter += 1;
        };
        tx.build_and_send(3, 20, &mut builder).unwrap().unwrap();
        for i in 0..3 {
            let pkg = read_handle.try_recv().expect("Expected a packet");
            assert_eq!(pkg[0], i);
        }
        assert!(read_handle.try_recv().is_err());
    }

    #[test]
    fn send_to() {
        let (_, read_handle, mut tx, _) = create_net();
        let mut buffer = vec![0; 20];
        buffer[1] = 34;
        buffer[18] = 76;

        tx.send_to(&buffer, None).unwrap().unwrap();
        let pkg = read_handle.try_recv().expect("Expected one packet to be sent");
        assert!(read_handle.try_recv().is_err());
        assert_eq!(pkg.len(), 20);
        assert_eq!(pkg[1], 34);
        assert_eq!(pkg[18], 76);
    }

    #[test]
    fn read_nothing() {
        let (_, _, _, mut rx) = create_net();
        let (control_tx, control_rx) = mpsc::channel();
        spawn(move || {
            let mut rx_iter = rx.iter();
            rx_iter.next().expect("Should not happen 1");
            control_tx.send(()).expect("Should not happen 2");
        });
        sleep(Duration::new(0, 1_000_000));
        match control_rx.try_recv() {
            Ok(_) => panic!("Nothing should have arrived"),
            Err(TryRecvError::Disconnected) => panic!("Thread should not have quit"),
            Err(TryRecvError::Empty) => (),
        }
    }

    #[test]
    fn read_one_pkg() {
        let (inject_handle, _, _, mut rx) = create_net();

        let buffer = vec![0; 20];
        inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();

        let mut rx_iter = rx.iter();
        let pkg = rx_iter.next().expect("Expected a packet");
        assert_eq!(pkg.len(), 20);
    }

    #[test]
    fn read_multiple_pkgs() {
        let (inject_handle, _, _, mut rx) = create_net();

        for i in 0..3 {
            let buffer = vec![i; 20];
            inject_handle.send(Ok(buffer.into_boxed_slice())).unwrap();
        }

        let mut rx_iter = rx.iter();
        {
            let pkg1 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg1[0], 0);
        }
        {
            let pkg2 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg2[0], 1);
        }
        {
            let pkg3 = rx_iter.next().expect("Expected a packet");
            assert_eq!(pkg3[0], 2);
        }
    }

    fn create_net()
        -> (Sender<io::Result<Box<[u8]>>>,
            Receiver<Box<[u8]>>,
            Box<EthernetDataLinkSender>,
            Box<EthernetDataLinkReceiver>) {
        let interface = super::dummy_interface(56);
        let mut config = super::Config::default();
        let inject_handle = config.inject_handle().unwrap();
        let read_handle = config.read_handle().unwrap();

        let channel = super::channel(&interface, config);
        let (tx, rx) = match channel {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            _ => panic!("Not a valid channel returned"),
        };
        (inject_handle, read_handle, tx, rx)
    }
}
<|endoftext|>


<commit_before>#[crate_type = "bin"];
#[feature(globs)];
#[feature(managed_boxes)];

extern mod protobuf;
extern mod extra;

use std::io::fs::*;
use std::io::Reader;
use std::io::Writer;
use std::path::Path;
use std::os;
use extra::getopts;

use protobuf::*;
use protobuf::descriptor::*;
use protobuf::codegen::*;

fn write_file(bin: &str, gen_options: &GenOptions) {
    let is: @Reader = @File::open(&Path::new(bin)).unwrap() as @Reader;
    let fds = parse_from_reader::<FileDescriptorSet>(is);

    let results = gen(fds.file, gen_options);

    for r in results.iter() {
        let file_writer = @mut File::create(&Path::new(r.name.to_owned())).unwrap()
                as @mut Writer;
        file_writer.write(r.content);
    }
}

fn main() {
    let args = os::args();
    let opts: ~[getopts::Opt] = ~[
    ];
    let matches = getopts::getopts(args.tail(), opts).unwrap();
    let pb_bin = match matches.free {
        [ref pb_bin] => pb_bin.to_owned(),
        _ => fail!("must have exactly one argument")
    };
    let gen_options = GenOptions {
        dummy: false,
    };
    write_file(pb_bin, &gen_options);
}
<commit_msg>Path::new renamed to Path::init<commit_after>#[crate_type = "bin"];
#[feature(globs)];
#[feature(managed_boxes)];

extern mod protobuf;
extern mod extra;

use std::io::fs::*;
use std::io::Reader;
use std::io::Writer;
use std::path::Path;
use std::os;
use extra::getopts;

use protobuf::*;
use protobuf::descriptor::*;
use protobuf::codegen::*;

fn write_file(bin: &str, gen_options: &GenOptions) {
    let is: @Reader = @File::open(&Path::init(bin)).unwrap() as @Reader;
    let fds = parse_from_reader::<FileDescriptorSet>(is);

    let results = gen(fds.file, gen_options);

    for r in results.iter() {
        let file_writer = @mut File::create(&Path::init(r.name.to_owned())).unwrap()
                as @mut Writer;
        file_writer.write(r.content);
    }
}

fn main() {
    let args = os::args();
    let opts: ~[getopts::Opt] = ~[
    ];
    let matches = getopts::getopts(args.tail(), opts).unwrap();
    let pb_bin = match matches.free {
        [ref pb_bin] => pb_bin.to_owned(),
        _ => fail!("must have exactly one argument")
    };
    let gen_options = GenOptions {
        dummy: false,
    };
    write_file(pb_bin, &gen_options);
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::coprocessor::dag::expr::EvalContext;
use crate::util;
use regex::Error as RegexpError;
use std::error::Error as StdError;
use std::io;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{error, str};
use tipb::expression::ScalarFuncSig;
use tipb::select;

pub const ERR_UNKNOWN: i32 = 1105;
pub const ERR_REGEXP: i32 = 1139;
pub const ZLIB_LENGTH_CORRUPTED: i32 = 1258;
pub const ZLIB_DATA_CORRUPTED: i32 = 1259;
pub const WARN_DATA_TRUNCATED: i32 = 1265;
pub const ERR_TRUNCATE_WRONG_VALUE: i32 = 1292;
pub const ERR_UNKNOWN_TIMEZONE: i32 = 1298;
pub const ERR_DIVISION_BY_ZERO: i32 = 1365;
pub const ERR_DATA_TOO_LONG: i32 = 1406;
pub const ERR_DATA_OUT_OF_RANGE: i32 = 1690;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidDataType(reason: String) {
            description("invalid data type")
            display("{}", reason)
        }
        Encoding(err: Utf8Error) {
            from()
            cause(err)
            description("encoding failed")
        }
        ColumnOffset(offset: usize) {
            description("column offset not found")
            display("illegal column offset: {}", offset)
        }
        UnknownSignature(sig: ScalarFuncSig) {
            description("Unknown signature")
            display("Unknown signature: {:?}", sig)
        }
        Eval(s: String,code:i32) {
            description("evaluation failed")
            display("{}", s)
        }
        Other(err: Box<dyn error::Error + Send + Sync>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("unknown error {:?}", err)
        }
    }
}

impl Error {
    pub fn handle_invalid_time_error(ctx: &mut EvalContext, err: Error) -> Result<()> {
        if err.code() == ERR_TRUNCATE_WRONG_VALUE {
            return Err(err);
        }
        if ctx.cfg.strict_sql_mode && (ctx.cfg.in_insert_stmt || ctx.cfg.in_update_or_delete_stmt) {
            return Err(err);
        }
        ctx.warnings.append_warning(err);
        Ok(())
    }

    pub fn overflow(data: &str, expr: &str) -> Error {
        let msg = format!("{} value is out of range in {:?}", data, expr);
        Error::Eval(msg, ERR_DATA_OUT_OF_RANGE)
    }

    pub fn truncated_wrong_val(data_type: &str, val: &str) -> Error {
        let msg = format!("Truncated incorrect {} value: '{}'", data_type, val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn truncated() -> Error {
        Error::Eval("Data Truncated".into(), WARN_DATA_TRUNCATED)
    }

    pub fn cast_neg_int_as_unsigned() -> Error {
        let msg = "Cast to unsigned converted negative integer to it's positive complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn cast_as_signed_overflow() -> Error {
        let msg =
            "Cast to signed converted positive out-of-range integer to it's negative complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn invalid_timezone(given_time_zone: &str) -> Error {
        let msg = format!("unknown or incorrect time zone: {}", given_time_zone);
        Error::Eval(msg, ERR_UNKNOWN_TIMEZONE)
    }

    pub fn division_by_zero() -> Error {
        let msg = "Division by 0";
        Error::Eval(msg.into(), ERR_DIVISION_BY_ZERO)
    }

    pub fn data_too_long(msg: String) -> Error {
        if msg.is_empty() {
            Error::Eval("Data Too Long".into(), ERR_DATA_TOO_LONG)
        } else {
            Error::Eval(msg, ERR_DATA_TOO_LONG)
        }
    }

    pub fn code(&self) -> i32 {
        match *self {
            Error::Eval(_, code) => code,
            _ => ERR_UNKNOWN,
        }
    }

    pub fn is_overflow(&self) -> bool {
        self.code() == ERR_DATA_OUT_OF_RANGE
    }

    pub fn unexpected_eof() -> Error {
        util::codec::Error::unexpected_eof().into()
    }

    pub fn invalid_time_format(val: &str) -> Error {
        let msg = format!("invalid time format: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn incorrect_datetime_value(val: &str) -> Error {
        let msg = format!("Incorrect datetime value: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn zlib_length_corrupted() -> Error {
        let msg = "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)";
        Error::Eval(msg.into(), ZLIB_LENGTH_CORRUPTED)
    }

    pub fn zlib_data_corrupted() -> Error {
        Error::Eval("ZLIB: Input data corrupted".into(), ZLIB_DATA_CORRUPTED)
    }
}

impl Into<select::Error> for Error {
    fn into(self) -> select::Error {
        let mut err = select::Error::new();
        err.set_code(self.code());
        err.set_msg(format!("{:?}", self));
        err
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Encoding(err.utf8_error())
    }
}

impl From<util::codec::Error> for Error {
    fn from(err: util::codec::Error) -> Error {
        box_err!("codec:{:?}", err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        let uerr: util::codec::Error = err.into();
        uerr.into()
    }
}

impl From<RegexpError> for Error {
    fn from(err: RegexpError) -> Error {
        let msg = format!("Got error '{:.64}' from regexp", err.description());
        Error::Eval(msg, ERR_REGEXP)
    }
}

pub type Result<T> = std::result::Result<T, Error>;
<commit_msg>Minor fixup - use single quote in error message (#4413)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::coprocessor::dag::expr::EvalContext;
use crate::util;
use regex::Error as RegexpError;
use std::error::Error as StdError;
use std::io;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::{error, str};
use tipb::expression::ScalarFuncSig;
use tipb::select;

pub const ERR_UNKNOWN: i32 = 1105;
pub const ERR_REGEXP: i32 = 1139;
pub const ZLIB_LENGTH_CORRUPTED: i32 = 1258;
pub const ZLIB_DATA_CORRUPTED: i32 = 1259;
pub const WARN_DATA_TRUNCATED: i32 = 1265;
pub const ERR_TRUNCATE_WRONG_VALUE: i32 = 1292;
pub const ERR_UNKNOWN_TIMEZONE: i32 = 1298;
pub const ERR_DIVISION_BY_ZERO: i32 = 1365;
pub const ERR_DATA_TOO_LONG: i32 = 1406;
pub const ERR_DATA_OUT_OF_RANGE: i32 = 1690;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        InvalidDataType(reason: String) {
            description("invalid data type")
            display("{}", reason)
        }
        Encoding(err: Utf8Error) {
            from()
            cause(err)
            description("encoding failed")
        }
        ColumnOffset(offset: usize) {
            description("column offset not found")
            display("illegal column offset: {}", offset)
        }
        UnknownSignature(sig: ScalarFuncSig) {
            description("Unknown signature")
            display("Unknown signature: {:?}", sig)
        }
        Eval(s: String,code:i32) {
            description("evaluation failed")
            display("{}", s)
        }
        Other(err: Box<dyn error::Error + Send + Sync>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("unknown error {:?}", err)
        }
    }
}

impl Error {
    pub fn handle_invalid_time_error(ctx: &mut EvalContext, err: Error) -> Result<()> {
        if err.code() == ERR_TRUNCATE_WRONG_VALUE {
            return Err(err);
        }
        if ctx.cfg.strict_sql_mode && (ctx.cfg.in_insert_stmt || ctx.cfg.in_update_or_delete_stmt) {
            return Err(err);
        }
        ctx.warnings.append_warning(err);
        Ok(())
    }

    pub fn overflow(data: &str, expr: &str) -> Error {
        let msg = format!("{} value is out of range in '{}'", data, expr);
        Error::Eval(msg, ERR_DATA_OUT_OF_RANGE)
    }

    pub fn truncated_wrong_val(data_type: &str, val: &str) -> Error {
        let msg = format!("Truncated incorrect {} value: '{}'", data_type, val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn truncated() -> Error {
        Error::Eval("Data Truncated".into(), WARN_DATA_TRUNCATED)
    }

    pub fn cast_neg_int_as_unsigned() -> Error {
        let msg = "Cast to unsigned converted negative integer to it's positive complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn cast_as_signed_overflow() -> Error {
        let msg =
            "Cast to signed converted positive out-of-range integer to it's negative complement";
        Error::Eval(msg.into(), ERR_UNKNOWN)
    }

    pub fn invalid_timezone(given_time_zone: &str) -> Error {
        let msg = format!("unknown or incorrect time zone: {}", given_time_zone);
        Error::Eval(msg, ERR_UNKNOWN_TIMEZONE)
    }

    pub fn division_by_zero() -> Error {
        let msg = "Division by 0";
        Error::Eval(msg.into(), ERR_DIVISION_BY_ZERO)
    }

    pub fn data_too_long(msg: String) -> Error {
        if msg.is_empty() {
            Error::Eval("Data Too Long".into(), ERR_DATA_TOO_LONG)
        } else {
            Error::Eval(msg, ERR_DATA_TOO_LONG)
        }
    }

    pub fn code(&self) -> i32 {
        match *self {
            Error::Eval(_, code) => code,
            _ => ERR_UNKNOWN,
        }
    }

    pub fn is_overflow(&self) -> bool {
        self.code() == ERR_DATA_OUT_OF_RANGE
    }

    pub fn unexpected_eof() -> Error {
        util::codec::Error::unexpected_eof().into()
    }

    pub fn invalid_time_format(val: &str) -> Error {
        let msg = format!("invalid time format: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn incorrect_datetime_value(val: &str) -> Error {
        let msg = format!("Incorrect datetime value: '{}'", val);
        Error::Eval(msg, ERR_TRUNCATE_WRONG_VALUE)
    }

    pub fn zlib_length_corrupted() -> Error {
        let msg = "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)";
        Error::Eval(msg.into(), ZLIB_LENGTH_CORRUPTED)
    }

    pub fn zlib_data_corrupted() -> Error {
        Error::Eval("ZLIB: Input data corrupted".into(), ZLIB_DATA_CORRUPTED)
    }
}

impl Into<select::Error> for Error {
    fn into(self) -> select::Error {
        let mut err = select::Error::new();
        err.set_code(self.code());
        err.set_msg(format!("{:?}", self));
        err
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::Encoding(err.utf8_error())
    }
}

impl From<util::codec::Error> for Error {
    fn from(err: util::codec::Error) -> Error {
        box_err!("codec:{:?}", err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        let uerr: util::codec::Error = err.into();
        uerr.into()
    }
}

impl From<RegexpError> for Error {
    fn from(err: RegexpError) -> Error {
        let msg = format!("Got error '{:.64}' from regexp", err.description());
        Error::Eval(msg, ERR_REGEXP)
    }
}

pub type Result<T> = std::result::Result<T, Error>;
<|endoftext|>


<commit_before>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::rc::Rc;

use common::err::{Error, Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	MiniPage,
  FMiniPage,
	Page,
	OwnedPageBuilder,
	PageId
};
use common::session::Session;
use common::types::*;
use jit::{JitCompiler};
use jit::builder::Builder;
use jit::types::LLVMTy;
use jit::value::{Function, Predicate, Value, ValueRef, ToValue};
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;
use super::NamedSchema;

#[repr(C)]
pub struct MiniPage2 {
  ptr: *const u8,
  size: usize
}

pub type MapFunc = extern "C" fn(&mut MiniPage2) -> i32;

macro_rules! unary_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, expr: &Expr)
    {
      let val = self.visit(expr);
      let builder = &self.builder;

      self.stack.push(builder.$func(&val));
    }
  );
);

macro_rules! bin_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, lhs: &Expr, rhs: &Expr)
    {
      let lhs_val = self.visit(lhs);
      let rhs_val = self.visit(rhs);

      let builder = &self.builder;

      self.stack.push(builder.$func(&lhs_val, &rhs_val));
    }
  );
);

pub struct MapCompiler<'a>
{
  jit  : &'a JitCompiler,
  types: &'a Vec<Ty>,
	names: &'a Vec<&'a str>,
	stack: Vec<Value>,
  error: Option<Error>,
  func: Function,
  builder: Builder
}

impl<'a> MapCompiler<'a> {
  fn new(jit: &'a JitCompiler,
         fn_registry: &FuncRegistry,
		     session: &Session,
		     schema : &'a NamedSchema,) -> MapCompiler<'a> {
    let builder = jit.new_builder();
    let func = MapCompiler::generate_fn_prototype(jit, &builder);

		MapCompiler {
      jit   : jit,
			types : &schema.types,
			names : &schema.names,
			stack : Vec::new(),
			error : None,
      func: func,
      builder: builder
		}
	}

  pub fn compile(
            jit: &'a JitCompiler,
						fn_registry: &FuncRegistry,
		        session    : &'a Session,
					  schema     : &'a NamedSchema,
					  expr       : &Expr) -> Result<Rc<MapFunc>>
	{
    let mut map = MapCompiler::new(jit, fn_registry, session, schema);
    map.accept(expr);
    MapCompiler::generate_scalar_func(&mut map, jit);
    map.ret_func(jit)
  }

  fn generate_fn_prototype(jit: &JitCompiler, bld: &Builder) -> Function {
    let minipage_ty = jit.get_ty("struct.MiniPage").unwrap();
    let minipage_ptr_ty = jit.get_pointer_ty(&minipage_ty);
    jit.create_func_prototype(
      "processor",
      &i32::llvm_ty(jit.context()),
      &[&minipage_ptr_ty],
      Some(bld))
  }

  fn generate_scalar_func(map: &mut MapCompiler, jit: &JitCompiler) {
    let func = &map.func;
    let builder = &map.builder;

    let codegen = map.stack.pop().unwrap();
    let minipage: Value = func.arg(0).into();

    let call = match jit.get_func("test") {
      Some(f) => {
        builder.create_call(&f, &[&minipage, &codegen])
      },
      _       => panic!("No such a function")
    };
    builder.create_ret(&call);
  }

  fn ret_func(&self, jit: &JitCompiler) -> Result<Rc<MapFunc>>
  {
    // dump code
    jit.dump();

    match jit.verify() {
      Ok(_) => {
        let func_ptr = unsafe { jit.get_func_ptr(&self.func).unwrap() };
        let func: MapFunc = unsafe {::std::mem::transmute(func_ptr)};
        Ok(Rc::new(func))
      }
      Err(msg) => {
        error!("{}", msg);
        Err(Error::FunctionCorrupted)
      }
    }
  }

  #[inline(always)]
  fn visit(&mut self, expr: &Expr) -> Value
  {

    // Stack must contain at least one Value item.
    // Otherwise, it is definitely a bug.
    self.stack.pop().unwrap()
  }

  #[inline(always)]
  fn push_value<T: ToValue>(&mut self, val: &T)
  {
    let v = val.to_value(self.jit.context());
    self.stack.push(v);
  }

  unary_codegen!(Not, create_not);

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, c: &Expr)
	{
	}

	pub fn PlusSign(&self, c: &Expr)
	{
    self.accept(expr);
	}

  unary_codegen!(MinusSign, create_neg);

	pub fn Cast(&self, c: &Expr, from: &Ty, to: &Ty)
	{
    match (*from, *to) {
      _ => {}
    }
	}

  bin_codegen!(And, create_and);
  bin_codegen!(Or,  create_or);
  bin_codegen!(Xor, create_xor);

	pub fn Cmp(&mut self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    let pred = match *op {
      CmpOp::Eq => Predicate::Eq,
      CmpOp::Ne => Predicate::Ne,
      CmpOp::Lt => Predicate::Lt,
      CmpOp::Le => Predicate::Le,
      CmpOp::Gt => Predicate::Gt,
      CmpOp::Ge => Predicate::Ge
    };

    self.stack.push(builder.create_cmp(&lhs_val, &rhs_val, pred));
	}

	pub fn Arithm(&mut self, ty: &Ty, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    self.stack.push(match *op {
      ArithmOp::Plus => {builder.create_add(&lhs_val, &rhs_val)}
      ArithmOp::Sub  => {builder.create_sub(&lhs_val, &rhs_val)}
      ArithmOp::Mul  => {builder.create_mul(&lhs_val, &rhs_val)}
      ArithmOp::Div  => {builder.create_div(&lhs_val, &rhs_val)}
      ArithmOp::Rem  => {builder.create_rem(&lhs_val, &rhs_val)}
    });
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}

  pub fn Const(&mut self, l: &Literal)
  {
    match *l {
      Literal::U8(ref v)  => self.push_value(v),
      Literal::I8(ref v)  => self.push_value(v),
      Literal::I16(ref v) => self.push_value(v),
      Literal::I32(ref v) => self.push_value(v),
      Literal::I64(ref v) => self.push_value(v),
      Literal::F32(ref v) => self.push_value(v),
      Literal::F64(ref v) => self.push_value(v),
      _                    => unimplemented!()
    }
  }

	pub fn Field(&mut self, ty: &Ty, name: &str)
	{
		/*
    let found: Option<(usize, &Ty, &&str)>;

		found = izip!(0 .. self.types.len(), self.types, self.names)
						.find(|&(i, t, n)| *n == name);

    let eval = match found {
    	Some(f) => FieldEvaluator {idx: f.0, ty: f.1.clone()},
    	None    => panic!("no such field for {}", name)
    };*/
	}
}

impl<'a> visitor::Visitor for MapCompiler<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.Or(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(e.ty(), o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (ref name)         => self.Field(e.ty(), name),
	    ExprKind::Const  (ref lit)          => self.Const(lit),
	    /*
	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut OwnedPageBuilder) -> Void;
}

#[cfg(test)]
mod tests {
	use common::rows::{
		Page,
		OwnedPageBuilder,
		PageId
	};
	use common::plugin::*;
	use common::session::Session;
	use common::storage::{RandomTable, MemTable};
	use common::types::*;

  use jit::JitCompiler;

	use plan::expr::*;
	use driver::DriverContext;

	use super::super::NamedSchema;

	use super::*;

  #[test]
  pub fn codegen() {
    let plugin_mgr = PluginManager::new();
    let jit = JitCompiler::new_from_bc("../common/target/ir/common.bc").ok().unwrap();
    assert!(jit.get_ty("struct.MiniPage").is_some());
    assert!(jit.get_ty("struct.Page").is_some());

    let types: Vec<Ty> = schema!(
	    I64, // l_orderkey      bigint
	    I64, // l_partkey       bigint
	    I64, // l_suppkey       bigint
	    I32, // l_linenumber    int
	    F64, // l_quantity      double,
	    F64, // l_extendedprice double,
	    F64, // l_discount      double,
	    F64  // l_tax           double,
	    // string types are not implmeneted yet.
    );

	  let names: Vec<&str> = vec![
	  	"l_orderkey",
	  	"l_partkey",
	  	"l_suppkey",
	  	"l_linenumber",
	  	"l_quantity",
	  	"l_extendedprice",
	  	"l_discount",
	  	"l_tax"
	  ];

    //let expr = Plus(I32, Const(19800401i32), Const(1i32));
    //let expr = Or(Const(4i32), Const(2i32));
    //let expr = Not(Const(0i32));
    let expr = MinusSign(Const(7i32));
    let schema  = NamedSchema::new(&names, &types);
  	let session = Session;

    let map = MapCompiler::compile(&jit,
                                   plugin_mgr.fn_registry(),
																	 &session,
																	 &schema,
																	 &expr).ok().unwrap();

    let mut minipage = MiniPage2 {
      ptr: ::std::ptr::null(),
      size: 0
    };
    assert_eq!(map(&mut minipage), 19800401i32);
  }
}<commit_msg>Implement MapCompiler::Cast().<commit_after>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::convert::From;
use std::rc::Rc;

use common::err::{Error, Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	MiniPage,
  FMiniPage,
	Page,
	OwnedPageBuilder,
	PageId
};
use common::session::Session;
use common::types::{Ty, name};

use jit::{JitCompiler};
use jit::builder::{Builder, CastOps};
use jit::types::{self, LLVMTy};
use jit::value::{Function, Predicate, Value, ValueRef, ToValue};
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;
use super::NamedSchema;

#[repr(C)]
pub struct MiniPage2 {
  ptr: *const u8,
  size: usize
}

pub type MapFunc = extern "C" fn(&mut MiniPage2) -> i32;

macro_rules! unary_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, expr: &Expr)
    {
      let val = self.visit(expr);
      let builder = &self.builder;

      self.stack.push(builder.$func(&val));
    }
  );
);

macro_rules! bin_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, lhs: &Expr, rhs: &Expr)
    {
      println!("before lhs");
      let lhs_val = self.visit(lhs);
      println!("before rhs");
      let rhs_val = self.visit(rhs);
      let builder = &self.builder;

      self.stack.push(builder.$func(&lhs_val, &rhs_val));
    }
  );
);

fn to_llvm_ty<'a>(jit: &'a JitCompiler, ty: &Ty) -> &'a types::Ty
{
  match *ty {
    Ty::Bool => jit.get_void_ty(),
    Ty::I8   => jit.get_void_ty(),
    Ty::I16  => jit.get_void_ty(),
    Ty::I32  => jit.get_void_ty(),
    Ty::I64  => jit.get_void_ty(),
    Ty::F32  => jit.get_void_ty(),
    Ty::F64  => jit.get_void_ty(),
    _        => panic!("not supported type: {}", ty.base())
  }
}

pub struct MapCompiler<'a>
{
  jit  : &'a JitCompiler,
  types: &'a Vec<Ty>,
	names: &'a Vec<&'a str>,
	stack: Vec<Value>,
  error: Option<Error>,
  func: Function,
  builder: Builder
}

impl<'a> MapCompiler<'a> {
  fn new(jit: &'a JitCompiler,
         fn_registry: &FuncRegistry,
		     session: &Session,
		     schema : &'a NamedSchema,) -> MapCompiler<'a> {
    let builder = jit.new_builder();
    let func = MapCompiler::generate_fn_prototype(jit, &builder);

		MapCompiler {
      jit   : jit,
			types : &schema.types,
			names : &schema.names,
			stack : Vec::new(),
			error : None,
      func: func,
      builder: builder
		}
	}

  pub fn compile(
            jit: &'a JitCompiler,
						fn_registry: &FuncRegistry,
		        session    : &'a Session,
					  schema     : &'a NamedSchema,
					  expr       : &Expr) -> Result<Rc<MapFunc>>
	{
    let mut map = MapCompiler::new(jit, fn_registry, session, schema);
    println!("before accept");
    map.accept(expr);
    println!("after accept");
    MapCompiler::generate_scalar_func(&mut map, jit);
    println!("after generate_scalar_func");
    map.ret_func(jit)
  }

  fn generate_fn_prototype(jit: &JitCompiler, bld: &Builder) -> Function {
    let minipage_ty = jit.get_ty("struct.MiniPage").unwrap();
    let minipage_ptr_ty = jit.get_pointer_ty(&minipage_ty);
    jit.create_func_prototype(
      "processor",
      &i32::llvm_ty(jit.context()),
      &[&minipage_ptr_ty],
      Some(bld))
  }

  fn generate_scalar_func(map: &mut MapCompiler, jit: &JitCompiler) {
    let func = &map.func;
    let builder = &map.builder;

    let codegen = map.stack.pop().unwrap();
    let minipage: Value = func.arg(0).into();

    let call = match jit.get_func("test") {
      Some(f) => {
        builder.create_call(&f, &[&minipage, &codegen])
      },
      _       => panic!("No such a function")
    };
    builder.create_ret(&call);
  }

  fn ret_func(&self, jit: &JitCompiler) -> Result<Rc<MapFunc>>
  {
    // dump code
    jit.dump();

    match jit.verify() {
      Ok(_) => {
        let func_ptr = unsafe { jit.get_func_ptr(&self.func).unwrap() };
        let func: MapFunc = unsafe {::std::mem::transmute(func_ptr)};
        Ok(Rc::new(func))
      }
      Err(msg) => {
        error!("{}", msg);
        Err(Error::FunctionCorrupted)
      }
    }
  }

  #[inline(always)]
  fn visit(&mut self, expr: &Expr) -> Value
  {
    self.accept(expr);
    // Stack must contain at least one Value item.
    // Otherwise, it is definitely a bug.
    self.stack.pop().unwrap()
  }

  #[inline(always)]
  fn push_value<T: ToValue>(&mut self, val: &T)
  {
    let v = val.to_value(self.jit.context());
    self.stack.push(v);
  }

  unary_codegen!(Not, create_not);

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, e: &Expr)
	{
	}

	pub fn PlusSign(&mut self, e: &Expr)
	{
    self.accept(e);
	}

  unary_codegen!(MinusSign, create_neg);

	pub fn Cast(&mut self, e: &Expr, from: &Ty, to: &Ty)
	{
    // if the both types are equivalent, just return.
    if from == to { return; }

    let cast_op = if from.is_sint() && to.is_sint() {
      if from.size_of() < to.size_of() {
        CastOps::SExt
      } else {
        CastOps::Trunc
      }
    } else if from.is_sint() && to.is_float() {
      CastOps::SIToFP
    } else if from.is_uint() && to.is_float() {
      CastOps::UIToFP
    } else if from.is_float() && to.is_sint() {
      CastOps::FPToSI
    } else if from.is_float() && to.is_uint() {
      CastOps::FPToUI
    } else if from.is_float() && to.is_float() {
      if from.size_of() < to.size_of() {
        CastOps::FPExt
      } else {
        CastOps::FPTrunc
      }
    } else {
      panic!("not supported cast from {} to {}", from.base(), to.base());
    };

    let val = self.visit(e);
    let builder = &self.builder;

    self.stack.push(builder.create_cast(cast_op, &val, to_llvm_ty(self.jit, to)));
	}

  bin_codegen!(And, create_and);
  bin_codegen!(Or,  create_or);
  bin_codegen!(Xor, create_xor);

	pub fn Cmp(&mut self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    let pred = match *op {
      CmpOp::Eq => Predicate::Eq,
      CmpOp::Ne => Predicate::Ne,
      CmpOp::Lt => Predicate::Lt,
      CmpOp::Le => Predicate::Le,
      CmpOp::Gt => Predicate::Gt,
      CmpOp::Ge => Predicate::Ge
    };

    self.stack.push(builder.create_cmp(&lhs_val, &rhs_val, pred));
	}

	pub fn Arithm(&mut self, ty: &Ty, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    self.stack.push(match *op {
      ArithmOp::Plus => {builder.create_add(&lhs_val, &rhs_val)}
      ArithmOp::Sub  => {builder.create_sub(&lhs_val, &rhs_val)}
      ArithmOp::Mul  => {builder.create_mul(&lhs_val, &rhs_val)}
      ArithmOp::Div  => {builder.create_div(&lhs_val, &rhs_val)}
      ArithmOp::Rem  => {builder.create_rem(&lhs_val, &rhs_val)}
    });
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}

  pub fn Const(&mut self, l: &Literal)
  {
    match *l {
      Literal::U8(ref v)  => self.push_value(v),
      Literal::I8(ref v)  => self.push_value(v),
      Literal::I16(ref v) => self.push_value(v),
      Literal::I32(ref v) => self.push_value(v),
      Literal::I64(ref v) => self.push_value(v),
      Literal::F32(ref v) => self.push_value(v),
      Literal::F64(ref v) => self.push_value(v),
      _                    => unimplemented!()
    }
  }

	pub fn Field(&mut self, ty: &Ty, name: &str)
	{
		/*
    let found: Option<(usize, &Ty, &&str)>;

		found = izip!(0 .. self.types.len(), self.types, self.names)
						.find(|&(i, t, n)| *n == name);

    let eval = match found {
    	Some(f) => FieldEvaluator {idx: f.0, ty: f.1.clone()},
    	None    => panic!("no such field for {}", name)
    };*/
	}
}

impl<'a> visitor::Visitor for MapCompiler<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.Or(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(e.ty(), o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (ref name)         => self.Field(e.ty(), name),
	    ExprKind::Const  (ref lit)          => self.Const(lit),
	    /*
	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut OwnedPageBuilder) -> Void;
}

#[cfg(test)]
mod tests {
	use common::rows::{
		Page,
		OwnedPageBuilder,
		PageId
	};
	use common::plugin::*;
	use common::session::Session;
	use common::storage::{RandomTable, MemTable};
	use common::types::*;

  use jit::JitCompiler;

	use plan::expr::*;
	use driver::DriverContext;

	use super::super::NamedSchema;

	use super::*;

  #[test]
  pub fn codegen() {
    let plugin_mgr = PluginManager::new();
    let jit = JitCompiler::new_from_bc("../common/target/ir/common.bc").ok().unwrap();
    assert!(jit.get_ty("struct.MiniPage").is_some());
    assert!(jit.get_ty("struct.Page").is_some());

    let types: Vec<Ty> = schema!(
	    I64, // l_orderkey      bigint
	    I64, // l_partkey       bigint
	    I64, // l_suppkey       bigint
	    I32, // l_linenumber    int
	    F64, // l_quantity      double,
	    F64, // l_extendedprice double,
	    F64, // l_discount      double,
	    F64  // l_tax           double,
	    // string types are not implmeneted yet.
    );

	  let names: Vec<&str> = vec![
	  	"l_orderkey",
	  	"l_partkey",
	  	"l_suppkey",
	  	"l_linenumber",
	  	"l_quantity",
	  	"l_extendedprice",
	  	"l_discount",
	  	"l_tax"
	  ];

    let expr = Plus(I32, Const(19800401i32), Const(1i32));
    //let expr = Or(Const(4i32), Const(2i32));
    //let expr = Not(Const(0i32));
    //let expr = MinusSign(Const(7i32));
    let schema  = NamedSchema::new(&names, &types);
  	let session = Session;

    let map = MapCompiler::compile(&jit,
                                   plugin_mgr.fn_registry(),
																	 &session,
																	 &schema,
																	 &expr).ok().unwrap();

    let mut minipage = MiniPage2 {
      ptr: ::std::ptr::null(),
      size: 0
    };
    assert_eq!(map(&mut minipage), 19800401i32);
  }
}<|endoftext|>


<commit_before>pub trait FormatProvider {
    fn get_strikethrough(&self, s: &str) -> String;
}

pub trait Format {
    fn format(&self, fp: &FormatProvider) -> String;
}

<commit_msg>GitterMdFormatProvider<commit_after>pub trait FormatProvider {
    fn get_strikethrough(&self, s: &str) -> String;
}

pub trait Format {
    fn format(&self, fp: &FormatProvider) -> String;
}

pub struct GitterMdFormatProvider;

impl FormatProvider for GitterMdFormatProvider {
     fn get_strikethrough(&self, s: &str) -> String {
         format!("~~{}~~", s)
     }
}<|endoftext|>