<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// TODO
// This example doesnt work yet!
// Maybe it's an issue with the example maybe it's an issue with vulkano.
// I checked it in so we can use it to test the issue.
// Delete this comment when the example is working

#[macro_use]
extern crate vulkano;
#[macro_use]
extern crate vulkano_shader_derive;
extern crate winit;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;

use vulkano::buffer::BufferUsage;
use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::command_buffer::DynamicState;
use vulkano::device::Device;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::Subpass;
use vulkano::instance::Instance;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::viewport::Viewport;
use vulkano::swapchain;
use vulkano::swapchain::PresentMode;
use vulkano::swapchain::SurfaceTransform;
use vulkano::swapchain::Swapchain;
use vulkano::swapchain::AcquireError;
use vulkano::swapchain::SwapchainCreationError;
use vulkano::sync::now;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("failed to create Vulkan instance")
    };

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let mut events_loop = winit::EventsLoop::new();
    let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();

    let queue = physical.queue_families().find(|&q| {
        q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
    }).expect("couldn't find a graphical queue family");
    let (device, mut queues) = {
        let device_ext = vulkano::device::DeviceExtensions {
            khr_swapchain: true,
            .. vulkano::device::DeviceExtensions::none()
        };

        Device::new(physical, physical.supported_features(), &device_ext,
                    [(queue, 0.5)].iter().cloned()).expect("failed to create device")
    };
    let queue = queues.next().unwrap();

    let mut dimensions;

    let (mut swapchain, mut images) = {
        let caps = surface.capabilities(physical)
                         .expect("failed to get surface capabilities");

        dimensions = caps.current_extent.unwrap_or([1024, 768]);
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();
        let format = caps.supported_formats[0].0;

        Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
                       dimensions, 1, caps.supported_usage_flags, &queue,
                       SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
                       None).expect("failed to create swapchain")
    };

    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex { position: [f32; 2] }
        impl_vertex!(Vertex, position);

        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [
            Vertex { position: [-0.5, -0.25] },
            Vertex { position: [0.0, 0.5] },
            Vertex { position: [0.25, -0.1] },
            Vertex { position: [0.25, -0.5] },
        ].iter().cloned()).expect("failed to create buffer")
    };

    mod vs {
        #[derive(VulkanoShader)]
        #[ty = "vertex"]
        #[src = "
#version 450

layout(location = 0) in vec2 position;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}
"]
        #[allow(dead_code)]
        struct Dummy;
    }

    mod fs {
        #[derive(VulkanoShader)]
        #[ty = "fragment"]
        #[src = "
#version 450

layout(location = 0) out vec4 f_color;

void main() {
    f_color = vec4(1.0, 0.0, 0.0, 1.0);
}
"]
        #[allow(dead_code)]
        struct Dummy;
    }

    mod tcs {
        #[derive(VulkanoShader)]
        #[ty = "tess_ctrl"]
        #[src = "
#version 450

layout (vertices = 3) out;

void main(void)
{
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
    "]
        #[allow(dead_code)]
        struct Dummy;
    }

    mod tes {
        #[derive(VulkanoShader)]
        #[ty = "tess_eval"]
        #[src = "
#version 450

layout(quads, equal_spacing, cw) in;

void main(void)
{
    gl_Position = gl_in[0].gl_Position;
}
    "]
        #[allow(dead_code)]
        struct Dummy;
    }

    let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
    let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
    let tcs = tcs::Shader::load(device.clone()).expect("failed to create shader module");
    let tes = tes::Shader::load(device.clone()).expect("failed to create shader module");

    let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
        attachments: {
            color: {
                load: Clear,
                store: Store,
                format: swapchain.format(),
                samples: 1,
            }
        },
        pass: {
            color: [color],
            depth_stencil: {}
        }
    ).unwrap());

    let pipeline = Arc::new(GraphicsPipeline::start()
        .vertex_input_single_buffer()
        .vertex_shader(vs.main_entry_point(), ())
        .tessellation_shaders(tcs.main_entry_point(), (), tes.main_entry_point(), ())
        .patch_list(4)
        .viewports_dynamic_scissors_irrelevant(1)
        .fragment_shader(fs.main_entry_point(), ())
        .render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
        .build(device.clone())
        .unwrap());

    let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
    let mut recreate_swapchain = false;
    let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
    let mut dynamic_state = DynamicState {
        line_width: None,
        viewports: Some(vec![Viewport {
            origin: [0.0, 0.0],
            dimensions: [dimensions[0] as f32, dimensions[1] as f32],
            depth_range: 0.0 .. 1.0,
        }]),
        scissors: None,
    };

    loop {
        previous_frame_end.cleanup_finished();
        if recreate_swapchain {
            dimensions = surface.capabilities(physical)
                        .expect("failed to get surface capabilities")
                        .current_extent.unwrap();

            let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
                Ok(r) => r,
                Err(SwapchainCreationError::UnsupportedDimensions) => {
                    continue;
                },
                Err(err) => panic!("{:?}", err)
            };

            swapchain = new_swapchain;
            images = new_images;
            framebuffers = None;
            dynamic_state.viewports = Some(vec![Viewport {
                origin: [0.0, 0.0],
                dimensions: [dimensions[0] as f32, dimensions[1] as f32],
                depth_range: 0.0 .. 1.0,
            }]);

            recreate_swapchain = false;
        }

        if framebuffers.is_none() {
            framebuffers = Some(images.iter().map(|image| {
                Arc::new(Framebuffer::start(render_pass.clone())
                         .add(image.clone()).unwrap()
                         .build().unwrap())
            }).collect::<Vec<_>>());
        }

        let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
                                                                              None) {
            Ok(r) => r,
            Err(AcquireError::OutOfDate) => {
                recreate_swapchain = true;
                continue;
            },
            Err(err) => panic!("{:?}", err)
        };

        let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
            .begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
                               vec![[0.0, 0.0, 1.0, 1.0].into()])
            .unwrap()
            .draw(pipeline.clone(),
                  &dynamic_state,
                  vertex_buffer.clone(), (), ())
            .unwrap()
            .end_render_pass()
            .unwrap()
            .build().unwrap();

        let future = previous_frame_end.join(acquire_future)
            .then_execute(queue.clone(), command_buffer).unwrap()
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence_and_flush();

        match future {
            Ok(future) => {
                previous_frame_end = Box::new(future) as Box<_>;
            }
            Err(vulkano::sync::FlushError::OutOfDate) => {
                recreate_swapchain = true;
                previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
            Err(e) => {
                println!("{:?}", e);
                previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
        }

        let mut done = false;
        events_loop.poll_events(|ev| {
            match ev {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
                _ => ()
            }
        });
        if done { return }
    }
}
<commit_msg>Implement tessellation example (#1025)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// Some relevant documentation:
// *    Tessellation overview           https://www.khronos.org/opengl/wiki/Tessellation
// *    Tessellation Control Shader     https://www.khronos.org/opengl/wiki/Tessellation_Control_Shader
// *    Tessellation Evaluation Shader  https://www.khronos.org/opengl/wiki/Tessellation_Evaluation_Shader
// *    Tessellation real-world usage 1 http://ogldev.atspace.co.uk/www/tutorial30/tutorial30.html
// *    Tessellation real-world usage 2 http://prideout.net/blog/?p=48

// Notable elements of this example:
// *    tessellation control shader and a tessellation evaluation shader
// *    tessellation_shaders(..), patch_list(3) and polygon_mode_line() are called on the pipeline builder

#[macro_use]
extern crate vulkano;
#[macro_use]
extern crate vulkano_shader_derive;
extern crate winit;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;

use vulkano::buffer::BufferUsage;
use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::command_buffer::DynamicState;
use vulkano::device::Device;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::Subpass;
use vulkano::instance::Instance;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::viewport::Viewport;
use vulkano::swapchain;
use vulkano::swapchain::PresentMode;
use vulkano::swapchain::SurfaceTransform;
use vulkano::swapchain::Swapchain;
use vulkano::swapchain::AcquireError;
use vulkano::swapchain::SwapchainCreationError;
use vulkano::sync::now;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("failed to create Vulkan instance")
    };

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let mut events_loop = winit::EventsLoop::new();
    let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();

    let queue = physical.queue_families().find(|&q| {
        q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
    }).expect("couldn't find a graphical queue family");
    let (device, mut queues) = {
        let device_ext = vulkano::device::DeviceExtensions {
            khr_swapchain: true,
            .. vulkano::device::DeviceExtensions::none()
        };

        Device::new(physical, physical.supported_features(), &device_ext,
                    [(queue, 0.5)].iter().cloned()).expect("failed to create device")
    };
    let queue = queues.next().unwrap();

    let mut dimensions;

    let (mut swapchain, mut images) = {
        let caps = surface.capabilities(physical)
                         .expect("failed to get surface capabilities");

        dimensions = caps.current_extent.unwrap_or([1024, 768]);
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();
        let format = caps.supported_formats[0].0;

        Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
                       dimensions, 1, caps.supported_usage_flags, &queue,
                       SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
                       None).expect("failed to create swapchain")
    };

    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex { position: [f32; 2] }
        impl_vertex!(Vertex, position);

        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [
            Vertex { position: [-0.5,  -0.25] },
            Vertex { position: [ 0.0,   0.5] },
            Vertex { position: [ 0.25, -0.1] },
            Vertex { position: [ 0.9,   0.9] },
            Vertex { position: [ 0.9,   0.8] },
            Vertex { position: [ 0.8,   0.8] },
            Vertex { position: [-0.9,   0.9] },
            Vertex { position: [-0.7,   0.6] },
            Vertex { position: [-0.5,   0.9] },
        ].iter().cloned()).expect("failed to create buffer")
    };

    mod vs {
        #[derive(VulkanoShader)]
        #[ty = "vertex"]
        #[src = "
#version 450

layout(location = 0) in vec2 position;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}
"]
        #[allow(dead_code)]
        struct Dummy;
    }

    mod tcs {
        #[derive(VulkanoShader)]
        #[ty = "tess_ctrl"]
        #[src = "
#version 450

layout (vertices = 3) out; // a value of 3 means a patch consists of a single triangle

void main(void)
{
    // save the position of the patch, so the tes can access it
    // We could define our own output variables for this,
    // but gl_out is handily provided.
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

    gl_TessLevelInner[0] = 10; // many triangles are generated in the center
    gl_TessLevelOuter[0] = 1;  // no triangles are generated for this edge
    gl_TessLevelOuter[1] = 10; // many triangles are generated for this edge
    gl_TessLevelOuter[2] = 10; // many triangles are generated for this edge
    // gl_TessLevelInner[1] = only used when tes uses layout(quads)
    // gl_TessLevelOuter[3] = only used when tes uses layout(quads)
}
    "]
        #[allow(dead_code)]
        struct Dummy;
    }

    // PG
    // There is a stage in between tcs and tes called Primitive Generation (PG)
    // Shaders cannot be defined for it.
    // It takes gl_TessLevelInner and gl_TessLevelOuter and uses them to generate positions within
    // the patch and pass them to tes via gl_TessCoord.
    //
    // When tes uses layout(triangles) then gl_TessCoord is in barrycentric coordinates.
    // if layout(quads) is used then gl_TessCoord is in cartesian coordinates.
    // Barrycentric coordinates are of the form (x, y, z) where x + y + z = 1
    // and the values x, y and z represent the distance from a vertex of the triangle.
    // http://mathworld.wolfram.com/BarycentricCoordinates.html

    mod tes {
        #[derive(VulkanoShader)]
        #[ty = "tess_eval"]
        #[src = "
#version 450

layout(triangles, equal_spacing, cw) in;

void main(void)
{
    // retreive the vertex positions set by the tcs
    vec4 vert_x = gl_in[0].gl_Position;
    vec4 vert_y = gl_in[1].gl_Position;
    vec4 vert_z = gl_in[2].gl_Position;

    // convert gl_TessCoord from barycentric coordinates to cartesian coordinates
    gl_Position = vec4(
        gl_TessCoord.x * vert_x.x + gl_TessCoord.y * vert_y.x + gl_TessCoord.z * vert_z.x,
        gl_TessCoord.x * vert_x.y + gl_TessCoord.y * vert_y.y + gl_TessCoord.z * vert_z.y,
        gl_TessCoord.x * vert_x.z + gl_TessCoord.y * vert_y.z + gl_TessCoord.z * vert_z.z,
        1.0
    );
}
    "]
        #[allow(dead_code)]
        struct Dummy;
    }

    mod fs {
        #[derive(VulkanoShader)]
        #[ty = "fragment"]
        #[src = "
#version 450

layout(location = 0) out vec4 f_color;

void main() {
    f_color = vec4(1.0, 1.0, 1.0, 1.0);
}
"]
        #[allow(dead_code)]
        struct Dummy;
    }

    let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
    let tcs = tcs::Shader::load(device.clone()).expect("failed to create shader module");
    let tes = tes::Shader::load(device.clone()).expect("failed to create shader module");
    let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");

    let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
        attachments: {
            color: {
                load: Clear,
                store: Store,
                format: swapchain.format(),
                samples: 1,
            }
        },
        pass: {
            color: [color],
            depth_stencil: {}
        }
    ).unwrap());

    let pipeline = Arc::new(GraphicsPipeline::start()
        .vertex_input_single_buffer()
        .vertex_shader(vs.main_entry_point(), ())
        // Actually use the tessellation shaders.
        .tessellation_shaders(tcs.main_entry_point(), (), tes.main_entry_point(), ())
        // use PrimitiveTopology::PathList(3)
        // Use a vertices_per_patch of 3, because we want to convert one triangle into lots of
        // little ones. A value of 4 would convert a rectangle into lots of little triangles.
        .patch_list(3)
        // Enable line mode so we can see the generated vertices.
        .polygon_mode_line()
        .viewports_dynamic_scissors_irrelevant(1)
        .fragment_shader(fs.main_entry_point(), ())
        .render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
        .build(device.clone())
        .unwrap());

    let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
    let mut recreate_swapchain = false;
    let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
    let mut dynamic_state = DynamicState {
        line_width: None,
        viewports: Some(vec![Viewport {
            origin: [0.0, 0.0],
            dimensions: [dimensions[0] as f32, dimensions[1] as f32],
            depth_range: 0.0 .. 1.0,
        }]),
        scissors: None,
    };

    loop {
        previous_frame_end.cleanup_finished();
        if recreate_swapchain {
            dimensions = surface.capabilities(physical)
                        .expect("failed to get surface capabilities")
                        .current_extent.unwrap();

            let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
                Ok(r) => r,
                Err(SwapchainCreationError::UnsupportedDimensions) => {
                    continue;
                },
                Err(err) => panic!("{:?}", err)
            };

            swapchain = new_swapchain;
            images = new_images;
            framebuffers = None;
            dynamic_state.viewports = Some(vec![Viewport {
                origin: [0.0, 0.0],
                dimensions: [dimensions[0] as f32, dimensions[1] as f32],
                depth_range: 0.0 .. 1.0,
            }]);

            recreate_swapchain = false;
        }

        if framebuffers.is_none() {
            framebuffers = Some(images.iter().map(|image| {
                Arc::new(Framebuffer::start(render_pass.clone())
                         .add(image.clone()).unwrap()
                         .build().unwrap())
            }).collect::<Vec<_>>());
        }

        let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
                                                                              None) {
            Ok(r) => r,
            Err(AcquireError::OutOfDate) => {
                recreate_swapchain = true;
                continue;
            },
            Err(err) => panic!("{:?}", err)
        };

        let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
            .begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
                               vec![[0.0, 0.0, 0.0, 1.0].into()])
            .unwrap()
            .draw(pipeline.clone(),
                  &dynamic_state,
                  vertex_buffer.clone(), (), ())
            .unwrap()
            .end_render_pass()
            .unwrap()
            .build().unwrap();

        let future = previous_frame_end.join(acquire_future)
            .then_execute(queue.clone(), command_buffer).unwrap()
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence_and_flush();

        match future {
            Ok(future) => {
                previous_frame_end = Box::new(future) as Box<_>;
            }
            Err(vulkano::sync::FlushError::OutOfDate) => {
                recreate_swapchain = true;
                previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
            Err(e) => {
                println!("{:?}", e);
                previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
        }

        let mut done = false;
        events_loop.poll_events(|ev| {
            match ev {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
                _ => ()
            }
        });
        if done { return }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum Error {
    NotEnoughPinsLeft,
    GameComplete,
}

struct Frame {
    rolls: Vec<u16>,
    remaining_pins: u16,
    final_frame: bool,
    fill_ball: bool,
}

impl Frame {
    fn new(final_frame: bool) -> Self {
        Frame {
            rolls: Vec::new(),
            remaining_pins: 10,
            final_frame,
            fill_ball: false,
        }
    }

    fn roll(&mut self, pins: u16) -> Result<bool, Error> {
        if pins > self.remaining_pins {
            return Err(Error::NotEnoughPinsLeft);
        }

        self.remaining_pins -= pins;
        self.rolls.push(pins);

        if self.final_frame {
            if self.remaining_pins == 0 && self.rolls.len() < 3 {
                self.fill_ball = true;
                self.remaining_pins = 10;
            }

            Ok(self.rolls.len() > 2 || (self.rolls.len() > 1 && !self.fill_ball))
        } else {
            Ok(self.remaining_pins == 0 || self.rolls.len() > 1)
        }
    }

    fn score<'a, I>(&self, next_rolls: I) -> u16
    where
        I: IntoIterator<Item = &'a u16>,
    {
        let mut score = self.rolls.iter().sum();

        if score == 10 {
            score += next_rolls
                .into_iter()
                .take(3 - self.rolls.len())
                .sum::<u16>();
        }

        score
    }

    fn rolls(&self) -> impl Iterator<Item = &u16> {
        self.rolls.iter()
    }
}

pub struct BowlingGame {
    frames: Vec<Frame>,
    current_frame: Option<usize>,
}

impl BowlingGame {
    pub fn new() -> Self {
        BowlingGame {
            frames: (0..10).map(|i| Frame::new(i == 9)).collect(),
            current_frame: Some(0),
        }
    }

    pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
        if let Some(frame) = self.current_frame {
            if self.frames[frame].roll(pins)? {
                self.current_frame = if frame == 9 { None } else { Some(frame + 1) }
            }

            Ok(())
        } else {
            Err(Error::GameComplete)
        }
    }

    pub fn score(&self) -> Option<u16> {
        if let Some(_) = self.current_frame {
            None
        } else {
            Some(
                self.frames
                    .iter()
                    .enumerate()
                    .map(|(index, frame)| {
                        frame.score(self.frames.iter().skip(index + 1).flat_map(Frame::rolls))
                    })
                    .sum::<u16>(),
            )
        }
    }
}
<commit_msg>Update Bowling to use impl Trait<commit_after>#[derive(Debug, PartialEq)]
pub enum Error {
    NotEnoughPinsLeft,
    GameComplete,
}

struct Frame {
    rolls: Vec<u16>,
    remaining_pins: u16,
    final_frame: bool,
    fill_ball: bool,
}

impl Frame {
    fn new(final_frame: bool) -> Self {
        Frame {
            rolls: Vec::new(),
            remaining_pins: 10,
            final_frame,
            fill_ball: false,
        }
    }

    fn roll(&mut self, pins: u16) -> Result<bool, Error> {
        if pins > self.remaining_pins {
            return Err(Error::NotEnoughPinsLeft);
        }

        self.remaining_pins -= pins;
        self.rolls.push(pins);

        if self.final_frame {
            if self.remaining_pins == 0 && self.rolls.len() < 3 {
                self.fill_ball = true;
                self.remaining_pins = 10;
            }

            Ok(self.rolls.len() > 2 || (self.rolls.len() > 1 && !self.fill_ball))
        } else {
            Ok(self.remaining_pins == 0 || self.rolls.len() > 1)
        }
    }

    fn score<'a>(&self, next_rolls: impl IntoIterator<Item = &'a u16>) -> u16 {
        let mut score = self.rolls.iter().sum();

        if score == 10 {
            score += next_rolls
                .into_iter()
                .take(3 - self.rolls.len())
                .sum::<u16>();
        }

        score
    }

    fn rolls(&self) -> impl Iterator<Item = &u16> {
        self.rolls.iter()
    }
}

pub struct BowlingGame {
    frames: Vec<Frame>,
    current_frame: Option<usize>,
}

impl BowlingGame {
    pub fn new() -> Self {
        BowlingGame {
            frames: (0..10).map(|i| Frame::new(i == 9)).collect(),
            current_frame: Some(0),
        }
    }

    pub fn roll(&mut self, pins: u16) -> Result<(), Error> {
        if let Some(frame) = self.current_frame {
            if self.frames[frame].roll(pins)? {
                self.current_frame = if frame == 9 { None } else { Some(frame + 1) }
            }

            Ok(())
        } else {
            Err(Error::GameComplete)
        }
    }

    pub fn score(&self) -> Option<u16> {
        if let Some(_) = self.current_frame {
            None
        } else {
            Some(
                self.frames
                    .iter()
                    .enumerate()
                    .map(|(index, frame)| {
                        frame.score(self.frames.iter().skip(index + 1).flat_map(Frame::rolls))
                    })
                    .sum::<u16>(),
            )
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate walkdir;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::fs::DirBuilder;
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};
use walkdir::WalkDir;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // Get the SDK path from the ANDROID_HOME env.
    let sdk_path = env::var("ANDROID_HOME").ok().expect("Please set the ANDROID_HOME environment variable");
    let sdk_path = Path::new(&sdk_path);

    // Get the NDK path from NDK_HOME env.
    let ndk_path = env::var("NDK_HOME").ok().expect("Please set the NDK_HOME environment variable");
    let ndk_path = Path::new(&ndk_path);

    // Get the target android platform from ANDROID_PLATFORM env. Expecting "android-{version}"
    let android_platform = env::var("ANDROID_PLATFORM")
        .ok()
        .expect("Please set the ANDROID_PLATFORM environment variable");

    // Get the standalone NDK path from NDK_STANDALONE env.
    //  let standalone_path = env::var("NDK_STANDALONE").ok().unwrap_or("/opt/ndk_standalone".to_string());
    //  let standalone_path = Path::new(&standalone_path);

    let debug = passthrough.contains(&"-d".to_string());

    // Set the build directory that will contain all the necessary files to create the apk
    let directory = args.root_path.join("support").join("android").join("apk");
    let resdir = args.root_path.join("resources/");

    // executing ndk-build
    env::set_var("V", "1");
    if debug {
        env::set_var("NDK_DEBUG", "1");
        env::set_var("APP_OPTIM", "0");
    } else {
        // Overrides android:debuggable propery in the .xml file.
        env::set_var("APP_OPTIM", "1");
    }

    // Copy libservo.so into the jni folder for inclusion in the build
    // TODO: pass/detect target architecture
    {
        let source = &args.target_path.join("libservo.so");
        let target_dir = &directory.join("jni").join("armeabi");
        let _ = DirBuilder::new().recursive(true).create(target_dir);
        let target = target_dir.join("libmain.so");
        println!("Copying the file {:?} to {:?}", source, target);
        fs::copy(source, target).unwrap();
    }

    let ndkcmd = Command::new(ndk_path.join("ndk-build"))
                              .arg("-B")
                              .stdout(Stdio::inherit())
                              .stderr(Stdio::inherit())
                              .current_dir(directory.clone())
                              .status();
    if ndkcmd.is_err() || ndkcmd.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ndk-build`, or missing program.");
        process::exit(1);
    }

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        let target = &directory.join("libs").join("armeabi").join(name);
        println!("Copying the file {:?} to {:?}", name, target);
        fs::copy(path, target).unwrap();
    }

    // Copy over the resources
    let cpcmd = Command::new("cp")
                             .arg("-R")
                             .arg(&resdir)
                             .arg(&directory.join("assets"))
                             .stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .current_dir(directory.clone())
                             .status();
    if cpcmd.is_err() || cpcmd.unwrap().code().unwrap() != 0 {
        println!("Error while copying files from the resources dir to the assets dir");
        process::exit(1);
    }

    // Update the project
    let androidcmd = Command::new(sdk_path.join("tools").join("android"))
                                  .arg("update")
                                  .arg("project")
                                  .arg("--name")
                                  .arg("Servo")
                                  .arg("--target")
                                  .arg(&android_platform)
                                  .arg("--path")
                                  .arg(".")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
    if androidcmd.is_err() || androidcmd.unwrap().code().unwrap() != 0 {
        println!("Error while updating the project with the android command");
        process::exit(1);
    }

    // Build the APK
    let mut antcmd = Command::new("ant");
    if debug {
        antcmd.arg("debug");
    } else {
        antcmd.arg("release");
    }
    let antresult = antcmd
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .current_dir(directory.clone())
        .status();
    if antresult.is_err() || antresult.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ant`, or missing program.");
        process::exit(1);
    }

    // Copying apk file to the requested output
    // Release builds also need to be signed. For now, we use a simple debug
    // signing key.
    if debug {
        fs::copy(&directory.join("bin").join("Servo-debug.apk"),
                 &args.output).unwrap();
    } else {
        let keystore_dir = env::home_dir().expect("Please have a home directory");
        let keystore_dir = Path::new(&keystore_dir).join(".keystore");
        let keytoolcmd = Command::new("keytool")
                                  .arg("-list")
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-alias")
                                  .arg("androiddebugkey")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
        if keytoolcmd.is_err() || keytoolcmd.unwrap().code().unwrap() != 0 {
            let keytoolcreatecmd = Command::new("keytool")
                                  .arg("-genkeypair")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-alias")
                                  .arg("androiddebugkey")
                                  .arg("-keypass")
                                  .arg("android")
                                  .arg("-dname")
                                  .arg("CN=Android Debug,O=Android,C=US")
                                  .arg("-keyalg")
                                  .arg("RSA")
                                  .arg("-validity")
                                  .arg("365")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
            if keytoolcreatecmd.is_err() ||
               keytoolcreatecmd.unwrap().code().unwrap() != 0 {
                   println!("Error while using `keytool` to create the debug keystore.");
                   process::exit(1);
               }
        }

        let jarsigncmd = Command::new("jarsigner")
                                  .arg("-digestalg")
                                  .arg("SHA1")
                                  .arg("-sigalg")
                                  .arg("MD5withRSA")
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .arg(&directory.join("bin").join("Servo-release-unsigned.apk"))
                                  .arg("androiddebugkey")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
        if jarsigncmd.is_err() || jarsigncmd.unwrap().code().unwrap() != 0 {
            println!("Error while using `jarsign` to sign the APK.");
            process::exit(1);
        }

        fs::copy(&directory.join("bin").join("Servo-release-unsigned.apk"),
                 &args.output).unwrap();
    }

}

struct Args {
    output: PathBuf,
    root_path: PathBuf,
    target_path: PathBuf,
    shared_libraries: HashSet<String>,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_root_path = None;
    let mut result_target_path = None;
    let mut result_shared_libraries = HashSet::new();
    let mut result_passthrough = Vec::new();

    let args = env::args();
    let mut args = args.skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument"),
                    root_path: result_root_path.expect("Could not find -r enlistment root argument"),
                    target_path: result_target_path.expect("Could not find -t target path argument"),
                    shared_libraries: result_shared_libraries,
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match &*arg {
            "-o" => {
                result_output = Some(PathBuf::from(args.next().expect("-o must be followed by the output name")));
            },
            "-r" => {
                result_root_path =
                    Some(PathBuf::from(args.next().expect("-r must be followed by the enlistment root directory")));
            },
            "-t" => {
                result_target_path =
                    Some(PathBuf::from(args.next().expect("-t must be followed by the target output directory")));
            },
            "-l" => {
                let name = args.next().expect("-l must be followed by a library name");
                result_shared_libraries.insert(vec!["lib", &name, ".so"].concat());

                // Also pass these through.
                result_passthrough.push(arg);
                result_passthrough.push(name);
            }
            _ => {
                if arg.starts_with("-l") {
                    result_shared_libraries.insert(vec!["lib", &arg[2..], ".so"].concat());
                }
                result_passthrough.push(arg)
            }
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, PathBuf> {
    let mut native_shared_libs: HashMap<String, PathBuf> = HashMap::new();

    // Add requested .so files
    for dir_entry in WalkDir::new(&args.target_path) {
        let dir_entry = dir_entry.unwrap();
        let path = dir_entry.path();

        match (path.file_name(), path.extension()) {
            (Some(file_name), Some(extension)) => {
                let file_name = file_name.to_str().unwrap();

                if file_name.starts_with("lib") &&
                    extension == "so" &&
                    args.shared_libraries.contains(file_name) {
                        println!("Adding the file {:?}", file_name);
                        native_shared_libs.insert(file_name.to_string(), path.to_path_buf().clone());
                        break;
                }
            }
            _ => {}
        }
    }

    native_shared_libs
}
<commit_msg>Auto merge of #14528 - mmatyas:android_cppruntime, r=larsbergstrom<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate walkdir;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::fs::DirBuilder;
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};
use walkdir::WalkDir;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let mut native_shared_libs = find_native_libs(&args);

    // Get the SDK path from the ANDROID_HOME env.
    let sdk_path = env::var("ANDROID_HOME").ok().expect("Please set the ANDROID_HOME environment variable");
    let sdk_path = Path::new(&sdk_path);

    // Get the NDK path from NDK_HOME env.
    let ndk_path = env::var("NDK_HOME").ok().expect("Please set the NDK_HOME environment variable");
    let ndk_path = Path::new(&ndk_path);

    // Get the target android platform from ANDROID_PLATFORM env. Expecting "android-{version}"
    let android_platform = env::var("ANDROID_PLATFORM")
        .ok()
        .expect("Please set the ANDROID_PLATFORM environment variable");

    // Add the C++ runtime .so
    {
        let libcpp_base_path = ndk_path.join("sources").join("cxx-stl").join("llvm-libc++").join("libs");
        let libcpp_filename = "libc++_shared.so";
        let libcpp_path = libcpp_base_path.join("armeabi").join(libcpp_filename);
        native_shared_libs.insert(libcpp_filename.to_string(), libcpp_path);
    }

    // Get the standalone NDK path from NDK_STANDALONE env.
    //  let standalone_path = env::var("NDK_STANDALONE").ok().unwrap_or("/opt/ndk_standalone".to_string());
    //  let standalone_path = Path::new(&standalone_path);

    let debug = passthrough.contains(&"-d".to_string());

    // Set the build directory that will contain all the necessary files to create the apk
    let directory = args.root_path.join("support").join("android").join("apk");
    let resdir = args.root_path.join("resources/");

    // executing ndk-build
    env::set_var("V", "1");
    if debug {
        env::set_var("NDK_DEBUG", "1");
        env::set_var("APP_OPTIM", "0");
    } else {
        // Overrides android:debuggable propery in the .xml file.
        env::set_var("APP_OPTIM", "1");
    }

    // Copy libservo.so into the jni folder for inclusion in the build
    // TODO: pass/detect target architecture
    {
        let source = &args.target_path.join("libservo.so");
        let target_dir = &directory.join("jni").join("armeabi");
        let _ = DirBuilder::new().recursive(true).create(target_dir);
        let target = target_dir.join("libmain.so");
        println!("Copying the file {:?} to {:?}", source, target);
        fs::copy(source, target).unwrap();
    }

    let ndkcmd = Command::new(ndk_path.join("ndk-build"))
                              .arg("-B")
                              .stdout(Stdio::inherit())
                              .stderr(Stdio::inherit())
                              .current_dir(directory.clone())
                              .status();
    if ndkcmd.is_err() || ndkcmd.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ndk-build`, or missing program.");
        process::exit(1);
    }

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        let target = &directory.join("libs").join("armeabi").join(name);
        println!("Copying the file {:?} to {:?}", name, target);
        fs::copy(path, target).unwrap();
    }

    // Copy over the resources
    let cpcmd = Command::new("cp")
                             .arg("-R")
                             .arg(&resdir)
                             .arg(&directory.join("assets"))
                             .stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .current_dir(directory.clone())
                             .status();
    if cpcmd.is_err() || cpcmd.unwrap().code().unwrap() != 0 {
        println!("Error while copying files from the resources dir to the assets dir");
        process::exit(1);
    }

    // Update the project
    let androidcmd = Command::new(sdk_path.join("tools").join("android"))
                                  .arg("update")
                                  .arg("project")
                                  .arg("--name")
                                  .arg("Servo")
                                  .arg("--target")
                                  .arg(&android_platform)
                                  .arg("--path")
                                  .arg(".")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
    if androidcmd.is_err() || androidcmd.unwrap().code().unwrap() != 0 {
        println!("Error while updating the project with the android command");
        process::exit(1);
    }

    // Build the APK
    let mut antcmd = Command::new("ant");
    if debug {
        antcmd.arg("debug");
    } else {
        antcmd.arg("release");
    }
    let antresult = antcmd
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .current_dir(directory.clone())
        .status();
    if antresult.is_err() || antresult.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ant`, or missing program.");
        process::exit(1);
    }

    // Copying apk file to the requested output
    // Release builds also need to be signed. For now, we use a simple debug
    // signing key.
    if debug {
        fs::copy(&directory.join("bin").join("Servo-debug.apk"),
                 &args.output).unwrap();
    } else {
        let keystore_dir = env::home_dir().expect("Please have a home directory");
        let keystore_dir = Path::new(&keystore_dir).join(".keystore");
        let keytoolcmd = Command::new("keytool")
                                  .arg("-list")
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-alias")
                                  .arg("androiddebugkey")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
        if keytoolcmd.is_err() || keytoolcmd.unwrap().code().unwrap() != 0 {
            let keytoolcreatecmd = Command::new("keytool")
                                  .arg("-genkeypair")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-alias")
                                  .arg("androiddebugkey")
                                  .arg("-keypass")
                                  .arg("android")
                                  .arg("-dname")
                                  .arg("CN=Android Debug,O=Android,C=US")
                                  .arg("-keyalg")
                                  .arg("RSA")
                                  .arg("-validity")
                                  .arg("365")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
            if keytoolcreatecmd.is_err() ||
               keytoolcreatecmd.unwrap().code().unwrap() != 0 {
                   println!("Error while using `keytool` to create the debug keystore.");
                   process::exit(1);
               }
        }

        let jarsigncmd = Command::new("jarsigner")
                                  .arg("-digestalg")
                                  .arg("SHA1")
                                  .arg("-sigalg")
                                  .arg("MD5withRSA")
                                  .arg("-storepass")
                                  .arg("android")
                                  .arg("-keystore")
                                  .arg(&keystore_dir)
                                  .arg(&directory.join("bin").join("Servo-release-unsigned.apk"))
                                  .arg("androiddebugkey")
                                  .stdout(Stdio::inherit())
                                  .stderr(Stdio::inherit())
                                  .current_dir(directory.clone())
                                  .status();
        if jarsigncmd.is_err() || jarsigncmd.unwrap().code().unwrap() != 0 {
            println!("Error while using `jarsign` to sign the APK.");
            process::exit(1);
        }

        fs::copy(&directory.join("bin").join("Servo-release-unsigned.apk"),
                 &args.output).unwrap();
    }

}

struct Args {
    output: PathBuf,
    root_path: PathBuf,
    target_path: PathBuf,
    shared_libraries: HashSet<String>,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_root_path = None;
    let mut result_target_path = None;
    let mut result_shared_libraries = HashSet::new();
    let mut result_passthrough = Vec::new();

    let args = env::args();
    let mut args = args.skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument"),
                    root_path: result_root_path.expect("Could not find -r enlistment root argument"),
                    target_path: result_target_path.expect("Could not find -t target path argument"),
                    shared_libraries: result_shared_libraries,
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match &*arg {
            "-o" => {
                result_output = Some(PathBuf::from(args.next().expect("-o must be followed by the output name")));
            },
            "-r" => {
                result_root_path =
                    Some(PathBuf::from(args.next().expect("-r must be followed by the enlistment root directory")));
            },
            "-t" => {
                result_target_path =
                    Some(PathBuf::from(args.next().expect("-t must be followed by the target output directory")));
            },
            "-l" => {
                let name = args.next().expect("-l must be followed by a library name");
                result_shared_libraries.insert(vec!["lib", &name, ".so"].concat());

                // Also pass these through.
                result_passthrough.push(arg);
                result_passthrough.push(name);
            }
            _ => {
                if arg.starts_with("-l") {
                    result_shared_libraries.insert(vec!["lib", &arg[2..], ".so"].concat());
                }
                result_passthrough.push(arg)
            }
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, PathBuf> {
    let mut native_shared_libs: HashMap<String, PathBuf> = HashMap::new();

    // Add requested .so files
    for dir_entry in WalkDir::new(&args.target_path) {
        let dir_entry = dir_entry.unwrap();
        let path = dir_entry.path();

        match (path.file_name(), path.extension()) {
            (Some(file_name), Some(extension)) => {
                let file_name = file_name.to_str().unwrap();

                if file_name.starts_with("lib") &&
                    extension == "so" &&
                    args.shared_libraries.contains(file_name) {
                        println!("Adding the file {:?}", file_name);
                        native_shared_libs.insert(file_name.to_string(), path.to_path_buf().clone());
                        break;
                }
            }
            _ => {}
        }
    }

    native_shared_libs
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

local_data_key!(MSG_QUEUE: RefCell<Vec<::Msg>>)

/// Pop and return the oldest message left in the message queue.
pub fn pop_msg() -> Option<::Msg> {
    if MSG_QUEUE.get().is_none() { return None; }
    MSG_QUEUE.get().unwrap().borrow_mut().shift()
}

/// Insert a new message to the back of the message queue.
pub fn push_msg(msg: ::Msg) {
    if MSG_QUEUE.get().is_none() {
        MSG_QUEUE.replace(Some(RefCell::new(vec![msg])));
    } else {
        MSG_QUEUE.get().unwrap().borrow_mut().push(msg);
    }
}

// TODO: A println! style formatting msg! macro that emits text messages and
// optionally supports special game system stuff like entity name
// interpolation and string coloring.
<commit_msg>Fix deprecated method<commit_after>use std::cell::RefCell;

local_data_key!(MSG_QUEUE: RefCell<Vec<::Msg>>)

/// Pop and return the oldest message left in the message queue.
pub fn pop_msg() -> Option<::Msg> {
    if MSG_QUEUE.get().is_none() { return None; }
    MSG_QUEUE.get().unwrap().borrow_mut().remove(0)
}

/// Insert a new message to the back of the message queue.
pub fn push_msg(msg: ::Msg) {
    if MSG_QUEUE.get().is_none() {
        MSG_QUEUE.replace(Some(RefCell::new(vec![msg])));
    } else {
        MSG_QUEUE.get().unwrap().borrow_mut().push(msg);
    }
}

// TODO: A println! style formatting msg! macro that emits text messages and
// optionally supports special game system stuff like entity name
// interpolation and string coloring.
<|endoftext|>


<commit_before>use std::fmt::Display;

pub mod str;
mod slice;
pub mod error;

/// The result type used internally in the parser.
///
/// You'll only need this if implementing the `Parse*` traits for a custom input
/// type. The public API of a parser adapts errors to `std::result::Result`.
#[derive(Clone)]
pub enum RuleResult<T> {
    Matched(usize, T),
    Failed,
}

/// A type that can be used as input to a parser.
pub trait Parse {
    type PositionRepr: Display;
    fn start<'input>(&'input self) -> usize;
    fn position_repr<'input>(&'input self, p: usize) -> Self::PositionRepr;
}

/// A parser input type supporting the `[...]` syntax.
pub trait ParseElem: Parse {
    /// Type of a single atomic element of the input, for example a character or token
    type Element;

    /// Get the element at `pos`, or `Failed` if past end of input.
    fn parse_elem(&self, pos: usize) -> RuleResult<Self::Element>;
}

/// A parser input type supporting the `"literal"` syntax.
pub trait ParseLiteral: Parse {
    /// Attempt to match the `literal` string at `pos`, returning whether it
    /// matched or failed.
    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()>;
}

/// A parser input type supporting the `$()` syntax.
pub trait ParseSlice<'input>: Parse {
    /// Type of a slice of the input.
    type Slice;

    /// Get a slice of input.
    fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice;
}

<commit_msg>Derive more Implementations for RuleResult<commit_after>use std::fmt::Display;

pub mod str;
mod slice;
pub mod error;

/// The result type used internally in the parser.
///
/// You'll only need this if implementing the `Parse*` traits for a custom input
/// type. The public API of a parser adapts errors to `std::result::Result`.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum RuleResult<T> {
    Matched(usize, T),
    Failed,
}

/// A type that can be used as input to a parser.
pub trait Parse {
    type PositionRepr: Display;
    fn start<'input>(&'input self) -> usize;
    fn position_repr<'input>(&'input self, p: usize) -> Self::PositionRepr;
}

/// A parser input type supporting the `[...]` syntax.
pub trait ParseElem: Parse {
    /// Type of a single atomic element of the input, for example a character or token
    type Element;

    /// Get the element at `pos`, or `Failed` if past end of input.
    fn parse_elem(&self, pos: usize) -> RuleResult<Self::Element>;
}

/// A parser input type supporting the `"literal"` syntax.
pub trait ParseLiteral: Parse {
    /// Attempt to match the `literal` string at `pos`, returning whether it
    /// matched or failed.
    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()>;
}

/// A parser input type supporting the `$()` syntax.
pub trait ParseSlice<'input>: Parse {
    /// Type of a slice of the input.
    type Slice;

    /// Get a slice of input.
    fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice;
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

type Time = usize;
type Position = usize;

#[derive(Debug)]
struct Disk {
    n_positions: usize,
    initial: Position,
}

impl Disk {
    fn at(&self, t: Time) -> Position {
        (t + self.initial) % self.n_positions
    }
}

impl std::str::FromStr for Disk {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref DISK_RE: Regex =
                Regex::new(r"Disc #\d+ has (\d+) positions; at time=0, it is at position (\d+).").unwrap();
        }
        if let Some(cap) = DISK_RE.captures(s) {
            Ok(Disk {
                n_positions: cap[1].parse().expect("bad regex"),
                initial: cap[2].parse().expect("bad regex"),
            })
        } else {
            Err("invalid disk".into())
        }
    }
}

fn gcd(mut a: usize, mut b: usize) -> usize {
    while b != 0 {
        let temp = b;
        b = a % b;
        a = temp;
    }
    a
}

fn lcm(a: usize, b: usize) -> usize {
    a * b / gcd(a, b)
}

fn solve(disks: &[Disk]) -> Time {
    if disks.is_empty() {
        return 0;
    }
    let mut current_period = disks[0].n_positions;
    let mut time = disks[0].n_positions - disks[0].initial - 1;
    for (disk_num, disk) in disks.iter().enumerate().map(|(idx, disk)| (idx + 1, disk)) {
        while disk.at(time + disk_num) != 0 {
            time += current_period;
        }
        current_period = lcm(current_period, disk.n_positions);
    }
    time
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 15")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("disks")
            .index(1)
            .short("f")
            .long("disks")
            .help("file containing disks for puzzle. Reads from stdin otherwise")
            .takes_value(true))
        .get_matches();
    let source = matches.value_of_os("disks");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let disks: Vec<Disk> = input.lines()
        .map(|line| line.trim().parse())
        .collect::<Result<_, _>>()
        .unwrap_or_else(|err| panic!("Error parsing disks: {}", err));
    println!("part 1 solution: drop at t = {} seconds", solve(&disks))
}

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

    #[test]
    fn example() {
        let disks = [Disk {
                         n_positions: 5,
                         initial: 4,
                     },
                     Disk {
                         n_positions: 2,
                         initial: 1,
                     }];
        assert_eq!(solve(&disks), 5);
    }
}
<commit_msg>Day 15 part 2<commit_after>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

type Time = usize;
type Position = usize;

#[derive(Debug)]
struct Disk {
    n_positions: usize,
    initial: Position,
}

impl Disk {
    fn at(&self, t: Time) -> Position {
        (t + self.initial) % self.n_positions
    }
}

impl std::str::FromStr for Disk {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref DISK_RE: Regex =
                Regex::new(
                    r"Disc #\d+ has (\d+) positions; at time=0, it is at position (\d+).")
                .unwrap();
        }
        if let Some(cap) = DISK_RE.captures(s) {
            Ok(Disk {
                n_positions: cap[1].parse().expect("bad regex"),
                initial: cap[2].parse().expect("bad regex"),
            })
        } else {
            Err("invalid disk".into())
        }
    }
}

fn gcd(mut a: usize, mut b: usize) -> usize {
    while b != 0 {
        let temp = b;
        b = a % b;
        a = temp;
    }
    a
}

fn lcm(a: usize, b: usize) -> usize {
    a * b / gcd(a, b)
}

fn solve(disks: &[Disk]) -> Time {
    if disks.is_empty() {
        return 0;
    }
    let mut current_period = disks[0].n_positions;
    let mut time = disks[0].n_positions - disks[0].initial - 1;
    for (disk_num, disk) in disks.iter().enumerate().map(|(idx, disk)| (idx + 1, disk)) {
        while disk.at(time + disk_num) != 0 {
            time += current_period;
        }
        current_period = lcm(current_period, disk.n_positions);
    }
    time
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 15")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("disks")
            .index(1)
            .short("f")
            .long("disks")
            .help("file containing disks for puzzle. Reads from stdin otherwise")
            .takes_value(true))
        .get_matches();
    let source = matches.value_of_os("disks");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let mut disks: Vec<Disk> = input.lines()
        .map(|line| line.trim().parse())
        .collect::<Result<_, _>>()
        .unwrap_or_else(|err| panic!("Error parsing disks: {}", err));
    println!("part 1 solution: drop at t = {} seconds", solve(&disks));
    disks.push(Disk {
        n_positions: 11,
        initial: 0,
    });
    println!("part 2 solution: drop at t = {} seconds", solve(&disks));
}

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

    #[test]
    fn example() {
        let disks = [Disk {
                         n_positions: 5,
                         initial: 4,
                     },
                     Disk {
                         n_positions: 2,
                         initial: 1,
                     }];
        assert_eq!(solve(&disks), 5);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate perl_xs;
#[macro_use]
extern crate perl_sys;

use perl_xs::{ AV, IV, NV };

xs! {
    package XSBench::RS;

    sub rs_sum_loop(ctx, array: AV) {
        let mut sum = 0.0;
        for i in 0..array.top_index() + 1 {
            if let Some(val) = array.fetch(i) {
                sum += val;
            }
        }
        sum
    }

    sub rs_sum_iter(ctx, array: AV) {
        array.iter().map(|v| v.unwrap_or(0.0)).sum::<NV>()
    }

    sub rs_gcd(ctx, a: IV, b: IV) {
        let mut a = a;
        let mut b = b;
        while b > 0 {
            let t = a;
            a = b;
            b = t % b;
        }

        let res = if a < 0 {
            -a
        } else {
            a
        };

        res
    }
}

xs! {
    bootstrap boot_XSBench__RS;
    use self;
}
<commit_msg>Fix regression on nightly.<commit_after>#[macro_use]
extern crate perl_xs;
#[macro_use]
extern crate perl_sys;

use perl_xs::{ AV, IV, NV };

xs! {
    package XSBench::RS;

    sub rs_sum_loop(ctx, array: AV) {
        let mut sum = 0.0;
        for i in 0..array.top_index() + 1 {
            if let Some(val) = array.fetch::<NV>(i) {
                sum += val;
            }
        }
        sum
    }

    sub rs_sum_iter(ctx, array: AV) {
        array.iter().map(|v| v.unwrap_or(0.0)).sum::<NV>()
    }

    sub rs_gcd(ctx, a: IV, b: IV) {
        let mut a = a;
        let mut b = b;
        while b > 0 {
            let t = a;
            a = b;
            b = t % b;
        }

        let res = if a < 0 {
            -a
        } else {
            a
        };

        res
    }
}

xs! {
    bootstrap boot_XSBench__RS;
    use self;
}
<|endoftext|>


<commit_before>use hdr_histogram::simple_hdr_histogram::*;

#[derive(Debug)]
#[derive(Clone)]
pub struct HistogramIterationValue {
    value_iterated_to: u64,
    value_iterated_from: u64,
    count_at_value_iterated_to: u64,
    count_added_in_this_iteration_step: u64,
    total_count_to_this_value: u64,
    total_value_to_this_value: u64,
    percentile: f64,
    percentile_level_iterated_to: f64,
    integer_to_double_value_conversion_ratio: f64,
}

impl Default for HistogramIterationValue {
    fn default() -> HistogramIterationValue {
        HistogramIterationValue {
            value_iterated_to: 0,
            value_iterated_from: 0,
            count_at_value_iterated_to: 0,
            count_added_in_this_iteration_step: 0,
            total_count_to_this_value: 0,
            total_value_to_this_value: 0,
            percentile: 0.0,
            percentile_level_iterated_to: 0.0,
            integer_to_double_value_conversion_ratio: 0.0,
        }
    }
}

impl HistogramIterationValue {
    fn reset(mut self) {
        self = HistogramIterationValue { ..Default::default() };
    }
    fn set(&mut self,
            value_iterated_to: u64,
            value_iterated_from: u64,
            count_at_value_iterated_to: u64,
            count_added_in_this_iteration_step: u64,
            total_count_to_this_value: u64,
            total_value_to_this_value: u64,
            percentile: f64,
            percentile_level_iterated_to: f64,
            integer_to_double_value_conversion_ratio: f64) {
        self.value_iterated_to = value_iterated_to;
        self.value_iterated_from = value_iterated_from;
        self.count_at_value_iterated_to = count_at_value_iterated_to;
        self.count_added_in_this_iteration_step = count_added_in_this_iteration_step;
        self.total_count_to_this_value = total_count_to_this_value;
        self.total_value_to_this_value = total_value_to_this_value;
        self.percentile = percentile;
        self.percentile_level_iterated_to = percentile_level_iterated_to;
        self.integer_to_double_value_conversion_ratio = integer_to_double_value_conversion_ratio;
    }
}

#[derive(Debug)]
pub struct BaseHistogramIterator<T: HistogramCount> {
    histogram: SimpleHdrHistogram<T>,
    saved_histogram_total_raw_count: u64,
    current_index: usize,
    current_value_at_index: u64,
    next_value_at_index: u64,
    prev_value_iterated_to: u64,
    total_count_to_prev_index: u64,
    total_count_to_current_index: u64,
    total_value_to_current_index: u64,
    array_total_count: u64,
    count_at_this_value: T,
    fresh_sub_bucket: bool,
    current_iteration_value: HistogramIterationValue,
    integer_to_double_value_conversion_ratio: f64,
    visited_index: i32,
}

impl<T: HistogramCount> BaseHistogramIterator<T> {
    fn reset_iterator(mut self, histogram: SimpleHdrHistogram<T>) {
        self.histogram = histogram;
        self.saved_histogram_total_raw_count = self.histogram.get_count();
        self.array_total_count = self.histogram.get_count();
        self.integer_to_double_value_conversion_ratio = 0.0; //TODO should be self.histogram.integer_to_double_value_conversion_ratio
        self.current_index = 0;
        self.current_value_at_index = 0;
        self.next_value_at_index = 1 << self.histogram.get_unit_magnitude();
        self.prev_value_iterated_to = 0;
        self.total_count_to_prev_index = 0;
        self.total_count_to_current_index = 0;
        self.total_value_to_current_index = 0;
        self.count_at_this_value = T::zero();
        self.fresh_sub_bucket = true;
        self.visited_index = -1;
        self.current_iteration_value.reset();
    }
    fn exhausted_sub_buckets(&self) -> bool {
        self.current_index >= 1000 //TODO should be self.histogram.get_counts_array_length()
    }

    pub fn reached_iter_level(&self) -> bool {
        let current_count = match self.histogram.get_count_at_index(self.current_index) {
            Err(err) => 0,
            Ok(the_count) => match the_count.to_u64() {
                None => 0,
                Some(the_val) => the_val
            }
        };
        (current_count != 0) && (self.visited_index != self.current_index as i32)
    }

    pub fn get_value_iterated_to(&self) -> u64 {
        self.histogram.highest_equivalent_value(self.current_value_at_index)
    }

    pub fn increment_iteration_level(&mut self) {
        self.visited_index = self.current_index as i32;
    }

    pub fn increment_sub_bucket(&mut self) {
        self.fresh_sub_bucket = true;
        self.current_index += 1;
        self.current_value_at_index = self.histogram.value_from_index(self.current_index);
        self.next_value_at_index = self.histogram.value_from_index(self.current_index + 1);
    }

    pub fn get_percentile_iterated_to(total_count_to_current_index: f64, array_total_count: f64) -> f64 {
        (100.0 * total_count_to_current_index) / array_total_count
    }
}

impl <T: HistogramCount> Iterator for BaseHistogramIterator<T> {

    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //combine Java's hasNext() and next()
        //first check if has next
        if self.histogram.get_count() != self.saved_histogram_total_raw_count {
            //in Java, this threw a ConcurrentModificationException
            return None
        }
        if self.total_count_to_current_index >= self.array_total_count {
            //this means hasNext() returns false
            return None
        }

        fn get_percentile_iterated_to(total_count_to_current_index: f64, array_total_count: f64) -> f64 {
            (100.0 * total_count_to_current_index) / array_total_count
        }

        while ! self.exhausted_sub_buckets() {
            self.count_at_this_value = match self.histogram.get_count_at_index(self.current_index) {
                Ok(val) => val,
                Err(err) => T::zero()
            };
            if self.fresh_sub_bucket {
                let count_u64 = match self.count_at_this_value.to_u64() {
                    None => 0,
                    Some(the_long) => the_long
                };
                self.total_count_to_current_index += count_u64;
                let highest_eq_val = self.histogram.highest_equivalent_value(self.current_value_at_index);
                self.total_value_to_current_index += count_u64 * highest_eq_val;
                self.fresh_sub_bucket = false;
                if self.reached_iter_level() {
                    let value_iterated_to = self.get_value_iterated_to();
                    self.current_iteration_value.set(
                        value_iterated_to,
                        self.prev_value_iterated_to,
                        match self.count_at_this_value.to_u64() {
                            None => 0,
                            Some(the_count) => the_count
                        },
                        (self.total_count_to_current_index - self.total_count_to_prev_index),
                        self.total_count_to_current_index,
                        self.total_value_to_current_index,
                        ((100.0 * self.total_count_to_current_index as f64) / self.array_total_count as f64),
                        get_percentile_iterated_to(self.total_count_to_current_index as f64, self.array_total_count as f64),
                        self.integer_to_double_value_conversion_ratio);
                    self.prev_value_iterated_to = value_iterated_to;
                    self.total_count_to_prev_index = self.total_count_to_current_index;
                    self.increment_iteration_level();

                    if self.histogram.get_count() != self.saved_histogram_total_raw_count {
                        //TODO this is bad
                    }

                    return Some(self.current_iteration_value.clone())
                }
                self.increment_sub_bucket();
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct RecordedValuesIterator {
    //TODO
    visited_index: u32,
}

impl Iterator for RecordedValuesIterator {
    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //TODO
        None
    }
}<commit_msg>remove dupe code<commit_after>use hdr_histogram::simple_hdr_histogram::*;

#[derive(Debug)]
#[derive(Clone)]
pub struct HistogramIterationValue {
    value_iterated_to: u64,
    value_iterated_from: u64,
    count_at_value_iterated_to: u64,
    count_added_in_this_iteration_step: u64,
    total_count_to_this_value: u64,
    total_value_to_this_value: u64,
    percentile: f64,
    percentile_level_iterated_to: f64,
    integer_to_double_value_conversion_ratio: f64,
}

impl Default for HistogramIterationValue {
    fn default() -> HistogramIterationValue {
        HistogramIterationValue {
            value_iterated_to: 0,
            value_iterated_from: 0,
            count_at_value_iterated_to: 0,
            count_added_in_this_iteration_step: 0,
            total_count_to_this_value: 0,
            total_value_to_this_value: 0,
            percentile: 0.0,
            percentile_level_iterated_to: 0.0,
            integer_to_double_value_conversion_ratio: 0.0,
        }
    }
}

impl HistogramIterationValue {
    fn reset(mut self) {
        self = HistogramIterationValue { ..Default::default() };
    }
    fn set(&mut self,
            value_iterated_to: u64,
            value_iterated_from: u64,
            count_at_value_iterated_to: u64,
            count_added_in_this_iteration_step: u64,
            total_count_to_this_value: u64,
            total_value_to_this_value: u64,
            percentile: f64,
            percentile_level_iterated_to: f64,
            integer_to_double_value_conversion_ratio: f64) {
        self.value_iterated_to = value_iterated_to;
        self.value_iterated_from = value_iterated_from;
        self.count_at_value_iterated_to = count_at_value_iterated_to;
        self.count_added_in_this_iteration_step = count_added_in_this_iteration_step;
        self.total_count_to_this_value = total_count_to_this_value;
        self.total_value_to_this_value = total_value_to_this_value;
        self.percentile = percentile;
        self.percentile_level_iterated_to = percentile_level_iterated_to;
        self.integer_to_double_value_conversion_ratio = integer_to_double_value_conversion_ratio;
    }
}

#[derive(Debug)]
pub struct BaseHistogramIterator<T: HistogramCount> {
    histogram: SimpleHdrHistogram<T>,
    saved_histogram_total_raw_count: u64,
    current_index: usize,
    current_value_at_index: u64,
    next_value_at_index: u64,
    prev_value_iterated_to: u64,
    total_count_to_prev_index: u64,
    total_count_to_current_index: u64,
    total_value_to_current_index: u64,
    array_total_count: u64,
    count_at_this_value: T,
    fresh_sub_bucket: bool,
    current_iteration_value: HistogramIterationValue,
    integer_to_double_value_conversion_ratio: f64,
    visited_index: i32,
}

impl<T: HistogramCount> BaseHistogramIterator<T> {
    fn reset_iterator(mut self, histogram: SimpleHdrHistogram<T>) {
        self.histogram = histogram;
        self.saved_histogram_total_raw_count = self.histogram.get_count();
        self.array_total_count = self.histogram.get_count();
        self.integer_to_double_value_conversion_ratio = 0.0; //TODO should be self.histogram.integer_to_double_value_conversion_ratio
        self.current_index = 0;
        self.current_value_at_index = 0;
        self.next_value_at_index = 1 << self.histogram.get_unit_magnitude();
        self.prev_value_iterated_to = 0;
        self.total_count_to_prev_index = 0;
        self.total_count_to_current_index = 0;
        self.total_value_to_current_index = 0;
        self.count_at_this_value = T::zero();
        self.fresh_sub_bucket = true;
        self.visited_index = -1;
        self.current_iteration_value.reset();
    }
    fn exhausted_sub_buckets(&self) -> bool {
        self.current_index >= 1000 //TODO should be self.histogram.get_counts_array_length()
    }

    pub fn reached_iter_level(&self) -> bool {
        let current_count = match self.histogram.get_count_at_index(self.current_index) {
            Err(err) => 0,
            Ok(the_count) => match the_count.to_u64() {
                None => 0,
                Some(the_val) => the_val
            }
        };
        (current_count != 0) && (self.visited_index != self.current_index as i32)
    }

    pub fn get_value_iterated_to(&self) -> u64 {
        self.histogram.highest_equivalent_value(self.current_value_at_index)
    }

    pub fn increment_iteration_level(&mut self) {
        self.visited_index = self.current_index as i32;
    }

    pub fn increment_sub_bucket(&mut self) {
        self.fresh_sub_bucket = true;
        self.current_index += 1;
        self.current_value_at_index = self.histogram.value_from_index(self.current_index);
        self.next_value_at_index = self.histogram.value_from_index(self.current_index + 1);
    }
}

impl <T: HistogramCount> Iterator for BaseHistogramIterator<T> {

    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //combine Java's hasNext() and next()
        //first check if has next
        if self.histogram.get_count() != self.saved_histogram_total_raw_count {
            //in Java, this threw a ConcurrentModificationException
            return None
        }
        if self.total_count_to_current_index >= self.array_total_count {
            //this means hasNext() returns false
            return None
        }

        fn get_percentile_iterated_to(total_count_to_current_index: f64, array_total_count: f64) -> f64 {
            (100.0 * total_count_to_current_index) / array_total_count
        }

        while ! self.exhausted_sub_buckets() {
            self.count_at_this_value = match self.histogram.get_count_at_index(self.current_index) {
                Ok(val) => val,
                Err(err) => T::zero()
            };
            if self.fresh_sub_bucket {
                let count_u64 = match self.count_at_this_value.to_u64() {
                    None => 0,
                    Some(the_long) => the_long
                };
                self.total_count_to_current_index += count_u64;
                let highest_eq_val = self.histogram.highest_equivalent_value(self.current_value_at_index);
                self.total_value_to_current_index += count_u64 * highest_eq_val;
                self.fresh_sub_bucket = false;
                if self.reached_iter_level() {
                    let value_iterated_to = self.get_value_iterated_to();
                    self.current_iteration_value.set(
                        value_iterated_to,
                        self.prev_value_iterated_to,
                        match self.count_at_this_value.to_u64() {
                            None => 0,
                            Some(the_count) => the_count
                        },
                        (self.total_count_to_current_index - self.total_count_to_prev_index),
                        self.total_count_to_current_index,
                        self.total_value_to_current_index,
                        ((100.0 * self.total_count_to_current_index as f64) / self.array_total_count as f64),
                        get_percentile_iterated_to(self.total_count_to_current_index as f64, self.array_total_count as f64),
                        self.integer_to_double_value_conversion_ratio);
                    self.prev_value_iterated_to = value_iterated_to;
                    self.total_count_to_prev_index = self.total_count_to_current_index;
                    self.increment_iteration_level();

                    if self.histogram.get_count() != self.saved_histogram_total_raw_count {
                        //TODO this is bad
                    }

                    return Some(self.current_iteration_value.clone())
                }
                self.increment_sub_bucket();
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct RecordedValuesIterator {
    //TODO
    visited_index: u32,
}

impl Iterator for RecordedValuesIterator {
    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //TODO
        None
    }
}<|endoftext|>