<commit_before>extern crate num_cpus;

use std::sync::{Arc, Mutex, mpsc::{self, Sender, Receiver, TryRecvError}};
use std::thread::{self, JoinHandle};

use cgmath::prelude::*;
use cgmath::{Vector3, Vector4, Point3};

use glium;
use glium::{VertexBuffer, IndexBuffer, Surface, DrawParameters, Rect};
use glium::backend::Facade;
use glium::texture::{RawImage2d, Texture2d};

use camera::Camera;
use scene::Scene;
use bvh::BVHNode;
use triangle::Hit;
use vertex::Vertex;

pub trait Intersect<'a, H> {
    fn intersect(&'a self, ray: &Ray) -> Option<H>;
}

#[derive(Clone, Copy)]
pub struct Ray {
    pub orig: Point3<f32>,
    pub dir: Vector3<f32>,
    // For more efficient ray plane intersections
    pub reciprocal_dir: Vector3<f32>,
    pub length: f32,
}

impl Ray {
    fn new(orig: Point3<f32>, dir: Vector3<f32>, length: f32) -> Ray {
        let reciprocal_dir = 1.0 / dir;
        Ray { orig, dir, reciprocal_dir, length }
    }
}

#[allow(dead_code)]
pub struct RenderCoordinator {
    width: u32,
    height: u32,
    max_iterations: Option<u32>,
    end_x: u32,
    start_y: u32,
    end_y: u32,
    iteration: u32,
}

impl RenderCoordinator {
    fn new(width: u32, height: u32, max_iterations: Option<u32>) -> RenderCoordinator {
        RenderCoordinator {
            width, height, max_iterations,
            end_x: 0, start_y: 0, end_y: 0, iteration: 0
        }
    }

    fn next_block(&mut self) -> Option<Rect> {
        let block_height = 50;
        let block_width = 50;
        if let Some(max) = self.max_iterations {
            if self.iteration > max {
                return None;
            }
        }
        if self.end_y >= self.height && self.end_x >= self.width {
            self.iteration += 1;
            self.start_y = 0;
            self.end_y = block_width.min(self.height);
            self.end_x = 0;
        } else if self.end_x >= self.width {
            self.start_y = self.end_y;
            self.end_y = (self.start_y + block_height).min(self.height);
            self.end_x = 0;
        }
        let start_x = self.end_x;
        self.end_x = (start_x + block_width).min(self.width);
        Some (
            Rect {
                left: start_x,
                bottom: self.start_y,
                width: self.end_x - start_x,
                height: self.end_y - self.start_y,
            }
        )
    }
}

pub struct PTRenderer {
    shader: glium::Program,
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u32>,
    texture: Texture2d,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    receive_channel: Option<Receiver<(Rect, Vec<f32>)>>,
    send_channels: Vec<Sender<()>>,
    thread_handles: Vec<JoinHandle<()>>,
}

impl PTRenderer {
    pub fn new<F: Facade>(facade: &F) -> PTRenderer {
        let vertices = vec!(
            Vertex { pos: [-1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 0.0] },
            Vertex { pos: [1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 0.0] },
            Vertex { pos: [1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 1.0] },
            Vertex { pos: [-1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 1.0] },
        );
        let vertex_buffer = VertexBuffer::new(facade, &vertices)
            .expect("Failed to create vertex buffer!");
        let indices = vec!(0, 1, 2, 0, 2, 3);
        let index_buffer = IndexBuffer::new(facade,
                                            glium::index::PrimitiveType::TrianglesList,
                                            &indices)
            .expect("Failed to create index buffer!");
        let texture = Texture2d::empty(facade, 0, 0).expect("Failed to create trace texture!");

        // Image shader
        let vertex_shader_src = include_str!("shaders/image.vert");
        let fragment_shader_src = include_str!("shaders/image.frag");
        let shader = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        PTRenderer { shader, vertex_buffer, index_buffer, texture,
                     coordinator: Arc::new(Mutex::new(RenderCoordinator::new(0, 0, None))),
                     receive_channel: None,
                     send_channels: Vec::new(),
                     thread_handles: Vec::new(),
        }
    }

    pub fn start_render<F: Facade>(&mut self, facade: &F, scene: &Arc<Scene>, camera: &Camera,
                                    width: u32, height: u32) {
        let empty_image = RawImage2d::from_raw_rgb(vec![0.0; (3 * width * height) as usize], (width, height));
        self.texture = Texture2d::new(facade, empty_image).expect("Failed to upload traced image!");
        self.coordinator = Arc::new(Mutex::new(RenderCoordinator::new(width, height, None)));
        let (thread_sender, main_receiver) = mpsc::channel();
        self.receive_channel = Some(main_receiver);
        for _ in 0..num_cpus::get_physical() {
            let sender = thread_sender.clone();
            let (main_sender, receiver) = mpsc::channel();
            self.send_channels.push(main_sender);
            let coordinator = self.coordinator.clone();
            let camera = camera.clone();
            let scene = scene.clone();
            let clip_to_world = (camera.get_camera_to_clip(width, height)
                                 * camera.get_world_to_camera()).invert()
                .expect("Non invertible world to clip");
            let handle = thread::spawn(move|| {
                let mut node_stack = Vec::new();
                loop {
                    match receiver.try_recv() {
                        Err(TryRecvError::Empty) => (),
                        Ok(_) => return,
                        Err(TryRecvError::Disconnected) => {
                            println!("Threads were not properly stopped before disconnecting channel!");
                            return;
                        }
                    }
                    if let Some(rect) = coordinator.lock().unwrap().next_block() {
                        let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                        for h in 0..rect.height {
                            for w in 0..rect.width {
                                let clip_x = 2.0 * (rect.left + w) as f32 / width as f32 - 1.0;
                                let clip_y = 2.0 * (rect.bottom + h) as f32 / height as f32 - 1.0;
                                let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                                let world_p = clip_to_world * clip_p;
                                let dir = ((world_p / world_p.w).truncate() - camera.pos.to_vec()).normalize();
                                let ray = Ray::new(camera.pos, dir, 100.0);

                                let pixel_i = 3 * (h * rect.width + w) as usize;
                                if let Some(hit) = find_hit(&scene, ray, &mut node_stack) {
                                    // TODO: This should account for sRBG
                                    let mut c = hit.tri.diffuse(&scene.materials, hit.u, hit.v);
                                    c *= dir.dot(hit.tri.normal(hit.u, hit.v)).abs();
                                    block[pixel_i]     = c.x;
                                    block[pixel_i + 1] = c.y;
                                    block[pixel_i + 2] = c.z;
                                } else {
                                    block[pixel_i]     = 0.1;
                                    block[pixel_i + 1] = 0.1;
                                    block[pixel_i + 2] = 0.1;
                                }
                            }
                        }
                        sender.send((rect, block)).expect("Receiver closed!");
                    } else {
                        return;
                    }
                }
            });
            self.thread_handles.push(handle);
        }
    }

    pub fn render<S: Surface>(&mut self, target: &mut S) {
        if let Some(ref rx) = self.receive_channel {
            for (rect, block) in rx.try_iter().take(10) {
                let raw_block = RawImage2d::from_raw_rgb(block, (rect.width, rect.height));
                self.texture.write(rect, raw_block);
            }
            let uniforms = uniform! {
                image: &self.texture,
            };
            let draw_parameters = DrawParameters {
                ..Default::default()
            };
            target.draw(&self.vertex_buffer, &self.index_buffer, &self.shader,
                        &uniforms, &draw_parameters).unwrap();
        }
    }

    pub fn stop_threads(&mut self) {
        for sender in &self.send_channels {
            sender.send(()).unwrap();
        }
        for handle in self.thread_handles.drain(..) {
            handle.join().unwrap();
        }
        // Drop channels after join so stop messages are properly reveived
        self.send_channels.clear();
    }
}

fn find_hit<'a>(scene: &'a Scene, ray: Ray, node_stack: &mut Vec<(*const BVHNode, f32)>) -> Option<Hit<'a>> {
    let bvh = &scene.bvh;
    node_stack.push((bvh.root(), 0.0f32));
    let mut closest_hit: Option<Hit> = None;
    while let Some((node_p, t)) = node_stack.pop() {
        let node = unsafe { &*node_p };
        // We've already found closer hit
        if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
        if node.is_leaf() {
            for tri in &scene.triangles[node.start_i..node.end_i] {
                if let Some(hit) = tri.intersect(&ray) {
                    if let Some(closest) = closest_hit.take() {
                        if hit.t < closest.t {
                            closest_hit = Some(hit);
                        } else {
                            closest_hit = Some(closest);
                        }
                    } else {
                        closest_hit = Some(hit);
                    }
                }
            }
        } else {
            // TODO: put closest hit on top of the stack
            let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
            if let Some(t_left) = left.intersect(&ray) {
                node_stack.push((left, t_left));
            }
            if let Some(t_right) = right.intersect(&ray) {
                node_stack.push((right, t_right));
            }
        }
    }
    closest_hit
}
<commit_msg>Split long line<commit_after>extern crate num_cpus;

use std::sync::{Arc, Mutex, mpsc::{self, Sender, Receiver, TryRecvError}};
use std::thread::{self, JoinHandle};

use cgmath::prelude::*;
use cgmath::{Vector3, Vector4, Point3};

use glium;
use glium::{VertexBuffer, IndexBuffer, Surface, DrawParameters, Rect};
use glium::backend::Facade;
use glium::texture::{RawImage2d, Texture2d};

use camera::Camera;
use scene::Scene;
use bvh::BVHNode;
use triangle::Hit;
use vertex::Vertex;

pub trait Intersect<'a, H> {
    fn intersect(&'a self, ray: &Ray) -> Option<H>;
}

#[derive(Clone, Copy)]
pub struct Ray {
    pub orig: Point3<f32>,
    pub dir: Vector3<f32>,
    // For more efficient ray plane intersections
    pub reciprocal_dir: Vector3<f32>,
    pub length: f32,
}

impl Ray {
    fn new(orig: Point3<f32>, dir: Vector3<f32>, length: f32) -> Ray {
        let reciprocal_dir = 1.0 / dir;
        Ray { orig, dir, reciprocal_dir, length }
    }
}

#[allow(dead_code)]
pub struct RenderCoordinator {
    width: u32,
    height: u32,
    max_iterations: Option<u32>,
    end_x: u32,
    start_y: u32,
    end_y: u32,
    iteration: u32,
}

impl RenderCoordinator {
    fn new(width: u32, height: u32, max_iterations: Option<u32>) -> RenderCoordinator {
        RenderCoordinator {
            width, height, max_iterations,
            end_x: 0, start_y: 0, end_y: 0, iteration: 0
        }
    }

    fn next_block(&mut self) -> Option<Rect> {
        let block_height = 50;
        let block_width = 50;
        if let Some(max) = self.max_iterations {
            if self.iteration > max {
                return None;
            }
        }
        if self.end_y >= self.height && self.end_x >= self.width {
            self.iteration += 1;
            self.start_y = 0;
            self.end_y = block_width.min(self.height);
            self.end_x = 0;
        } else if self.end_x >= self.width {
            self.start_y = self.end_y;
            self.end_y = (self.start_y + block_height).min(self.height);
            self.end_x = 0;
        }
        let start_x = self.end_x;
        self.end_x = (start_x + block_width).min(self.width);
        Some (
            Rect {
                left: start_x,
                bottom: self.start_y,
                width: self.end_x - start_x,
                height: self.end_y - self.start_y,
            }
        )
    }
}

pub struct PTRenderer {
    shader: glium::Program,
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u32>,
    texture: Texture2d,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    receive_channel: Option<Receiver<(Rect, Vec<f32>)>>,
    send_channels: Vec<Sender<()>>,
    thread_handles: Vec<JoinHandle<()>>,
}

impl PTRenderer {
    pub fn new<F: Facade>(facade: &F) -> PTRenderer {
        let vertices = vec!(
            Vertex { pos: [-1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 0.0] },
            Vertex { pos: [1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 0.0] },
            Vertex { pos: [1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 1.0] },
            Vertex { pos: [-1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 1.0] },
        );
        let vertex_buffer = VertexBuffer::new(facade, &vertices)
            .expect("Failed to create vertex buffer!");
        let indices = vec!(0, 1, 2, 0, 2, 3);
        let index_buffer = IndexBuffer::new(facade,
                                            glium::index::PrimitiveType::TrianglesList,
                                            &indices)
            .expect("Failed to create index buffer!");
        let texture = Texture2d::empty(facade, 0, 0).expect("Failed to create trace texture!");

        // Image shader
        let vertex_shader_src = include_str!("shaders/image.vert");
        let fragment_shader_src = include_str!("shaders/image.frag");
        let shader = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        PTRenderer { shader, vertex_buffer, index_buffer, texture,
                     coordinator: Arc::new(Mutex::new(RenderCoordinator::new(0, 0, None))),
                     receive_channel: None,
                     send_channels: Vec::new(),
                     thread_handles: Vec::new(),
        }
    }

    pub fn start_render<F: Facade>(&mut self, facade: &F, scene: &Arc<Scene>, camera: &Camera,
                                    width: u32, height: u32) {
        let empty_image = RawImage2d::from_raw_rgb(vec![0.0; (3 * width * height) as usize], (width, height));
        self.texture = Texture2d::new(facade, empty_image).expect("Failed to upload traced image!");
        self.coordinator = Arc::new(Mutex::new(RenderCoordinator::new(width, height, None)));
        let (thread_sender, main_receiver) = mpsc::channel();
        self.receive_channel = Some(main_receiver);
        for _ in 0..num_cpus::get_physical() {
            let sender = thread_sender.clone();
            let (main_sender, receiver) = mpsc::channel();
            self.send_channels.push(main_sender);
            let coordinator = self.coordinator.clone();
            let camera = camera.clone();
            let scene = scene.clone();
            let clip_to_world = (camera.get_camera_to_clip(width, height)
                                 * camera.get_world_to_camera()).invert()
                .expect("Non invertible world to clip");
            let handle = thread::spawn(move|| {
                let mut node_stack = Vec::new();
                loop {
                    match receiver.try_recv() {
                        Err(TryRecvError::Empty) => (),
                        Ok(_) => return,
                        Err(TryRecvError::Disconnected) => {
                            println!("Threads were not properly stopped before disconnecting channel!");
                            return;
                        }
                    }
                    if let Some(rect) = coordinator.lock().unwrap().next_block() {
                        let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                        for h in 0..rect.height {
                            for w in 0..rect.width {
                                let clip_x = 2.0 * (rect.left + w) as f32 / width as f32 - 1.0;
                                let clip_y = 2.0 * (rect.bottom + h) as f32 / height as f32 - 1.0;
                                let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                                let world_p = clip_to_world * clip_p;
                                let dir = ((world_p / world_p.w).truncate() - camera.pos.to_vec()).normalize();
                                let ray = Ray::new(camera.pos, dir, 100.0);

                                let pixel_i = 3 * (h * rect.width + w) as usize;
                                if let Some(hit) = find_hit(&scene, ray, &mut node_stack) {
                                    // TODO: This should account for sRBG
                                    let mut c = hit.tri.diffuse(&scene.materials, hit.u, hit.v);
                                    c *= dir.dot(hit.tri.normal(hit.u, hit.v)).abs();
                                    block[pixel_i]     = c.x;
                                    block[pixel_i + 1] = c.y;
                                    block[pixel_i + 2] = c.z;
                                } else {
                                    block[pixel_i]     = 0.1;
                                    block[pixel_i + 1] = 0.1;
                                    block[pixel_i + 2] = 0.1;
                                }
                            }
                        }
                        sender.send((rect, block)).expect("Receiver closed!");
                    } else {
                        return;
                    }
                }
            });
            self.thread_handles.push(handle);
        }
    }

    pub fn render<S: Surface>(&mut self, target: &mut S) {
        if let Some(ref rx) = self.receive_channel {
            for (rect, block) in rx.try_iter().take(10) {
                let raw_block = RawImage2d::from_raw_rgb(block, (rect.width, rect.height));
                self.texture.write(rect, raw_block);
            }
            let uniforms = uniform! {
                image: &self.texture,
            };
            let draw_parameters = DrawParameters {
                ..Default::default()
            };
            target.draw(&self.vertex_buffer, &self.index_buffer, &self.shader,
                        &uniforms, &draw_parameters).unwrap();
        }
    }

    pub fn stop_threads(&mut self) {
        for sender in &self.send_channels {
            sender.send(()).unwrap();
        }
        for handle in self.thread_handles.drain(..) {
            handle.join().unwrap();
        }
        // Drop channels after join so stop messages are properly reveived
        self.send_channels.clear();
    }
}

fn find_hit<'a>(scene: &'a Scene, ray: Ray, node_stack: &mut Vec<(*const BVHNode, f32)>)
                -> Option<Hit<'a>> {
    let bvh = &scene.bvh;
    node_stack.push((bvh.root(), 0.0f32));
    let mut closest_hit: Option<Hit> = None;
    while let Some((node_p, t)) = node_stack.pop() {
        let node = unsafe { &*node_p };
        // We've already found closer hit
        if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
        if node.is_leaf() {
            for tri in &scene.triangles[node.start_i..node.end_i] {
                if let Some(hit) = tri.intersect(&ray) {
                    if let Some(closest) = closest_hit.take() {
                        if hit.t < closest.t {
                            closest_hit = Some(hit);
                        } else {
                            closest_hit = Some(closest);
                        }
                    } else {
                        closest_hit = Some(hit);
                    }
                }
            }
        } else {
            // TODO: put closest hit on top of the stack
            let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
            if let Some(t_left) = left.intersect(&ray) {
                node_stack.push((left, t_left));
            }
            if let Some(t_right) = right.intersect(&ray) {
                node_stack.push((right, t_right));
            }
        }
    }
    closest_hit
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![feature(proc_macro_hygiene)]

//! # ICU number formatting support for rust (modern)
//!
//! Since 0.3.1

use {
    paste, rust_icu_common as common,
    rust_icu_common::simple_drop_impl,
    rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_uloc as uloc, rust_icu_unum as unum,
    rust_icu_ustring as ustring,
    rust_icu_ustring::buffered_uchar_method_with_retry,
    std::{convert::TryFrom, convert::TryInto, ptr},
};

macro_rules! format_type {
    ($method_name:ident, $impl_function_name:ident, $value_type:ty) => {
        /// Implements `$impl_function_name`. Since 0.3.1.
        pub fn $method_name(&self, value: $value_type) -> Result<UFormattedNumber, common::Error> {
            let mut result = UFormattedNumber::try_new()?;
            let mut status = sys::UErrorCode::U_ZERO_ERROR;
            unsafe {
                versioned_function!($impl_function_name)(
                    self.rep.as_ptr(),
                    value,
                    result.as_c_mut_ptr(),
                    &mut status,
                )
            };
            common::Error::ok_or_warning(status)?;
            Ok(result)
        }
    };
}

/// The struct for modern number formatting (akin to ECMA402).
///
/// Use [UNumberFormatter::try_new] to create a new instance of this type.
#[derive(Debug)]
pub struct UNumberFormatter {
    rep: ptr::NonNull<sys::UNumberFormatter>,
}

simple_drop_impl!(UNumberFormatter, unumf_close);

impl UNumberFormatter {
    /// Makes a new [UNumberFormatter], using ICU types.
    ///
    /// To make a new formatter if you have Rust types only, see [UNumberFormatter::try_new].  See
    /// that function also for the description of skeleton syntax.
    ///
    /// Returns the error description if an error is found.
    ///
    /// Implements `unumf_openForSkeletonAndLocaleWithError`. Since 0.3.1.
    /// Implements `unumf_openForSkeletonAndLocale`. Since 0.3.1.
    pub fn try_new_ustring(
        skeleton: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormatter, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;

        // Uses the "with error" flavor of the constructor for ICU versions upwards of
        // 64.  This allows more elaborate error messages in case of an issue.
        #[cfg(feature = "icu_version_64_plus")]
        {
            let mut parse_status = common::NO_PARSE_ERROR.clone();
            let rep = unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unumf_openForSkeletonAndLocaleWithError)(
                    skeleton.as_c_ptr(),
                    skeleton.len() as i32,
                    locale.label().as_ptr() as *const std::os::raw::c_char,
                    &mut parse_status,
                    &mut status,
                )
            };
            assert_ne!(rep, 0 as *mut sys::UNumberFormatter);
            common::parse_ok(parse_status)?;
            common::Error::ok_or_warning(status)?;
            let result = UNumberFormatter {
                rep: std::ptr::NonNull::new(rep).unwrap(),
            };
            return Ok(result);
        }
        #[cfg(not(feature = "icu_version_64_plus"))]
        {
            let rep = unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unumf_openForSkeletonAndLocale)(
                    skeleton.as_c_ptr(),
                    skeleton.len() as i32,
                    locale.label().as_ptr() as *const std::os::raw::c_char,
                    &mut status,
                )
            };
            assert_ne!(rep, 0 as *mut sys::UNumberFormatter);
            common::Error::ok_or_warning(status)?;
            let result = UNumberFormatter {
                rep: std::ptr::NonNull::new(rep).unwrap(),
            };
            return Ok(result);
        }
    }

    /// Similar to [UNumberFormatter::try_new_ustring] but uses Rust types.
    ///
    /// The `skeleton` is a string that describes the formatting options.
    /// See [skeleton syntax][skel] for detailed documentation.
    ///
    /// Implements `unumf_openForSkeletonAndLocaleWithError`. Since 0.3.1.
    /// Implements `unumf_openForSkeletonAndLocale`. Since 0.3.1.
    ///
    /// [skel]: https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md
    pub fn try_new(skeleton: &str, locale: &str) -> Result<UNumberFormatter, common::Error> {
        let locale = uloc::ULoc::try_from(locale)?;
        let skeleton = ustring::UChar::try_from(skeleton)?;
        UNumberFormatter::try_new_ustring(&skeleton, &locale)
    }

    // Implements `unumf_formatInt`. Since 0.3.1.
    format_type!(format_int, unumf_formatInt, i64);

    // Implements `unumf_formatDouble`. Since 0.3.1.
    format_type!(format_double, unumf_formatDouble, f64);

    /// Implements `unumf_formatDecimal`. Since 0.3.1.
    pub fn format_decimal(&self, value: &str) -> Result<UFormattedNumber, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        let mut result = UFormattedNumber::try_new()?;
        unsafe {
            versioned_function!(unumf_formatDecimal)(
                self.rep.as_ptr(),
                value.as_ptr() as *const std::os::raw::c_char,
                value.len() as i32,
                result.as_c_mut_ptr(),
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        Ok(result)
    }
}

/// Stores a formatted number result.
///
/// These objects are produced [UNumberFormatter::format_int], [UNumberFormatter::format_double],
/// [UNumberFormatter::format_decimal].
///
pub struct UFormattedNumber {
    rep: std::ptr::NonNull<sys::UFormattedNumber>,
}

impl UFormattedNumber {
    /// Implements `unumf_openResult`.  Since 0.3.1.
    fn try_new() -> Result<Self, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unumf_openResult)(&mut status)
        };
        common::Error::ok_or_warning(status)?;
        assert_ne!(rep, 0 as *mut sys::UFormattedNumber);
        let result = std::ptr::NonNull::new(rep).unwrap();
        Ok(UFormattedNumber { rep: result })
    }

    /// Reveals the underlying C representation.
    fn as_c_mut_ptr(&mut self) -> *mut sys::UFormattedNumber {
        self.rep.as_ptr()
    }

    /// Reveals the underlying C representation.
    fn as_c_ptr(&self) -> *const sys::UFormattedNumber {
        self.rep.as_ptr()
    }

    /// Obtains the field iterator for the formatted result.
    ///
    /// Implements `unumf_resultGetAllFieldPositions`. Since 0.3.1.
    ///
    /// Implements `unumf_resultNextFieldPosition`. Since 0.3.1. All access is
    /// via iterators.
    pub fn try_field_iter<'a>(&'a self) -> Result<unum::UFieldPositionIterator<'a, Self>, common::Error> {
        let mut result = unum::UFieldPositionIterator::try_new_owned(self)?;
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        unsafe {
            versioned_function!(unumf_resultGetAllFieldPositions)(
                self.as_c_ptr(),
                result.as_mut_ptr(),
                &mut status,
                )
        };
        common::Error::ok_or_warning(status)?;
        Ok(result)
    }
}

simple_drop_impl!(UFormattedNumber, unumf_closeResult);

impl TryInto<ustring::UChar> for UFormattedNumber {
    type Error = common::Error;

    /// Converts this formatted number into a Unicode string.
    ///
    /// You want to use this method instead of `TryInto<String>` when you need
    /// to do additional processing on the result, such as extracting fields
    /// based on their indexes.
    ///
    /// Implements `unumf_resultToString`.  Since 0.3.1.
    fn try_into(self) -> Result<ustring::UChar, common::Error> {
        const CAPACITY: usize = 200;
        buffered_uchar_method_with_retry!(
            tryinto_impl,
            CAPACITY,
            [rep: *const sys::UFormattedNumber,],
            []
        );
        tryinto_impl(versioned_function!(unumf_resultToString), self.rep.as_ptr())
    }
}

impl TryInto<String> for UFormattedNumber {
    type Error = common::Error;

    /// Converts this formatted number into a Rust string.
    ///
    /// If you intend to use field position iterators on the result, you have to use
    /// `TryInto<ustring::UChar>` instead, because field position iterators use the fixed encoding
    /// of [ustring::UChar] for positioning.
    ///
    /// Implements `unumf_resultToString`.  Since 0.3.1.
    fn try_into(self) -> Result<String, common::Error> {
        let result: ustring::UChar = self.try_into()?;
        String::try_from(&result)
    }
}

#[cfg(test)]
mod testing {
    use std::convert::TryInto;

    #[test]
    fn basic() {
        let fmt = super::UNumberFormatter::try_new(
            "measure-unit/length-meter compact-long sign-always", "sr-RS").unwrap();
        let result = fmt.format_double(123456.7890).unwrap();
        let result_str: String = result.try_into().unwrap();
        assert_eq!("+123 хиљаде m", result_str);

        // Quickly check that the value is as expected.
        let result = fmt.format_double(123456.7890).unwrap();
        let num_fields = result.try_field_iter().unwrap().count();
        assert_eq!(2, num_fields);
    }

    #[test]
    fn thorough() {
        #[derive(Debug, Clone)]
        struct TestCase {
            locale: &'static str,
            number: f64,
            skeleton: &'static str,
            expected: &'static str,
        }
        let tests = vec![
           TestCase{
               locale: "sr-RS",
               number: 123456.7890,
               skeleton: "measure-unit/length-meter compact-long sign-always",
               expected: "+123 хиљаде m",
           },
           TestCase{
               locale: "sr-RS-u-nu-deva",
               number: 123456.7890,
               skeleton: "measure-unit/length-meter compact-long sign-always",
               expected: "+१२३ хиљаде m",
           },
           TestCase{
               locale: "sr-RS",
               number: 123456.7890,
               skeleton: "numbering-system/deva",
               expected: "१२३.४५६,७८९",
           },
        ];

        for test in tests {
            let fmt = super::UNumberFormatter::try_new(
                &test.skeleton, &test.locale).expect(&format!("for test {:?}", &test));
            let result = fmt.format_double(test.number).unwrap();
            let result_str: String = result.try_into().unwrap();
            assert_eq!(test.expected, result_str, "for test {:?}", &test);
        }
    }
}
<commit_msg>Fixes build check breaks<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![feature(proc_macro_hygiene)]

//! # ICU number formatting support for rust (modern)
//!
//! Since 0.3.1

use {
    paste, rust_icu_common as common,
    rust_icu_common::simple_drop_impl,
    rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_uloc as uloc, rust_icu_unum as unum,
    rust_icu_ustring as ustring,
    rust_icu_ustring::buffered_uchar_method_with_retry,
    std::{convert::TryFrom, convert::TryInto, ptr},
};

macro_rules! format_type {
    ($method_name:ident, $impl_function_name:ident, $value_type:ty) => {
        /// Implements `$impl_function_name`. Since 0.3.1.
        pub fn $method_name(&self, value: $value_type) -> Result<UFormattedNumber, common::Error> {
            let mut result = UFormattedNumber::try_new()?;
            let mut status = sys::UErrorCode::U_ZERO_ERROR;
            unsafe {
                versioned_function!($impl_function_name)(
                    self.rep.as_ptr(),
                    value,
                    result.as_c_mut_ptr(),
                    &mut status,
                )
            };
            common::Error::ok_or_warning(status)?;
            Ok(result)
        }
    };
}

/// The struct for modern number formatting (akin to ECMA402).
///
/// Use [UNumberFormatter::try_new] to create a new instance of this type.
#[derive(Debug)]
pub struct UNumberFormatter {
    rep: ptr::NonNull<sys::UNumberFormatter>,
}

simple_drop_impl!(UNumberFormatter, unumf_close);

impl UNumberFormatter {
    /// Makes a new [UNumberFormatter], using ICU types.
    ///
    /// To make a new formatter if you have Rust types only, see [UNumberFormatter::try_new].  See
    /// that function also for the description of skeleton syntax.
    ///
    /// Returns the error description if an error is found.
    ///
    /// Implements `unumf_openForSkeletonAndLocaleWithError`. Since 0.3.1.
    /// Implements `unumf_openForSkeletonAndLocale`. Since 0.3.1.
    pub fn try_new_ustring(
        skeleton: &ustring::UChar,
        locale: &uloc::ULoc,
    ) -> Result<UNumberFormatter, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;

        // Uses the "with error" flavor of the constructor for ICU versions upwards of
        // 64.  This allows more elaborate error messages in case of an issue.
        #[cfg(feature = "icu_version_64_plus")]
        {
            let mut parse_status = common::NO_PARSE_ERROR.clone();
            let rep = unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unumf_openForSkeletonAndLocaleWithError)(
                    skeleton.as_c_ptr(),
                    skeleton.len() as i32,
                    locale.label().as_ptr() as *const std::os::raw::c_char,
                    &mut parse_status,
                    &mut status,
                )
            };
            assert_ne!(rep, 0 as *mut sys::UNumberFormatter);
            common::parse_ok(parse_status)?;
            common::Error::ok_or_warning(status)?;
            let result = UNumberFormatter {
                rep: std::ptr::NonNull::new(rep).unwrap(),
            };
            return Ok(result);
        }
        #[cfg(not(feature = "icu_version_64_plus"))]
        {
            let rep = unsafe {
                assert!(common::Error::is_ok(status));
                versioned_function!(unumf_openForSkeletonAndLocale)(
                    skeleton.as_c_ptr(),
                    skeleton.len() as i32,
                    locale.label().as_ptr() as *const std::os::raw::c_char,
                    &mut status,
                )
            };
            assert_ne!(rep, 0 as *mut sys::UNumberFormatter);
            common::Error::ok_or_warning(status)?;
            let result = UNumberFormatter {
                rep: std::ptr::NonNull::new(rep).unwrap(),
            };
            return Ok(result);
        }
    }

    /// Similar to [UNumberFormatter::try_new_ustring] but uses Rust types.
    ///
    /// The `skeleton` is a string that describes the formatting options.
    /// See [skeleton syntax][skel] for detailed documentation.
    ///
    /// Implements `unumf_openForSkeletonAndLocaleWithError`. Since 0.3.1.
    /// Implements `unumf_openForSkeletonAndLocale`. Since 0.3.1.
    ///
    /// [skel]: https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md
    pub fn try_new(skeleton: &str, locale: &str) -> Result<UNumberFormatter, common::Error> {
        let locale = uloc::ULoc::try_from(locale)?;
        let skeleton = ustring::UChar::try_from(skeleton)?;
        UNumberFormatter::try_new_ustring(&skeleton, &locale)
    }

    // Implements `unumf_formatInt`. Since 0.3.1.
    format_type!(format_int, unumf_formatInt, i64);

    // Implements `unumf_formatDouble`. Since 0.3.1.
    format_type!(format_double, unumf_formatDouble, f64);

    /// Implements `unumf_formatDecimal`. Since 0.3.1.
    pub fn format_decimal(&self, value: &str) -> Result<UFormattedNumber, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        let mut result = UFormattedNumber::try_new()?;
        unsafe {
            versioned_function!(unumf_formatDecimal)(
                self.rep.as_ptr(),
                value.as_ptr() as *const std::os::raw::c_char,
                value.len() as i32,
                result.as_c_mut_ptr(),
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        Ok(result)
    }
}

/// Stores a formatted number result.
///
/// These objects are produced [UNumberFormatter::format_int], [UNumberFormatter::format_double],
/// [UNumberFormatter::format_decimal].
///
pub struct UFormattedNumber {
    rep: std::ptr::NonNull<sys::UFormattedNumber>,
}

impl UFormattedNumber {
    /// Implements `unumf_openResult`.  Since 0.3.1.
    fn try_new() -> Result<Self, common::Error> {
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(unumf_openResult)(&mut status)
        };
        common::Error::ok_or_warning(status)?;
        assert_ne!(rep, 0 as *mut sys::UFormattedNumber);
        let result = std::ptr::NonNull::new(rep).unwrap();
        Ok(UFormattedNumber { rep: result })
    }

    /// Reveals the underlying C representation.
    fn as_c_mut_ptr(&mut self) -> *mut sys::UFormattedNumber {
        self.rep.as_ptr()
    }

    /// Reveals the underlying C representation.
    fn as_c_ptr(&self) -> *const sys::UFormattedNumber {
        self.rep.as_ptr()
    }

    /// Obtains the field iterator for the formatted result.
    ///
    /// Implements `unumf_resultGetAllFieldPositions`. Since 0.3.1.
    ///
    /// Implements `unumf_resultNextFieldPosition`. Since 0.3.1. All access is
    /// via iterators.
    pub fn try_field_iter<'a>(&'a self) -> Result<unum::UFieldPositionIterator<'a, Self>, common::Error> {
        let mut result = unum::UFieldPositionIterator::try_new_owned(self)?;
        let mut status = sys::UErrorCode::U_ZERO_ERROR;
        unsafe {
            versioned_function!(unumf_resultGetAllFieldPositions)(
                self.as_c_ptr(),
                result.as_mut_ptr(),
                &mut status,
                )
        };
        common::Error::ok_or_warning(status)?;
        Ok(result)
    }
}

simple_drop_impl!(UFormattedNumber, unumf_closeResult);

impl TryInto<ustring::UChar> for UFormattedNumber {
    type Error = common::Error;

    /// Converts this formatted number into a Unicode string.
    ///
    /// You want to use this method instead of `TryInto<String>` when you need
    /// to do additional processing on the result, such as extracting fields
    /// based on their indexes.
    ///
    /// Implements `unumf_resultToString`.  Since 0.3.1.
    fn try_into(self) -> Result<ustring::UChar, common::Error> {
        const CAPACITY: usize = 200;
        buffered_uchar_method_with_retry!(
            tryinto_impl,
            CAPACITY,
            [rep: *const sys::UFormattedNumber,],
            []
        );
        tryinto_impl(versioned_function!(unumf_resultToString), self.rep.as_ptr())
    }
}

impl TryInto<String> for UFormattedNumber {
    type Error = common::Error;

    /// Converts this formatted number into a Rust string.
    ///
    /// If you intend to use field position iterators on the result, you have to use
    /// `TryInto<ustring::UChar>` instead, because field position iterators use the fixed encoding
    /// of [ustring::UChar] for positioning.
    ///
    /// Implements `unumf_resultToString`.  Since 0.3.1.
    fn try_into(self) -> Result<String, common::Error> {
        let result: ustring::UChar = self.try_into()?;
        String::try_from(&result)
    }
}

#[cfg(test)]
mod testing {
    use std::convert::TryInto;

    #[test]
    fn basic() {
        let fmt = super::UNumberFormatter::try_new(
            "measure-unit/length-meter compact-long sign-always", "sr-RS").unwrap();
        let result = fmt.format_double(123456.7890).unwrap();
        let result_str: String = result.try_into().unwrap();
        assert_eq!("+123 хиљаде m", result_str);

        // Quickly check that the value is as expected.
        let result = fmt.format_double(123456.7890).unwrap();
        let num_fields = result.try_field_iter().unwrap().count();
        assert!(num_fields > 0);
    }

    #[test]
    fn thorough() {
        #[derive(Debug, Clone)]
        struct TestCase {
            locale: &'static str,
            number: f64,
            skeleton: &'static str,
            expected: &'static str,
        }
        let tests = vec![
           TestCase{
               locale: "sr-RS",
               number: 123456.7890,
               skeleton: "measure-unit/length-meter compact-long sign-always",
               expected: "+123 хиљаде m",
           },
           TestCase{
               locale: "sr-RS-u-nu-deva",
               number: 123456.7890,
               skeleton: "measure-unit/length-meter compact-long sign-always",
               expected: "+१२३ хиљаде m",
           },
           TestCase{
               locale: "sr-RS",
               number: 123456.7890,
               skeleton: "numbering-system/deva",
               expected: "१२३.४५६,७८९",
           },
        ];

        for test in tests {
            let fmt = super::UNumberFormatter::try_new(
                &test.skeleton, &test.locale).expect(&format!("for test {:?}", &test));
            let result = fmt.format_double(test.number).unwrap();
            let result_str: String = result.try_into().unwrap();
            assert_eq!(test.expected, result_str, "for test {:?}", &test);
        }
    }
}
<|endoftext|>


<commit_before>use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

lazy_static! {
    static ref QGRAMS: Vec<f64> = {
        let f = include_str!("data/quadgrams.txt");
        let mut qgrams = vec![0.0; 456_976];  // 26^4 = 456,976

        for line in f.lines() {
            let line: Vec<_> = line.split(' ').collect();
            let qgram: &str = line[0];
            let count: f64 = line[1].parse().unwrap();

            let index = qgram.chars().fold(0, |acc, c| 26 * acc + c.index());
            qgrams[index] = count.ln();
        }

        qgrams
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning the tuple `(plaintext, rotor, key, ring)`
/// corresponding to the most probable plaintext.
pub fn decrypt(msg: &str) -> (String, String, String, String) {
    // Rotor and key settings (60*26^3 == 1,054,560 decryptions)
    let (_, k1, best_rotor) = iproduct!(
            b'1'..b'6', b'1'..b'6', b'1'..b'6',
            b'A'..b'[', b'A'..b'[', b'A'..b'['
        ).collect::<Vec<_>>()
        .par_iter()
        .filter(|&&(r1, r2, r3, _, _, _)| (r1 != r2) && (r1 != r3) && (r2 != r3))
        .map(|&(r1, r2, r3, k1, k2, k3)| {
            let rotor = String::from_utf8(vec![r1, r2, r3]).unwrap();
            let key = String::from_utf8(vec![k1, k2, k3]).unwrap();

            let mut enigma = Enigma::new(&rotor, &key, "AAA", 'B', "");
            let plaintext = enigma.encrypt(msg);
            let score = qgram_score(&plaintext);
            (OrderedFloat(score), k1, rotor)
        }).max().unwrap();

    // Key and ring settings (26^4 == 456,976 decryptions)
    let (_, best_msg, best_key, best_ring) = iproduct!(
            b'A'..b'[', b'A'..b'[', b'A'..b'[', b'A'..b'['
        ).collect::<Vec<_>>()
        .par_iter()
        .map(|&(k2, k3, r2, r3)| {
            let key = String::from_utf8(vec![k1, k2, k3]).unwrap();
            let ring = String::from_utf8(vec![b'A', r2, r3]).unwrap();

            let mut enigma = Enigma::new(&best_rotor, &key, &ring, 'B', "");
            let plaintext = enigma.encrypt(msg);
            let score = qgram_score(&plaintext);
            (OrderedFloat(score), plaintext, key, ring)
        }).max().unwrap();

    (best_msg, best_rotor, best_key, best_ring)
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let char_indices: Vec<usize> = msg.chars()
        .filter(|&c| c.is_alphabetic())
        .map(|c| c.index())
        .collect();

    if char_indices.len() < 4 {
        panic!("Message must contain 4 or more alphabetic characters.");
    }

    char_indices.windows(4)
        .map(|w| w.iter().fold(0, |acc, x| 26 * acc + x))
        .map(|i| QGRAMS[i])
        .sum()
}

#[cfg(test)]
mod tests {
    use super::{QGRAMS, qgram_score};

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        }
    }

    #[test]
    fn qgram_estimates() {
        assert_approx_eq!(QGRAMS[0], 8.81060879);
        assert_approx_eq!(qgram_score("THE QUICK BROWN FOX"), 149.80102862);
    }

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<commit_msg>Refactor ciphertext decryption<commit_after>use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

lazy_static! {
    static ref QGRAMS: Vec<f64> = {
        let f = include_str!("data/quadgrams.txt");
        let mut qgrams = vec![0.0; 456_976];  // 26^4 = 456,976

        for line in f.lines() {
            let line: Vec<_> = line.split(' ').collect();
            let qgram: &str = line[0];
            let count: f64 = line[1].parse().unwrap();

            let index = qgram.chars().fold(0, |acc, c| 26 * acc + c.index());
            qgrams[index] = count.ln();
        }

        qgrams
    };

    static ref ALPHAS: Vec<String> = {
        // Construct the vector ["AAA", "AAB", ..., "ZZY", "ZZZ"]
        iproduct!(b'A'..b'[', b'A'..b'[', b'A'..b'[')
            .map(|(a, b, c)| String::from_utf8(vec![a, b, c]).unwrap())
            .collect()
    };

    static ref ROTORS: Vec<String> = {
        // Create all permutations of rotors 1 through 5
        iproduct!(b'1'..b'6', b'1'..b'6', b'1'..b'6')
            .filter(|&(r1, r2, r3)| (r1 != r2) && (r1 != r3) && (r2 != r3))
            .map(|(r1, r2, r3)| String::from_utf8(vec![r1, r2, r3]).unwrap())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning the tuple `(plaintext, rotor, key, ring)`
/// corresponding to the most probable plaintext.
pub fn decrypt(msg: &str) -> (String, String, String, String) {
    // Try all rotor/key permutations (60*26^3 == 1,054,560 decryptions)
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            let plaintext = enigma.encrypt(msg);
            OrderedFloat(qgram_score(&plaintext))
        }).unwrap();

    // Keep the best rotor configuration found previously, and use the same
    // key setting for the first (slow) rotor. The ring setting for the first
    // rotor doesn't matter, so fix it to 'A', and try all key/ring settings
    // for the remaining two rotors (26^4 == 456,976 decryptions)
    let key_offset = key.chars().nth(0).unwrap().index() * 676;

    let (_, msg, key, ring) = iproduct!(key_offset..(key_offset + 676), 0..676)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|&(key_index, ring_index)| {
            let key = &ALPHAS[key_index];
            let ring = &ALPHAS[ring_index];

            let mut enigma = Enigma::new(rotor, key, ring, 'B', "");
            let plaintext = enigma.encrypt(msg);
            let score = qgram_score(&plaintext);
            (OrderedFloat(score), plaintext, key, ring)
        }).max().unwrap();

    (msg, rotor.clone(), key.clone(), ring.clone())
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let char_indices: Vec<usize> = msg.chars()
        .filter(|&c| c.is_alphabetic())
        .map(|c| c.index())
        .collect();

    if char_indices.len() < 4 {
        panic!("Message must contain 4 or more alphabetic characters.");
    }

    char_indices.windows(4)
        .map(|w| w.iter().fold(0, |acc, x| 26 * acc + x))
        .map(|i| QGRAMS[i])
        .sum()
}

#[cfg(test)]
mod tests {
    use super::{QGRAMS, qgram_score};

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        }
    }

    #[test]
    fn qgram_estimates() {
        assert_approx_eq!(QGRAMS[0], 8.81060879);
        assert_approx_eq!(qgram_score("THE QUICK BROWN FOX"), 149.80102862);
    }

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<|endoftext|>


<commit_before>use crate::{BuildMetadata, Prerelease};
use std::fmt::{self, Debug, Display};

impl Display for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Display for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Debug for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Prerelease(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}

impl Debug for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("BuildMetadata(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}
<commit_msg>Customize Debug impl of Version to omit empty pieces<commit_after>use crate::{BuildMetadata, Prerelease, Version};
use std::fmt::{self, Debug, Display};

impl Display for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Display for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Debug for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let mut debug = formatter.debug_struct("Version");
        debug
            .field("major", &self.major)
            .field("minor", &self.minor)
            .field("patch", &self.patch);
        if !self.pre.is_empty() {
            debug.field("pre", &self.pre);
        }
        if !self.build.is_empty() {
            debug.field("build", &self.build);
        }
        debug.finish()
    }
}

impl Debug for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Prerelease(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}

impl Debug for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("BuildMetadata(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-test will be fixed later
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

#![feature(thread_local)]

#[thread_local]
static FOO: u8 = 3;

fn assert_static(_t: &'static u8) {}
fn main() {
     assert_static(&FOO); //[ast]~ ERROR [E0597]
                          //[mir]~^ ERROR [E0597]
}
<commit_msg>Unignore borrowck test<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

#![feature(thread_local)]

#[thread_local]
static FOO: u8 = 3;

fn assert_static(_t: &'static u8) {}
fn main() {
     assert_static(&FOO); //[ast]~ ERROR [E0597]
                          //[mir]~^ ERROR [E0597]
}
<|endoftext|>


<commit_before>use ffi;
use error::YamlError;
use event::{YamlVersionDirective, YamlTagDirective};

use std::str;
use std::slice;
use std::ptr;
use std::mem;
use std::ffi::{c_str_to_bytes, CString};
use std::io::IoError;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    unsafe fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: mem::uninitialized()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut (Writer+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'a>(writer: &'a mut Writer) -> Box<YamlEmitter<'a>> {
        unsafe {
            let mut emitter = box YamlEmitter {
                base_emitter: YamlBaseEmitter::new(),
                writer: writer,
                io_error: None
            };

            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                panic!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, mem::transmute(&mut *emitter));

            emitter
        }
    }

    fn get_error(&mut self) -> YamlError {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            let c_problem = c_str_to_bytes(&emitter_mem.problem);
            let mut error = YamlError {
                kind: emitter_mem.error,
                problem: str::from_utf8(c_problem).map(|s| s.to_string()).ok(),
                io_error: None,
                context: None
            };

            mem::swap(&mut self.io_error, &mut error.io_error);

            return error;
        }
    }

    pub fn emit_stream(&mut self,
                    encoding: ffi::YamlEncoding,
                    f: |&mut YamlEmitter| -> Result<(), YamlError>)
        -> Result<(), YamlError>
    {
        try!(self.emit_stream_start_event(encoding));
        try!(f(self));
        try!(self.emit_stream_end_event());
        self.flush()
    }

    fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                panic!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_stream_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool,
            f: |&mut YamlEmitter| -> Result<(), YamlError>)
        -> Result<(), YamlError>
    {
        try!(self.emit_document_start_event(version_directive, tag_directives, implicit));
        try!(f(self));
        self.emit_document_end_event(implicit)
    }

    fn emit_document_start_event(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool)
        -> Result<(), YamlError>
    {
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some(directive) => {
                vsn_dir.major = directive.major as libc::c_int;
                vsn_dir.minor = directive.minor as libc::c_int;
                &vsn_dir as *const ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: Vec<(CString, CString)> = tag_directives.iter().map(|tag| {
            (CString::from_slice(tag.handle.as_bytes()), CString::from_slice(tag.prefix.as_bytes()))
        }).collect();
        let c_tag_dirs: Vec<ffi::yaml_tag_directive_t> = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.0.as_ptr(),
                prefix: tuple.1.as_ptr(),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let mut event = mem::uninitialized();
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as int);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                panic!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), YamlError> {
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), YamlError> {
        let c_anchor = CString::from_slice(anchor.as_bytes());

        unsafe {
            let mut event = mem::uninitialized();

            let ptr = c_anchor.as_ptr();
            if ffi::yaml_alias_event_initialize(&mut event, ptr as *const ffi::yaml_char_t) != 0 {
                panic!("yaml_stream_end_event_initialize failed!")
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                panic!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: |&mut YamlEmitter| -> Result<(), YamlError>)
        -> Result<(), YamlError>
    {
        try!(self.emit_sequence_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_sequence_end_event()
    }

    fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_sequence_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                panic!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: |&mut YamlEmitter| -> Result<(), YamlError>)
        -> Result<(), YamlError>
    {
        try!(self.emit_mapping_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_mapping_end_event()
    }

    fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_mapping_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                panic!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), YamlError> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *const u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = slice::from_raw_buf(&buffer, size as uint);
        let emitter = &mut *data;
        match emitter.writer.write(buf) {
            Ok(()) => 1,
            Err(err) => {
                emitter.io_error = Some(err);
                0
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;
    use emitter::YamlEmitter;
    use ffi::YamlEncoding::YamlUtf8Encoding;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_sequence(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "[1, 2]\n".as_bytes());
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_mapping(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "{a: 1, b: 2}\n".as_bytes());
    }
}
<commit_msg>Language changes: Use unboxed closure syntax<commit_after>use ffi;
use error::YamlError;
use event::{YamlVersionDirective, YamlTagDirective};

use std::str;
use std::slice;
use std::ptr;
use std::mem;
use std::ffi::{c_str_to_bytes, CString};
use std::io::IoError;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    unsafe fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: mem::uninitialized()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut (Writer+'r),
    io_error: Option<IoError>,
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'a>(writer: &'a mut Writer) -> Box<YamlEmitter<'a>> {
        unsafe {
            let mut emitter = box YamlEmitter {
                base_emitter: YamlBaseEmitter::new(),
                writer: writer,
                io_error: None
            };

            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                panic!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, mem::transmute(&mut *emitter));

            emitter
        }
    }

    fn get_error(&mut self) -> YamlError {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            let c_problem = c_str_to_bytes(&emitter_mem.problem);
            let mut error = YamlError {
                kind: emitter_mem.error,
                problem: str::from_utf8(c_problem).map(|s| s.to_string()).ok(),
                io_error: None,
                context: None
            };

            mem::swap(&mut self.io_error, &mut error.io_error);

            return error;
        }
    }

    pub fn emit_stream<F>(&mut self, encoding: ffi::YamlEncoding, f: F) -> Result<(), YamlError>
        where F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_stream_start_event(encoding));
        try!(f(self));
        try!(self.emit_stream_end_event());
        self.flush()
    }

    fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                panic!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_stream_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document<F>(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_document_start_event(version_directive, tag_directives, implicit));
        try!(f(self));
        self.emit_document_end_event(implicit)
    }

    fn emit_document_start_event(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[YamlTagDirective],
            implicit: bool)
        -> Result<(), YamlError>
    {
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some(directive) => {
                vsn_dir.major = directive.major as libc::c_int;
                vsn_dir.minor = directive.minor as libc::c_int;
                &vsn_dir as *const ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: Vec<(CString, CString)> = tag_directives.iter().map(|tag| {
            (CString::from_slice(tag.handle.as_bytes()), CString::from_slice(tag.prefix.as_bytes()))
        }).collect();
        let c_tag_dirs: Vec<ffi::yaml_tag_directive_t> = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.0.as_ptr(),
                prefix: tuple.1.as_ptr(),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let mut event = mem::uninitialized();
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as int);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                panic!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), YamlError> {
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                panic!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), YamlError> {
        let c_anchor = CString::from_slice(anchor.as_bytes());

        unsafe {
            let mut event = mem::uninitialized();

            let ptr = c_anchor.as_ptr();
            if ffi::yaml_alias_event_initialize(&mut event, ptr as *const ffi::yaml_char_t) != 0 {
                panic!("yaml_stream_end_event_initialize failed!")
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                panic!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_sequence_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_sequence_end_event()
    }

    fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_sequence_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                panic!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping<F>(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
            style: ffi::YamlSequenceStyle,
            f: F) -> Result<(), YamlError> where
        F: Fn(&mut YamlEmitter) -> Result<(), YamlError>
    {
        try!(self.emit_mapping_start_event(anchor, tag, implicit, style));
        try!(f(self));
        self.emit_mapping_end_event()
    }

    fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), YamlError>
    {
        let c_anchor = anchor.map(|s| CString::from_slice(s.as_bytes()));
        let anchor_ptr = match c_anchor {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| CString::from_slice(s.as_bytes()));
        let tag_ptr = match c_tag {
            Some(s) => s.as_ptr(),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *const ffi::yaml_char_t, tag_ptr as *const ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                panic!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    fn emit_mapping_end_event(&mut self) -> Result<(), YamlError> {
        unsafe {
            let mut event = mem::uninitialized();

            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                panic!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), YamlError> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *const u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = slice::from_raw_buf(&buffer, size as uint);
        let emitter = &mut *data;
        match emitter.writer.write(buf) {
            Ok(()) => 1,
            Err(err) => {
                emitter.io_error = Some(err);
                0
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;
    use emitter::YamlEmitter;
    use ffi::YamlEncoding::YamlUtf8Encoding;
    use ffi::YamlScalarStyle::*;
    use ffi::YamlSequenceStyle::*;

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_sequence(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "[1, 2]\n".as_bytes());
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream(YamlUtf8Encoding, |e| {
                e.emit_document(None, &[], true, |e| {
                    e.emit_mapping(None, None, true, YamlFlowSequenceStyle, |e| {
                        try!(e.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle));
                        try!(e.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle));
                        e.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle)
                    })
                })
            });
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "{a: 1, b: 2}\n".as_bytes());
    }
}
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string(&"#bundle".to_string())
                            .iter()
                            .cloned());

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            bundle_bytes.extend(x.iter().cloned());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.len() == 0 {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter().cloned());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Use `into` to convert `String` into `Vec<u8>`<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string(&"#bundle".to_string())
                            .iter()
                            .cloned());

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            bundle_bytes.extend(x.iter().cloned());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.len() == 0 {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter().cloned());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes().into();
    bytes.push(0u8);
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>