<commit_before>use std::cmp::{max, min};

use cairo::{self, ImageSurface};
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::{AttributeResultExt, NodeError};
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers;
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// Enumeration of the possible morphology operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Operator {
    Erode,
    Dilate,
}

/// The `feMorphology` filter primitive.
pub struct FeMorphology {
    base: PrimitiveWithInput,
    operator: Operator,
    radius: (f64, f64),
}

impl Default for FeMorphology {
    /// Constructs a new `Morphology` with empty properties.
    #[inline]
    fn default() -> FeMorphology {
        FeMorphology {
            base: PrimitiveWithInput::new::<Self>(),
            operator: Operator::Erode,
            radius: (0.0, 0.0),
        }
    }
}

impl NodeTrait for FeMorphology {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "operator") => self.operator = Operator::parse(attr, value)?,
                expanded_name!(svg "radius") => {
                    self.radius = parsers::number_optional_number(value)
                        .attribute(attr.clone())
                        .and_then(|(x, y)| {
                            if x >= 0.0 && y >= 0.0 {
                                Ok((x, y))
                            } else {
                                Err(NodeError::value_error(attr, "radius cannot be negative"))
                            }
                        })?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeMorphology {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let (rx, ry) = self.radius;
        let (rx, ry) = ctx.paffine().transform_distance(rx, ry);

        // The radii can become negative here due to the transform.
        let rx = rx.abs();
        let ry = ry.abs();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, _pixel) in Pixels::new(input.surface(), bounds) {
                // Compute the kernel rectangle bounds.
                let kernel_bounds = IRect::new(
                    (f64::from(x) - rx).floor() as i32,
                    (f64::from(y) - ry).floor() as i32,
                    (f64::from(x) + rx).ceil() as i32 + 1,
                    (f64::from(y) + ry).ceil() as i32 + 1,
                );

                // Compute the new pixel values.
                let initial = match self.operator {
                    Operator::Erode => u8::max_value(),
                    Operator::Dilate => u8::min_value(),
                };

                let mut output_pixel = Pixel {
                    r: initial,
                    g: initial,
                    b: initial,
                    a: initial,
                };

                for (_x, _y, pixel) in
                    PixelRectangle::new(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
                {
                    let op = match self.operator {
                        Operator::Erode => min,
                        Operator::Dilate => max,
                    };

                    output_pixel.r = op(output_pixel.r, pixel.r);
                    output_pixel.g = op(output_pixel.g, pixel.g);
                    output_pixel.b = op(output_pixel.b, pixel.b);
                    output_pixel.a = op(output_pixel.a, pixel.a);
                }

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}

impl Operator {
    fn parse(attr: QualName, s: &str) -> Result<Self, NodeError> {
        match s {
            "erode" => Ok(Operator::Erode),
            "dilate" => Ok(Operator::Dilate),
            _ => Err(NodeError::parse_error(attr, "invalid value")),
        }
    }
}
<commit_msg>morphology.rs: Don't create a NodeError directly<commit_after>use std::cmp::{max, min};

use cairo::{self, ImageSurface};
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers;
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// Enumeration of the possible morphology operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Operator {
    Erode,
    Dilate,
}

/// The `feMorphology` filter primitive.
pub struct FeMorphology {
    base: PrimitiveWithInput,
    operator: Operator,
    radius: (f64, f64),
}

impl Default for FeMorphology {
    /// Constructs a new `Morphology` with empty properties.
    #[inline]
    fn default() -> FeMorphology {
        FeMorphology {
            base: PrimitiveWithInput::new::<Self>(),
            operator: Operator::Erode,
            radius: (0.0, 0.0),
        }
    }
}

impl NodeTrait for FeMorphology {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "operator") => self.operator = Operator::parse(attr, value)?,
                expanded_name!(svg "radius") => {
                    self.radius = parsers::number_optional_number(value)
                        .and_then(|(x, y)| {
                            if x >= 0.0 && y >= 0.0 {
                                Ok((x, y))
                            } else {
                                Err(ValueErrorKind::value_error("radius cannot be negative"))
                            }
                        }).attribute(attr)?
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeMorphology {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let (rx, ry) = self.radius;
        let (rx, ry) = ctx.paffine().transform_distance(rx, ry);

        // The radii can become negative here due to the transform.
        let rx = rx.abs();
        let ry = ry.abs();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, _pixel) in Pixels::new(input.surface(), bounds) {
                // Compute the kernel rectangle bounds.
                let kernel_bounds = IRect::new(
                    (f64::from(x) - rx).floor() as i32,
                    (f64::from(y) - ry).floor() as i32,
                    (f64::from(x) + rx).ceil() as i32 + 1,
                    (f64::from(y) + ry).ceil() as i32 + 1,
                );

                // Compute the new pixel values.
                let initial = match self.operator {
                    Operator::Erode => u8::max_value(),
                    Operator::Dilate => u8::min_value(),
                };

                let mut output_pixel = Pixel {
                    r: initial,
                    g: initial,
                    b: initial,
                    a: initial,
                };

                for (_x, _y, pixel) in
                    PixelRectangle::new(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
                {
                    let op = match self.operator {
                        Operator::Erode => min,
                        Operator::Dilate => max,
                    };

                    output_pixel.r = op(output_pixel.r, pixel.r);
                    output_pixel.g = op(output_pixel.g, pixel.g);
                    output_pixel.b = op(output_pixel.b, pixel.b);
                    output_pixel.a = op(output_pixel.a, pixel.a);
                }

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}

impl Operator {
    fn parse(attr: QualName, s: &str) -> Result<Self, NodeError> {
        match s {
            "erode" => Ok(Operator::Erode),
            "dilate" => Ok(Operator::Dilate),
            _ => Err(NodeError::parse_error(attr, "invalid value")),
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "fibonacci", vers = "1.0", author = "eliovir")];
#[crate_type = "lib"];
/**
 * Compute fibonacci.
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

extern mod extra;
/**
* Calcule les elements de la suite de Fibonnaci.
*
* REGLE RG024 Le projet permet de calculer les membres de la Suite de
* Fibonacci.
*
* REGLE RG024.1 : f(1) = 1
* REGLE RG024.2 : f(2) = 1
*
* REGLE RG024.3 : f(n) = f(n-1) + f(n-2) si n > 2
*
* REGLE RG024.4 : il n'est pas possible de calculer la valeur de la Suite
* de Fibonacci pour un rang negatif.
*
* REGLE RG024.5 : le calcul de n'importe quel element de la Suite de
* Fibonacci doit s'effectuer en moins de deux secondes.
*
* REGLE RG024.6 : le calcul de n'importe quel element de la Suite de
* Fibonacci, pour un rang inferieur a 50, doit s'effectuer en moins d'une
* seconde.
*
* @param n le rang pour lequel on calcule le membre.
* @return Le membre de rang n dans la Suite.
*/
fn fibonacci(n: int) -> uint {
	if n < 0 {
		fail!(fmt!("%d is negative!", n));
	}
	match n {
		0     => fail!("zero is not a right argument to fibonacci()!"),
		1 | 2 => 1,
		3     => 2,
		/*
		50    => 12586269025,
		*/
		_     => fibonacci(n - 1) + fibonacci(n - 2)
	}
}
/*
#[cfg(test)]
mod tests {
}
*/
fn RG024_x(n: int, expected: uint) {
	// println(fmt!("RG024_x(%d, %u)", n, expected));
	let found = fibonacci(n);
	assert!(expected == found);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.1 : f(1) = 1
 */
#[test]
fn RG024_1() {
	RG024_x(1, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.2 : f(2) = 1
 */
#[test]
fn RG024_2() {
	RG024_x(2, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.3.a : f(3) = 2
 */
#[test]
fn RG024_3_a() {
	RG024_x(3, 2);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.4.a : il n'est pas possible de calculer la valeur de la Suite
 * de Fibonacci pour un rang negatif ou nul.
 */
#[test]
#[should_fail]
fn RG024_4_a() {
	fibonacci(-1);
	fibonacci(0);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.5 : f(55) = 139583862445
 */
#[test]
fn RG024_5() {
	/*RG024_x(55, 139583862445);*/
	RG024_x(30, 832040);
}
#[bench]
fn bench_fibonacci_20(b: &mut extra::test::BenchHarness) {
	do b.iter {
		fibonacci(20);
	}
}
<commit_msg>libfibonacci.rs : add doc attributes<commit_after>#[link(name = "fibonacci", vers = "1.0", author = "eliovir")];
#[crate_type = "lib"];
#[license = "MIT"];
#[desc = "Fibonacci library" ];
#[comment = "Example of library: compute Fibonacci"];
/**
 * Compute fibonacci.
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

extern mod extra;
/**
* Calcule les elements de la suite de Fibonnaci.
*
* REGLE RG024 Le projet permet de calculer les membres de la Suite de
* Fibonacci.
*
* REGLE RG024.1 : f(1) = 1
* REGLE RG024.2 : f(2) = 1
*
* REGLE RG024.3 : f(n) = f(n-1) + f(n-2) si n > 2
*
* REGLE RG024.4 : il n'est pas possible de calculer la valeur de la Suite
* de Fibonacci pour un rang negatif.
*
* REGLE RG024.5 : le calcul de n'importe quel element de la Suite de
* Fibonacci doit s'effectuer en moins de deux secondes.
*
* REGLE RG024.6 : le calcul de n'importe quel element de la Suite de
* Fibonacci, pour un rang inferieur a 50, doit s'effectuer en moins d'une
* seconde.
*
* @param n le rang pour lequel on calcule le membre.
* @return Le membre de rang n dans la Suite.
*/
fn fibonacci(n: int) -> uint {
	if n < 0 {
		fail!(fmt!("%d is negative!", n));
	}
	match n {
		0     => fail!("zero is not a right argument to fibonacci()!"),
		1 | 2 => 1,
		3     => 2,
		/*
		50    => 12586269025,
		*/
		_     => fibonacci(n - 1) + fibonacci(n - 2)
	}
}
/*
#[cfg(test)]
mod tests {
}
*/
fn RG024_x(n: int, expected: uint) {
	// println(fmt!("RG024_x(%d, %u)", n, expected));
	let found = fibonacci(n);
	assert!(expected == found);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.1 : f(1) = 1
 */
#[test]
fn RG024_1() {
	RG024_x(1, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.2 : f(2) = 1
 */
#[test]
fn RG024_2() {
	RG024_x(2, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.3.a : f(3) = 2
 */
#[test]
fn RG024_3_a() {
	RG024_x(3, 2);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.4.a : il n'est pas possible de calculer la valeur de la Suite
 * de Fibonacci pour un rang negatif ou nul.
 */
#[test]
#[should_fail]
fn RG024_4_a() {
	fibonacci(-1);
	fibonacci(0);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.5 : f(55) = 139583862445
 */
#[test]
fn RG024_5() {
	/*RG024_x(55, 139583862445);*/
	RG024_x(30, 832040);
}
#[bench]
fn bench_fibonacci_20(b: &mut extra::test::BenchHarness) {
	do b.iter {
		fibonacci(20);
	}
}
<|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,
}

/// 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),
        }
    }

    /// 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),
        }
    }

    /// 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> {
        Stream::open(self.uri.as_str(), self.sync_to_pps)
    }
}

impl Stream {
    /// Opens a new stream for the provided uri, with no logger and default buffer size.
    ///
    /// The second parameter is `sync_to_pps`. If true, only grabs points that were collected after
    /// the scanner was synced to an external PPS signal.
    ///
    /// To customize logging and buffer size behavior, use a `Builder`.
    ///
    /// # Examples
    ///
    /// ```
    /// use scanifc::point3d::Stream;
    /// let stream = Stream::open("file:data/scan.rxp", true).unwrap();
    /// ```
    pub fn open(uri: &str, sync_to_pps: bool) -> Result<Stream> {
        use std::ffi::CString;
        use std::ptr;

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

    /// 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::open("file:data/scan.rxp", true).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 stream_read() {
        let stream = Stream::open("file:data/scan.rxp", true).unwrap();
        let points = stream.collect::<Result<Vec<_>>>().unwrap();
        assert_eq!(24390, points.len());
    }
}
<commit_msg>Push everything through the builder<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 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());
    }
}
<|endoftext|>


<commit_before>use crate::TokenStream;
use crate::{Ident,Literal};
use crate::{Punct,Spacing};
use crate::Span;

struct CharStream<T: Iterator<Item=char>> {
    inner: ::std::iter::Peekable<T>,
    cur: Option<char>,
}
impl<T: Iterator<Item=char>> CharStream<T> {
    fn new(i: T) -> Self {
        CharStream {
            inner: i.peekable(),
            cur: Some(' '),
            }
    }
    fn consume(&mut self) -> Option<char> {
        self.cur = self.inner.next();
        self.cur
    }
    fn is_complete(&self) -> bool {
        self.cur.is_none()
    }
    fn cur(&self) -> char {
        self.cur.expect("CharStream::cur called with no current")
    }
    fn next(&mut self) -> Option<char> {
        self.inner.peek().cloned()
    }
}

static SYMS: [&[u8]; 53] = [
    b"!" as &[u8],
    b"!=",
    b"#",
    b"$",
    b"%", b"%=",
    b"&", b"&&", b"&=",
    b"(",
    b")",
    b"*", b"*=",
    b"+", b"+=",
    b",",
    b"-", b"-=", b"->",
    b".", b"..", b"...",
    b"/", b"/=",
    b":", b"::",
    b";",
    b"<", b"<-", b"<<", b"<<=", b"<=",
    b"=", b"==", b"=>",
    b">", b">=", b">>", b">>=",
    b"?",
    b"@",
    b"[",
    b"\\",
    b"]",
    b"^", b"^=",
    b"`",
    b"{",
    b"|", b"|=", b"||",
    b"}",
    b"~",
    ];

pub struct LexError {
    inner: &'static str,
}
impl ::std::fmt::Debug for LexError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "LexError({})", self.inner)
    }
}
impl ::std::str::FromStr for TokenStream {
    type Err = LexError;
    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        debug!("TokenStream::from_str({:?})\r", src);
        let mut rv: Vec<crate::TokenTree> = Vec::new();
        let mut it = CharStream::new(src.chars());

        fn err(s: &'static str) -> Result<TokenStream,LexError> {
            Err(LexError { inner: s })
        }

        fn get_ident<T: Iterator<Item=char>>(it: &mut CharStream<T>, mut s: String) -> String
        {
            let mut c = it.cur();
            while c == '_' || c.is_alphanumeric() || c.is_digit(10)
            {
                s.push(c);
                c = some_else!(it.consume() => break);
            }
            s
        }

        'outer: while ! it.is_complete()
        {
            let mut c = it.cur();

            if c.is_whitespace() {
                it.consume();
                continue ;
            }

            if c == '\''
            {
                it.consume();
                c = it.cur();
                if (c.is_alphabetic() || c == '_') && it.next().map(|x| x != '\'').unwrap_or(true) {
                    // Lifetime
                    let ident = get_ident(&mut it, String::new());
                    rv.push(Punct::new('\'', Spacing::Joint).into());
                    rv.push(Ident { is_raw: false, val: ident, span: crate::Span::call_site() }.into());
                }
                else {
                    // Char lit
                    if c == '\\' {
                        panic!("TODO: char literal with escape");
                    }
                    else {
                        rv.push(Literal::character(c).into());
                        match it.consume()
                        {
                        Some('\'') => {},
                        Some(c) => {
                            debug!("Stray charcter '{}'", c);
                            return err("Multiple characters in char literal");
                            },
                        None => {
                            return err("Unterminated char literal");
                            },
                        }
                    }
                }
            }
            else if c == '/' && it.next() == Some('/')
            {
                // Line comment
                while it.consume() != Some('\n') {
                }
            }
            else if c == '/' && it.next() == Some('*')
            {
                // Block comment
                panic!("TODO: Block comment");
            }
            else
            {
                // byte or raw string literals
                if c == 'b' || c == 'r' || c == '"' {
                    let mut c = c;
                    let is_byte = if c == 'b' {
                            c = some_else!(it.consume() => { rv.push(Ident::new("b", crate::Span::call_site()).into()); break });
                            true
                        } else {
                            false
                        };

                    if c == 'r'
                    {
                        // TODO: If this isn't a string, start parsing an ident instead.
                        let ident_str = if is_byte { "br" } else { "r" };
                        c = some_else!(it.consume() => { rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into()); break });
                        let mut hashes = 0;
                        while c == '#' {
                            hashes += 1;
                            c = some_else!(it.consume() => return err("rawstr eof"));
                        }

                        if c != '"' {
                            if hashes == 0 {
                                let s = get_ident(&mut it, ident_str.to_string());
                                rv.push(Ident { is_raw: false, val: s, span: crate::Span::call_site() }.into());
                            }
                            else {
                                rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into());
                            }
                            while hashes > 0 {
                                rv.push(Punct::new('#', if hashes == 1 { Spacing::Alone } else { Spacing::Joint }).into());
                                hashes -= 1;
                            }
                            continue 'outer;
                        }

                        let req_hashes = hashes;
                        let mut rawstr = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("Rawstr eof"));
                            if c == '"' {
                                let mut hashes = 0;
                                while hashes < req_hashes {
                                    c = some_else!(it.consume() => return err("rawstr eof"));
                                    if c != '#' { break ; }
                                    hashes += 1;
                                }

                                if hashes != req_hashes {
                                    rawstr.push('"');
                                    for _ in 0 .. hashes {
                                        rawstr.push('#');
                                    }
                                    rawstr.push(c);
                                }
                                else {
                                    break ;
                                }
                            }
                            else {
                                rawstr.push(c);
                            }
                        }

                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(rawstr.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(rawstr)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else if c == '\''
                    {
                        // Byte character literal?
                        // NOTE: That b'foo is not `b` followed by `'foo`
                        assert!(is_byte);
                        panic!("TODO: Byte character literal");
                    }
                    else if c == '\"'
                    {
                        // String literal
                        let mut s = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("str eof"));
                            if c == '"' {
                                it.consume();
                                break ;
                            }
                            else if c == '\\' {
                                match some_else!(it.consume() => return err("str eof"))
                                {
                                c @ _ => panic!("Unknown escape in string {}", c),
                                }
                            }
                            else {
                                s.push(c);
                            }
                        }
                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(s.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(s)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else
                    {
                        // Could be an ident starting with 'b', or it's just 'b'
                        // - Fall through
                        let ident = get_ident(&mut it, "b".into());
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                        continue 'outer;
                    }
                }

                // Identifier.
                if c.is_alphabetic() || c == '_'
                {
                    let ident = get_ident(&mut it, String::new());
                    if ident == "_" {
                        rv.push(Punct::new('_', Spacing::Alone).into());
                    }
                    else {
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                    }
                }
                else if c.is_digit(10)
                {
                    let base =
                        if c == '0' {
                            match it.consume()
                            {
                            Some('x') => { it.consume(); 16 },
                            Some('o') => { it.consume(); 8 },
                            Some('b') => { it.consume(); 2 },
                            None => {
                                rv.push(Literal::new_u(0, 0).into());
                                continue 'outer;
                                },
                            _ => 10,
                            }
                        }
                        else {
                            10
                        };
                    let mut v = 0;
                    let mut c = it.cur();
                    'int: loop
                    {
                        while c == '_' {
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        if c == 'u' || c == 'i' {
                            let s = get_ident(&mut it, String::new());
                            rv.push(match &*s
                                {
                                "u8"    => Literal::new_u(v,   8), "i8"    => Literal::new_s(v as i128,   8),
                                "u16"   => Literal::new_u(v,  16), "i16"   => Literal::new_s(v as i128,  16),
                                "u32"   => Literal::new_u(v,  32), "i32"   => Literal::new_s(v as i128,  32),
                                "u64"   => Literal::new_u(v,  64), "i64"   => Literal::new_s(v as i128,  64),
                                "u128"  => Literal::new_u(v, 128), "i128"  => Literal::new_s(v as i128, 128),
                                "usize" => Literal::new_u(v,   1), "isize" => Literal::new_s(v as i128,   1),
                                _ => return err("Unexpected integer suffix"),
                                }.into());
                            continue 'outer;
                        }
                        else if let Some(d) = c.to_digit(base) {
                            v *= base as u128;
                            v += d as u128;
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        else if c == '.' {
                            panic!("TODO: Floating point");
                        }
                        else {
                            break;
                        }
                    }
                    rv.push(Literal::new_u(v, 0).into());
                    continue 'outer;
                }
                // Punctuation?
                else if c as u32 <= 0xFF
                {
                    let mut start = match SYMS.iter().position(|v| v[0] == (c as u8))
                        {
                        Some(start) => start,
                        None => {
                            eprint!("Unknown operator character '{}'\r\n", c);
                            return err("Unknown operator")
                            },
                        };
                    let mut end = start+1;
                    while end < SYMS.len() && SYMS[end][0] == c as u8 {
                        end += 1;
                    }

                    let mut ofs = 1;
                    loop
                    {
                        let syms = &SYMS[start..end];
                        assert_eq!(ofs, syms[0].len(), "{:?}", syms[0]);
                        c = some_else!(it.consume() => break);
                        let step = match syms[1..].iter().position(|v| v[ofs] == (c as u8))
                            {
                            Some(s) => s+1,
                            None => break,
                            };
                        start += step;
                        end = start+1;
                        while end < syms.len() && syms[end][ofs] == c as u8 {
                            end += 1;
                        }
                        ofs += 1;
                    }
                    assert_eq!(SYMS[start].len(), ofs);
                    for (i,&c) in Iterator::enumerate(SYMS[start].iter())
                    {
                        let sep = if i == SYMS[start].len() - 1 { Spacing::Alone } else { Spacing::Joint };
                        rv.push(Punct::new(c as char, sep).into());
                    }
                }
                else
                {
                    return err("Unexpected character");
                }
            }
        }

        Ok(TokenStream {
            inner: rv,
            })
    }
}

#[cfg(test)]
mod tests {
    use crate::*;
    use ::std::str::FromStr;

    macro_rules! assert_tt_matches {
        ($have:expr, $exp:expr) => {{
            let e = $exp;
            let h = match $have
                {
                Some(h) => h,
                None => panic!("Unexpected end of stream (expecting {:?})", e),
                };
            assert!( crate::token_tree::tt_eq(&h, &e), "Expected {:?} got {:?}", e, h );
        }};
        ($have:expr) => {{
            match $have
            {
            Some(h) => panic!("Expected end of stream, found {:?}", h),
            None => {},
            }
        }};
    }

    #[test]
    fn lifetime()
    {
        let rv = TokenStream::from_str("foo::bar<'a>").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("foo", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("bar", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('<', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Punct::new('\'', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Ident::new("a", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('>', Spacing::Alone).into());
        assert_tt_matches!(it.next());
    }

    #[test]
    fn numbers()
    {
        assert_eq!(
            TokenStream::from_str("0").expect("Failed to parse").into_iter().collect::<Vec<_>>(),
            &[
                Literal::new_u(0,0).into(),
            ]
        );
    }
}<commit_msg>libproc_macro - Tweaked tests<commit_after>use crate::TokenStream;
use crate::{Ident,Literal};
use crate::{Punct,Spacing};
use crate::Span;

struct CharStream<T: Iterator<Item=char>> {
    inner: ::std::iter::Peekable<T>,
    cur: Option<char>,
}
impl<T: Iterator<Item=char>> CharStream<T> {
    fn new(i: T) -> Self {
        CharStream {
            inner: i.peekable(),
            cur: Some(' '),
            }
    }
    fn consume(&mut self) -> Option<char> {
        self.cur = self.inner.next();
        self.cur
    }
    fn is_complete(&self) -> bool {
        self.cur.is_none()
    }
    fn cur(&self) -> char {
        self.cur.expect("CharStream::cur called with no current")
    }
    fn next(&mut self) -> Option<char> {
        self.inner.peek().cloned()
    }
}

static SYMS: [&[u8]; 53] = [
    b"!" as &[u8],
    b"!=",
    b"#",
    b"$",
    b"%", b"%=",
    b"&", b"&&", b"&=",
    b"(",
    b")",
    b"*", b"*=",
    b"+", b"+=",
    b",",
    b"-", b"-=", b"->",
    b".", b"..", b"...",
    b"/", b"/=",
    b":", b"::",
    b";",
    b"<", b"<-", b"<<", b"<<=", b"<=",
    b"=", b"==", b"=>",
    b">", b">=", b">>", b">>=",
    b"?",
    b"@",
    b"[",
    b"\\",
    b"]",
    b"^", b"^=",
    b"`",
    b"{",
    b"|", b"|=", b"||",
    b"}",
    b"~",
    ];

pub struct LexError {
    inner: &'static str,
}
impl ::std::fmt::Debug for LexError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "LexError({})", self.inner)
    }
}
impl ::std::str::FromStr for TokenStream {
    type Err = LexError;
    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        debug!("TokenStream::from_str({:?})\r", src);
        let mut rv: Vec<crate::TokenTree> = Vec::new();
        let mut it = CharStream::new(src.chars());

        fn err(s: &'static str) -> Result<TokenStream,LexError> {
            Err(LexError { inner: s })
        }

        fn get_ident<T: Iterator<Item=char>>(it: &mut CharStream<T>, mut s: String) -> String
        {
            let mut c = it.cur();
            while c == '_' || c.is_alphanumeric() || c.is_digit(10)
            {
                s.push(c);
                c = some_else!(it.consume() => break);
            }
            s
        }

        'outer: while ! it.is_complete()
        {
            let mut c = it.cur();

            if c.is_whitespace() {
                it.consume();
                continue ;
            }

            if c == '\''
            {
                it.consume();
                c = it.cur();
                if (c.is_alphabetic() || c == '_') && it.next().map(|x| x != '\'').unwrap_or(true) {
                    // Lifetime
                    let ident = get_ident(&mut it, String::new());
                    rv.push(Punct::new('\'', Spacing::Joint).into());
                    rv.push(Ident { is_raw: false, val: ident, span: crate::Span::call_site() }.into());
                }
                else {
                    // Char lit
                    if c == '\\' {
                        panic!("TODO: char literal with escape");
                    }
                    else {
                        rv.push(Literal::character(c).into());
                        match it.consume()
                        {
                        Some('\'') => {},
                        Some(c) => {
                            debug!("Stray charcter '{}'", c);
                            return err("Multiple characters in char literal");
                            },
                        None => {
                            return err("Unterminated char literal");
                            },
                        }
                    }
                }
            }
            else if c == '/' && it.next() == Some('/')
            {
                // Line comment
                while it.consume() != Some('\n') {
                }
            }
            else if c == '/' && it.next() == Some('*')
            {
                // Block comment
                panic!("TODO: Block comment");
            }
            else
            {
                // byte or raw string literals
                if c == 'b' || c == 'r' || c == '"' {
                    let mut c = c;
                    let is_byte = if c == 'b' {
                            c = some_else!(it.consume() => { rv.push(Ident::new("b", crate::Span::call_site()).into()); break });
                            true
                        } else {
                            false
                        };

                    if c == 'r'
                    {
                        // TODO: If this isn't a string, start parsing an ident instead.
                        let ident_str = if is_byte { "br" } else { "r" };
                        c = some_else!(it.consume() => { rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into()); break });
                        let mut hashes = 0;
                        while c == '#' {
                            hashes += 1;
                            c = some_else!(it.consume() => return err("rawstr eof"));
                        }

                        if c != '"' {
                            if hashes == 0 {
                                let s = get_ident(&mut it, ident_str.to_string());
                                rv.push(Ident { is_raw: false, val: s, span: crate::Span::call_site() }.into());
                            }
                            else {
                                rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into());
                            }
                            while hashes > 0 {
                                rv.push(Punct::new('#', if hashes == 1 { Spacing::Alone } else { Spacing::Joint }).into());
                                hashes -= 1;
                            }
                            continue 'outer;
                        }

                        let req_hashes = hashes;
                        let mut rawstr = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("Rawstr eof"));
                            if c == '"' {
                                let mut hashes = 0;
                                while hashes < req_hashes {
                                    c = some_else!(it.consume() => return err("rawstr eof"));
                                    if c != '#' { break ; }
                                    hashes += 1;
                                }

                                if hashes != req_hashes {
                                    rawstr.push('"');
                                    for _ in 0 .. hashes {
                                        rawstr.push('#');
                                    }
                                    rawstr.push(c);
                                }
                                else {
                                    break ;
                                }
                            }
                            else {
                                rawstr.push(c);
                            }
                        }

                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(rawstr.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(rawstr)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else if c == '\''
                    {
                        // Byte character literal?
                        // NOTE: That b'foo is not `b` followed by `'foo`
                        assert!(is_byte);
                        panic!("TODO: Byte character literal");
                    }
                    else if c == '\"'
                    {
                        // String literal
                        let mut s = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("str eof"));
                            if c == '"' {
                                it.consume();
                                break ;
                            }
                            else if c == '\\' {
                                match some_else!(it.consume() => return err("str eof"))
                                {
                                c @ _ => panic!("Unknown escape in string {}", c),
                                }
                            }
                            else {
                                s.push(c);
                            }
                        }
                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(s.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(s)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else
                    {
                        // Could be an ident starting with 'b', or it's just 'b'
                        // - Fall through
                        let ident = get_ident(&mut it, "b".into());
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                        continue 'outer;
                    }
                }

                // Identifier.
                if c.is_alphabetic() || c == '_'
                {
                    let ident = get_ident(&mut it, String::new());
                    if ident == "_" {
                        rv.push(Punct::new('_', Spacing::Alone).into());
                    }
                    else {
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                    }
                }
                else if c.is_digit(10)
                {
                    let base =
                        if c == '0' {
                            match it.consume()
                            {
                            Some('x') => { it.consume(); 16 },
                            Some('o') => { it.consume(); 8 },
                            Some('b') => { it.consume(); 2 },
                            None => {
                                rv.push(Literal::new_u(0, 0).into());
                                continue 'outer;
                                },
                            _ => 10,
                            }
                        }
                        else {
                            10
                        };
                    let mut v = 0;
                    let mut c = it.cur();
                    'int: loop
                    {
                        while c == '_' {
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        if c == 'u' || c == 'i' {
                            let s = get_ident(&mut it, String::new());
                            rv.push(match &*s
                                {
                                "u8"    => Literal::new_u(v,   8), "i8"    => Literal::new_s(v as i128,   8),
                                "u16"   => Literal::new_u(v,  16), "i16"   => Literal::new_s(v as i128,  16),
                                "u32"   => Literal::new_u(v,  32), "i32"   => Literal::new_s(v as i128,  32),
                                "u64"   => Literal::new_u(v,  64), "i64"   => Literal::new_s(v as i128,  64),
                                "u128"  => Literal::new_u(v, 128), "i128"  => Literal::new_s(v as i128, 128),
                                "usize" => Literal::new_u(v,   1), "isize" => Literal::new_s(v as i128,   1),
                                _ => return err("Unexpected integer suffix"),
                                }.into());
                            continue 'outer;
                        }
                        else if let Some(d) = c.to_digit(base) {
                            v *= base as u128;
                            v += d as u128;
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        else if c == '.' {
                            panic!("TODO: Floating point");
                        }
                        else {
                            break;
                        }
                    }
                    rv.push(Literal::new_u(v, 0).into());
                    continue 'outer;
                }
                // Punctuation?
                else if c as u32 <= 0xFF
                {
                    let mut start = match SYMS.iter().position(|v| v[0] == (c as u8))
                        {
                        Some(start) => start,
                        None => {
                            eprint!("Unknown operator character '{}'\r\n", c);
                            return err("Unknown operator")
                            },
                        };
                    let mut end = start+1;
                    while end < SYMS.len() && SYMS[end][0] == c as u8 {
                        end += 1;
                    }

                    let mut ofs = 1;
                    loop
                    {
                        let syms = &SYMS[start..end];
                        assert_eq!(ofs, syms[0].len(), "{:?}", syms[0]);
                        c = some_else!(it.consume() => break);
                        let step = match syms[1..].iter().position(|v| v[ofs] == (c as u8))
                            {
                            Some(s) => s+1,
                            None => break,
                            };
                        start += step;
                        end = start+1;
                        while end < syms.len() && syms[end][ofs] == c as u8 {
                            end += 1;
                        }
                        ofs += 1;
                    }
                    assert_eq!(SYMS[start].len(), ofs);
                    for (i,&c) in Iterator::enumerate(SYMS[start].iter())
                    {
                        let sep = if i == SYMS[start].len() - 1 { Spacing::Alone } else { Spacing::Joint };
                        rv.push(Punct::new(c as char, sep).into());
                    }
                }
                else
                {
                    return err("Unexpected character");
                }
            }
        }

        Ok(TokenStream {
            inner: rv,
            })
    }
}

#[cfg(test)]
mod tests {
    use crate::*;
    use ::std::str::FromStr;

    macro_rules! assert_tt_matches {
        ($have:expr, $exp:expr) => {{
            let e = $exp;
            let h = match $have
                {
                Some(h) => h,
                None => panic!("Unexpected end of stream (expecting {:?})", e),
                };
            assert!( crate::token_tree::tt_eq(&h, &e), "Expected {:?} got {:?}", e, h );
        }};
        ($have:expr) => {{
            match $have
            {
            Some(h) => panic!("Expected end of stream, found {:?}", h),
            None => {},
            }
        }};
    }

    #[test]
    fn lifetime()
    {
        let rv = TokenStream::from_str("foo::bar<'a>").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("foo", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("bar", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('<', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Punct::new('\'', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Ident::new("a", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('>', Spacing::Alone).into());
        assert_tt_matches!(it.next());
    }

    #[test]
    fn trailing_zero()
    {
        let rv = TokenStream::from_str("0").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Literal::new_u(0,0).into());
        assert_tt_matches!(it.next());
    }
    #[test]
    fn tuple_index_method()
    {
        let rv = TokenStream::from_str("key . 1 . def_id").expect("Failed to parse");
        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("key", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Literal::new_u(1,0).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("def_id", Span::call_site()).into());
        assert_tt_matches!(it.next());
    }
}<|endoftext|>


<commit_before>#[macro_use(s)]
extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
    aview1,
    arr3,
};

use itertools::assert_equal;
use itertools::{rev, enumerate};

#[test]
fn double_ended() {
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
    assert_equal(aview1(&[1, 2, 3]), &[1, 2, 3]);
    assert_equal(rev(aview1(&[1, 2, 3])), rev(&[1, 2, 3]));
}

#[test]
fn iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut data = [0; 24];
    for (i, elt) in enumerate(&mut data) {
        *elt = i as i32;
    }
    assert_equal(&a, &data);
    let mut it = a.iter();
    let mut ans = data.iter();
    assert_eq!(it.len(), ans.len());
    while ans.len() > 0 {
        assert_eq!(it.next(), ans.next());
        assert_eq!(it.len(), ans.len());
    }
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
}

#[test]
fn inner_iter_corner_cases() {
    let a0 = Array::zeros(());
    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);

    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn inner_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut len = 6;
    let mut it = a.inner_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}

#[test]
fn outer_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows.clone());

    let mut found_rows_rev = Vec::new();
    for sub in b.outer_iter().rev() {
        for row in sub.into_outer_iter().rev() {
            found_rows_rev.push(row);
        }
    }
    found_rows_rev.reverse();
    assert_eq!(&found_rows, &found_rows_rev);

    // Test a case where strides are negative instead
    let mut c = Array::zeros((2, 3, 2));
    let mut cv = c.slice_mut(s![..;-1, ..;-1, ..;-1]);
    cv.assign(&a);
    assert_eq!(&a, &cv);
    assert_equal(cv.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in cv.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    println!("{:#?}", found_rows);
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn axis_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.axis_iter(1),
                 vec![a.subview(1, 0),
                      a.subview(1, 1),
                      a.subview(1, 2)]);
}

#[test]
fn outer_iter_corner_cases() {
    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn outer_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter_mut(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter_mut() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn axis_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut a = a.to_owned();

    for mut subview in a.axis_iter_mut(1) {
        subview[[0, 0]] = 42;
    }

    let b = arr3(&[[[42, 1],
                    [42, 3],
                    [42, 5]],
                   [[6, 7],
                    [8, 9],
                    [10, 11]]]);
    assert_eq!(a, b);
}

#[test]
fn axis_chunks_iter() {
    let a = Array::from_iter(0..24);
    let a = a.reshape((2, 6, 2));

    let it = a.axis_chunks_iter(1, 2);
    assert_equal(it,
                 vec![arr3(&[[[0, 1], [2, 3]], [[12, 13], [14, 15]]]),
                      arr3(&[[[4, 5], [6, 7]], [[16, 17], [18, 19]]]),
                      arr3(&[[[8, 9], [10, 11]], [[20, 21], [22, 23]]])]);

    let a = Array::from_iter(0..28);
    let a = a.reshape((2, 7, 2));

    let it = a.axis_chunks_iter(1, 2);
    assert_equal(it,
                 vec![arr3(&[[[0, 1], [2, 3]], [[14, 15], [16, 17]]]),
                      arr3(&[[[4, 5], [6, 7]], [[18, 19], [20, 21]]]),
                      arr3(&[[[8, 9], [10, 11]], [[22, 23], [24, 25]]]),
                      arr3(&[[[12, 13]], [[26, 27]]])]);

    let it = a.axis_chunks_iter(1, 2).rev();
    assert_equal(it,
                 vec![arr3(&[[[12, 13]], [[26, 27]]]),
                      arr3(&[[[8, 9], [10, 11]], [[22, 23], [24, 25]]]),
                      arr3(&[[[4, 5], [6, 7]], [[18, 19], [20, 21]]]),
                      arr3(&[[[0, 1], [2, 3]], [[14, 15], [16, 17]]])]);
}

#[test]
fn axis_chunks_iter_mut() {
    let a = Array::from_iter(0..24);
    let mut a = a.reshape((2, 6, 2));

    let mut it = a.axis_chunks_iter_mut(1, 2);
    let mut col0 = it.next().unwrap();
    col0[[0, 0, 0]] = 42;
    assert_eq!(col0, arr3(&[[[42, 1], [2, 3]], [[12, 13], [14, 15]]]));
}

#[test]
fn outer_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((4, 3, 2));
    let mut len = 4;
    let mut it = a.outer_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    // now try the double ended case
    let mut it = a.outer_iter();
    it.next_back();
    let mut len = 3;
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    let mut it = a.outer_iter();
    it.next();
    let mut len = 3;
    while len > 0 {
        it.next_back();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}
<commit_msg>chunks iter: add tests for size >= dim length<commit_after>#[macro_use(s)]
extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
    aview1,
    arr3,
};

use itertools::assert_equal;
use itertools::{rev, enumerate};

#[test]
fn double_ended() {
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
    assert_equal(aview1(&[1, 2, 3]), &[1, 2, 3]);
    assert_equal(rev(aview1(&[1, 2, 3])), rev(&[1, 2, 3]));
}

#[test]
fn iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut data = [0; 24];
    for (i, elt) in enumerate(&mut data) {
        *elt = i as i32;
    }
    assert_equal(&a, &data);
    let mut it = a.iter();
    let mut ans = data.iter();
    assert_eq!(it.len(), ans.len());
    while ans.len() > 0 {
        assert_eq!(it.next(), ans.next());
        assert_eq!(it.len(), ans.len());
    }
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
}

#[test]
fn inner_iter_corner_cases() {
    let a0 = Array::zeros(());
    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);

    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn inner_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut len = 6;
    let mut it = a.inner_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}

#[test]
fn outer_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows.clone());

    let mut found_rows_rev = Vec::new();
    for sub in b.outer_iter().rev() {
        for row in sub.into_outer_iter().rev() {
            found_rows_rev.push(row);
        }
    }
    found_rows_rev.reverse();
    assert_eq!(&found_rows, &found_rows_rev);

    // Test a case where strides are negative instead
    let mut c = Array::zeros((2, 3, 2));
    let mut cv = c.slice_mut(s![..;-1, ..;-1, ..;-1]);
    cv.assign(&a);
    assert_eq!(&a, &cv);
    assert_equal(cv.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in cv.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    println!("{:#?}", found_rows);
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn axis_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.axis_iter(1),
                 vec![a.subview(1, 0),
                      a.subview(1, 1),
                      a.subview(1, 2)]);
}

#[test]
fn outer_iter_corner_cases() {
    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn outer_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter_mut(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter_mut() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn axis_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut a = a.to_owned();

    for mut subview in a.axis_iter_mut(1) {
        subview[[0, 0]] = 42;
    }

    let b = arr3(&[[[42, 1],
                    [42, 3],
                    [42, 5]],
                   [[6, 7],
                    [8, 9],
                    [10, 11]]]);
    assert_eq!(a, b);
}

#[test]
fn axis_chunks_iter() {
    let a = Array::from_iter(0..24);
    let a = a.reshape((2, 6, 2));

    let it = a.axis_chunks_iter(1, 2);
    assert_equal(it,
                 vec![arr3(&[[[0, 1], [2, 3]], [[12, 13], [14, 15]]]),
                      arr3(&[[[4, 5], [6, 7]], [[16, 17], [18, 19]]]),
                      arr3(&[[[8, 9], [10, 11]], [[20, 21], [22, 23]]])]);

    let a = Array::from_iter(0..28);
    let a = a.reshape((2, 7, 2));

    let it = a.axis_chunks_iter(1, 2);
    assert_equal(it,
                 vec![arr3(&[[[0, 1], [2, 3]], [[14, 15], [16, 17]]]),
                      arr3(&[[[4, 5], [6, 7]], [[18, 19], [20, 21]]]),
                      arr3(&[[[8, 9], [10, 11]], [[22, 23], [24, 25]]]),
                      arr3(&[[[12, 13]], [[26, 27]]])]);

    let it = a.axis_chunks_iter(1, 2).rev();
    assert_equal(it,
                 vec![arr3(&[[[12, 13]], [[26, 27]]]),
                      arr3(&[[[8, 9], [10, 11]], [[22, 23], [24, 25]]]),
                      arr3(&[[[4, 5], [6, 7]], [[18, 19], [20, 21]]]),
                      arr3(&[[[0, 1], [2, 3]], [[14, 15], [16, 17]]])]);

    let it = a.axis_chunks_iter(1, 7);
    assert_equal(it, vec![a.view()]);

    let it = a.axis_chunks_iter(1, 9);
    assert_equal(it, vec![a.view()]);
}

#[test]
fn axis_chunks_iter_mut() {
    let a = Array::from_iter(0..24);
    let mut a = a.reshape((2, 6, 2));

    let mut it = a.axis_chunks_iter_mut(1, 2);
    let mut col0 = it.next().unwrap();
    col0[[0, 0, 0]] = 42;
    assert_eq!(col0, arr3(&[[[42, 1], [2, 3]], [[12, 13], [14, 15]]]));
}

#[test]
fn outer_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((4, 3, 2));
    let mut len = 4;
    let mut it = a.outer_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    // now try the double ended case
    let mut it = a.outer_iter();
    it.next_back();
    let mut len = 3;
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    let mut it = a.outer_iter();
    it.next();
    let mut len = 3;
    while len > 0 {
        it.next_back();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}
<|endoftext|>


<commit_before>extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
    aview1,
};

use itertools::assert_equal;
use itertools::{rev, enumerate};

#[test]
fn double_ended() {
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
    assert_equal(aview1(&[1, 2, 3]), &[1, 2, 3]);
    assert_equal(rev(aview1(&[1, 2, 3])), rev(&[1, 2, 3]));
}

#[test]
fn iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut data = [0; 24];
    for (i, elt) in enumerate(&mut data) {
        *elt = i as i32;
    }
    assert_equal(&a, &data);
    let mut it = a.iter();
    let mut ans = data.iter();
    assert_eq!(it.len(), ans.len());
    while ans.len() > 0 {
        assert_eq!(it.next(), ans.next());
        assert_eq!(it.len(), ans.len());
    }
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
}

#[test]
fn inner_iter_corner_cases() {
    let a0 = Array::zeros(());
    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);

    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn inner_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut len = 6;
    let mut it = a.inner_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}

#[test]
fn outer_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows.clone());

    let mut found_rows_rev = Vec::new();
    for sub in b.outer_iter().rev() {
        for row in sub.into_outer_iter().rev() {
            found_rows_rev.push(row);
        }
    }
    found_rows_rev.reverse();
    assert_eq!(&found_rows, &found_rows_rev);
}

#[test]
fn outer_iter_corner_cases() {
    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn outer_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter_mut(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter_mut() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn outer_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((4, 3, 2));
    let mut len = 4;
    let mut it = a.outer_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    // now try the double ended case
    let mut it = a.outer_iter();
    it.next_back();
    let mut len = 3;
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    let mut it = a.outer_iter();
    it.next();
    let mut len = 3;
    while len > 0 {
        it.next_back();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}
<commit_msg>Add another testcase for outer_iter<commit_after>#[macro_use(s)]
extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
    aview1,
};

use itertools::assert_equal;
use itertools::{rev, enumerate};

#[test]
fn double_ended() {
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
    assert_equal(aview1(&[1, 2, 3]), &[1, 2, 3]);
    assert_equal(rev(aview1(&[1, 2, 3])), rev(&[1, 2, 3]));
}

#[test]
fn iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut data = [0; 24];
    for (i, elt) in enumerate(&mut data) {
        *elt = i as i32;
    }
    assert_equal(&a, &data);
    let mut it = a.iter();
    let mut ans = data.iter();
    assert_eq!(it.len(), ans.len());
    while ans.len() > 0 {
        assert_eq!(it.next(), ans.next());
        assert_eq!(it.len(), ans.len());
    }
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
}

#[test]
fn inner_iter_corner_cases() {
    let a0 = Array::zeros(());
    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);

    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn inner_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((2, 3, 4));
    let mut len = 6;
    let mut it = a.inner_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}

#[test]
fn outer_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows.clone());

    let mut found_rows_rev = Vec::new();
    for sub in b.outer_iter().rev() {
        for row in sub.into_outer_iter().rev() {
            found_rows_rev.push(row);
        }
    }
    found_rows_rev.reverse();
    assert_eq!(&found_rows, &found_rows_rev);

    // Test a case where strides are negative instead
    let mut c = Array::zeros((2, 3, 2));
    let mut cv = c.slice_mut(s![..;-1, ..;-1, ..;-1]);
    cv.assign(&a);
    assert_eq!(&a, &cv);
    assert_equal(cv.outer_iter(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in cv.outer_iter() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    println!("{:#?}", found_rows);
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn outer_iter_corner_cases() {
    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.outer_iter(),
                 vec![aview1(&[]); 3]);
}

#[test]
fn outer_iter_mut() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.outer_iter_mut(),
                 vec![a.subview(0, 0), a.subview(0, 1)]);

    let mut found_rows = Vec::new();
    for sub in b.outer_iter_mut() {
        for row in sub.into_outer_iter() {
            found_rows.push(row);
        }
    }
    assert_equal(a.inner_iter(), found_rows);
}

#[test]
fn outer_iter_size_hint() {
    // Check that the size hint is correctly computed
    let a = Array::from_iter(0..24).reshape((4, 3, 2));
    let mut len = 4;
    let mut it = a.outer_iter();
    assert_eq!(it.len(), len);
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    // now try the double ended case
    let mut it = a.outer_iter();
    it.next_back();
    let mut len = 3;
    while len > 0 {
        it.next();
        len -= 1;
        assert_eq!(it.len(), len);
    }

    let mut it = a.outer_iter();
    it.next();
    let mut len = 3;
    while len > 0 {
        it.next_back();
        len -= 1;
        assert_eq!(it.len(), len);
    }
}
<|endoftext|>