<commit_before>extern crate glm;
extern crate sdl2;

use self::sdl2::rect;
use self::sdl2::render::{Renderer, Texture};

pub struct Meteor {
    texture: Texture,
    center: glm::Vector2<f64>,
    dims: glm::Vector2<u32>,
    max_coords: glm::Vector2<u32>,
    velocity: glm::Vector2<f64>,
    launched: bool,
}

impl Meteor {
    pub fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let center = glm::dvec2(0., 0.);
        let dims = glm::uvec2(query.width, query.height);

        Meteor {
            texture: texture,
            center: center,
            dims: dims,
            max_coords: max_coords,
            velocity: glm::dvec2(0., 0.),
            launched: false,
        }
    }

    pub fn launch(&mut self, target: glm::Vector2<i32>) {
        const FACTOR: f64 = 85.;
        let offset = glm::ivec2(target.x - self.center.y as i32,
                                target.y - self.center.y as i32);
        self.velocity = glm::dvec2(offset.x as f64 / FACTOR, offset.y as f64 / FACTOR);
        self.launched = true;
    }

    pub fn update(&mut self) {
        self.center.y += self.velocity.y;
        self.center.x += self.velocity.x;

        let max_height = self.max_coords.y as f64;
        let max_width = self.max_coords.x as f64;

        self.center.y = (self.center.y + max_height) % max_height;
        self.center.x = (self.center.x + max_width) % max_width;
    }

    pub fn is_launched(&self) -> bool {
        self.launched
    }

    pub fn draw(&self, renderer: &mut Renderer) -> Result<(), String> {
        self.drawing_rectangles()
            .iter()
            .filter(|r| r.is_some())
            .map(|&r| renderer.copy(&self.texture, None, r))
            .fold(Ok(()), |res, x| { if res.is_err() { res } else { x } })
    }

    fn drawing_rectangles(&self) -> [Option<rect::Rect>; 4] {
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let top = self.center.y as i32 - self.dims.y as i32 / 2;

        let rect = rect::Rect::new(left, top, self.dims.x, self.dims.y);
        let side_rect = self.side_rect(&rect);
        let vert_rect = self.vert_rect(&rect);

        let side_vert_rect = match vert_rect {
            Some(unwrapped) => self.side_rect(&unwrapped),
            None => None,
        };

        [Some(rect), vert_rect, side_rect, side_vert_rect]
    }

    fn vert_rect(&self, original: &rect::Rect) -> Option<rect::Rect> {
        let bottom = self.center.y as i32 + self.dims.y as i32 / 2;
        let top = self.center.y as i32 - self.dims.y as i32 / 2;
        let max_height = self.max_coords.y as i32;

        let mut copy = original.clone();

        if top < 0 {
            copy.set_y(top + max_height);
            Some(copy)
        } else if bottom > max_height {
            copy.set_bottom(bottom % max_height);
            Some(copy)
        } else {
            None
        }

    }

    fn side_rect(&self, original: &rect::Rect) -> Option<rect::Rect> {
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let right = self.center.x as i32 + self.dims.x as i32 / 2;
        let max_width = self.max_coords.x as i32;

        let mut copy = original.clone();

        if left < 0 {
            copy.set_x(left + max_width);
            Some(copy)
        } else if right > max_width {
            copy.set_right(right % max_width);
            Some(copy)
        } else {
            None
        }
    }
}
<commit_msg>small improvement on meteor drawing<commit_after>extern crate glm;
extern crate sdl2;

use self::sdl2::rect;
use self::sdl2::render::{Renderer, Texture};

pub struct Meteor {
    texture: Texture,
    center: glm::Vector2<f64>,
    dims: glm::Vector2<u32>,
    max_coords: glm::Vector2<u32>,
    velocity: glm::Vector2<f64>,
    launched: bool,
}

impl Meteor {
    pub fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let center = glm::dvec2(0., 0.);
        let dims = glm::uvec2(query.width, query.height);

        Meteor {
            texture: texture,
            center: center,
            dims: dims,
            max_coords: max_coords,
            velocity: glm::dvec2(0., 0.),
            launched: false,
        }
    }

    pub fn launch(&mut self, target: glm::Vector2<i32>) {
        const FACTOR: f64 = 85.;
        let offset = glm::ivec2(target.x - self.center.y as i32,
                                target.y - self.center.y as i32);
        self.velocity = glm::dvec2(offset.x as f64 / FACTOR, offset.y as f64 / FACTOR);
        self.launched = true;
    }

    pub fn update(&mut self) {
        self.center.y += self.velocity.y;
        self.center.x += self.velocity.x;

        let max_height = self.max_coords.y as f64;
        let max_width = self.max_coords.x as f64;

        self.center.y = (self.center.y + max_height) % max_height;
        self.center.x = (self.center.x + max_width) % max_width;
    }

    pub fn is_launched(&self) -> bool {
        self.launched
    }

    pub fn draw(&self, renderer: &mut Renderer) -> Result<(), String> {
        self.drawing_rectangles()
            .iter()
            .filter(|r| r.is_some())
            .map(|&r| renderer.copy(&self.texture, None, r))
            .fold(Ok(()), |res, x| { if res.is_err() { res } else { x } })
    }

    fn drawing_rectangles(&self) -> [Option<rect::Rect>; 4] {
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let top = self.center.y as i32 - self.dims.y as i32 / 2;

        let rect = rect::Rect::new(left, top, self.dims.x, self.dims.y);
        let side_rect = self.side_rect(&rect);
        let vert_rect = self.vert_rect(&rect);

        let side_vert_rect = match (vert_rect, side_rect) {
            (Some(vert_unwrapped), Some(side_unwrapped)) => {
                Some(rect::Rect::new(side_unwrapped.x(),
                                     vert_unwrapped.y(),
                                     self.dims.x,
                                     self.dims.y))
            }
            _ => None,
        };

        [Some(rect), vert_rect, side_rect, side_vert_rect]
    }

    fn vert_rect(&self, original: &rect::Rect) -> Option<rect::Rect> {
        let bottom = self.center.y as i32 + self.dims.y as i32 / 2;
        let top = self.center.y as i32 - self.dims.y as i32 / 2;
        let max_height = self.max_coords.y as i32;

        let mut copy = original.clone();

        if top < 0 {
            copy.set_y(top + max_height);
            Some(copy)
        } else if bottom > max_height {
            copy.set_bottom(bottom % max_height);
            Some(copy)
        } else {
            None
        }
    }

    fn side_rect(&self, original: &rect::Rect) -> Option<rect::Rect> {
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let right = self.center.x as i32 + self.dims.x as i32 / 2;
        let max_width = self.max_coords.x as i32;

        let mut copy = original.clone();

        if left < 0 {
            copy.set_x(left + max_width);
            Some(copy)
        } else if right > max_width {
            copy.set_right(right % max_width);
            Some(copy)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::marker::PhantomData;
use glib::object::{Ref, Wrapper};
use glib::types::StaticType;

pub use glib::object::{Downcast, Upcast};

/// The generic type for `GObject` descendants in GDK.
pub struct Object<T>(Ref, PhantomData<T>);

impl<T> Wrapper for Object<T>
where Object<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object<T> { Object(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for Object<T> {
    fn clone(&self) -> Object<T> {
        Object(self.0.clone(), PhantomData)
    }
}

unsafe impl<T> Upcast<::glib::object::Object> for Object<T> where Object<T>: StaticType { }
<commit_msg>Prepare for soundness fixes in glib<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::marker::PhantomData;
use glib::object::{Ref, Wrapper};
use glib::types::StaticType;

pub use glib::object::{Downcast, Upcast};

/// The generic type for `GObject` descendants in GDK.
pub struct Object<T>(Ref, PhantomData<T>);

impl<T: 'static> Wrapper for Object<T>
where Object<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object<T> { Object(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for Object<T> {
    fn clone(&self) -> Object<T> {
        Object(self.0.clone(), PhantomData)
    }
}

unsafe impl<T: 'static> Upcast<::glib::object::Object> for Object<T> where Object<T>: StaticType { }
<|endoftext|>


<commit_before>use num::{Complex, FromPrimitive, Signed};

use butterflies::{butterfly_2_single, butterfly_4_single, butterfly_4};

pub fn process_radix4<T>(size: usize,
              signal: &[Complex<T>],
              spectrum: &mut [Complex<T>],
              stride: usize,
              twiddles: &[Complex<T>],
              inverse: bool) where T: Signed + FromPrimitive + Copy {

    let num_bits = (size - 1).count_ones();

    //first, perform the butterflies. the butterfly size depends on the input size
    let mut current_size = if num_bits % 2 == 1 {
        //the size is a power of 2, so we need to do size-2 butterflies, with a stride of size / 2
        for (chunk_index, chunk) in spectrum.chunks_mut(2 * stride).enumerate() {
            //copy the data from the signal into our chunk -- we improve cache friendliness by copying it right when we need it
            for i in 0..2 {
                let signal_index = reverse_bits_radix4(num_bits, chunk_index * 2 + i);
                unsafe { *chunk.get_unchecked_mut(i * stride) =
                    *signal.get_unchecked(signal_index * stride) }
            }

            //perform the butterly on our newly copied data
            unsafe { butterfly_2_single(chunk, stride) }
        }

        //for the cross-ffts we want to to start off with a size of 8 (2 * 4)
        8
    }
    else {
        for (chunk_index, chunk) in spectrum.chunks_mut(4 * stride).enumerate() {
            //copy the data from the signal into our chunk -- we improve cache friendliness by copying it right when we need it
            for i in 0..4 {
                let signal_index = reverse_bits_radix4(num_bits, chunk_index * 4 + i);
                 unsafe { *chunk.get_unchecked_mut(i * stride) =
                    *signal.get_unchecked(signal_index * stride) }
            }

            unsafe { butterfly_4_single(chunk, stride, inverse) }
        }

        //for the cross-ffts we want to to start off with a size of 16 (4 * 4)
        16
    };

    //now, perform all the cross-FFTs, one "layer" at a time
    while current_size <= size {
        let group_stride = size / current_size;

        for i in 0..group_stride {
            unsafe { butterfly_4(&mut spectrum[i * current_size..], group_stride, twiddles, current_size / 4, inverse) }
        }
        current_size *= 4;
    }
}

fn reverse_bits_radix4(num_bits: u32, mut n: usize) -> usize {
    let mut output = 0;

    //for radix 4, we want to reverse the bits of n, in blocks of 2 bits at a time
    //so 110110 becomes 100111

    //for radix 2, num_bits will be odd. in this case, we want to reverse just a single bit in the last iteration
    if num_bits %2 == 1 {
        output |= n & 1;
        n >>= 1;
    }

    //now copy 2 bits at a time from n into
    for _ in 0..num_bits/2 {
        output <<= 2;
        output |= n & 3;
        n >>= 2;
    }

    output
}

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

    #[test]
    fn test_bit_reversal() {
        //first tuple element is num bits, second is expected output
        let test_list = vec![
            (1, vec![0,1]),
            (2, vec![0,1,2,3]),
            (3, vec![0,4,1,5,2,6,3,7]),
            (4, vec![0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15]),
            (5, vec![0,16,4,20,8,24,12,28,1,17,5,21,9,25,13,29,   2,18,6,22,10,26,14,30,3,19,7,23,11,27,15,31]),
        ];

        for (num_bits, expected_list) in test_list {

            // verify that the bit reversal function reorders the range 0..size into the expected output
            for (result, e) in
                    (0..expected_list.len())
                    .map(|i| reverse_bits_radix4(num_bits, i))
                    .zip(expected_list.iter()) {
                assert_eq!(result, *e);
            }
        }
    }
}<commit_msg>returned to a recursive setup algorithm, but kept iterative execution<commit_after>use num::{Complex, FromPrimitive, Signed};

use butterflies::{butterfly_2_single, butterfly_4_single, butterfly_4};

pub fn process_radix4<T>(size: usize,
                         signal: &[Complex<T>],
                         spectrum: &mut [Complex<T>],
                         stride: usize,
                         twiddles: &[Complex<T>],
                         inverse: bool)
    where T: Signed + FromPrimitive + Copy
{

    prepare_radix4(size, signal, spectrum, stride);

    // first, perform the butterflies. the butterfly size depends on the input size
    let num_bits = (size - 1).count_ones();
    let mut current_size = if num_bits % 2 > 0 {
        // the size is a power of 2, so we need to do size-2 butterflies, with a stride of size / 2
        for chunk in spectrum.chunks_mut(2 * stride) {
            unsafe { butterfly_2_single(chunk, stride) }
        }

        // for the cross-ffts we want to to start off with a size of 8 (2 * 4)
        8
    } else {
        for chunk in spectrum.chunks_mut(4 * stride) {
            unsafe { butterfly_4_single(chunk, stride, inverse) }
        }

        // for the cross-ffts we want to to start off with a size of 16 (4 * 4)
        16
    };

    // now, perform all the cross-FFTs, one "layer" at a time
    while current_size <= size {
        let group_stride = size / current_size;

        for i in 0..group_stride {
            unsafe {
                butterfly_4(&mut spectrum[i * current_size..],
                            group_stride,
                            twiddles,
                            current_size / 4,
                            inverse)
            }
        }
        current_size *= 4;
    }
}

// after testing an iterative bit reversal algorithm, this recursive algorithm
// was almost an order of magnitude faster at setting up
fn prepare_radix4<T: Copy>(size: usize,
                           signal: &[Complex<T>],
                           spectrum: &mut [Complex<T>],
                           stride: usize) {
    match size {
        4 => unsafe {
            for i in 0..4 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        2 => unsafe {
            for i in 0..2 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        _ => {
            for i in 0..4 {
                prepare_radix4(size / 4,
                               &signal[i * stride..],
                               &mut spectrum[i * (size / 4)..],
                               stride * 4);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Instructions to generate random bits directly from the hardware (RDRAND and RDSEED).
//!
//! The decision process for which instruction to use is based on what
//! the output will be used for. If you wish to seed another pseudorandom
//! number generator (PRNG), use RDSEED. For all other purposes, use RDRAND
//!
//! See also: https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
//!
//! * RDRAND: Cryptographically secure pseudorandom number generator	NIST:SP 800-90A
//! * RDSEED: Non-deterministic random bit generator	NIST: SP 800-90B & C (drafts)
//!
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::{
    _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
};

#[cfg(target_arch = "x86")]
use core::arch::x86::{_rdrand16_step, _rdrand32_step, _rdseed16_step, _rdseed32_step};

/// Generates a 16-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[inline(always)]
pub unsafe fn rdrand16(e: &mut u16) -> bool {
    _rdrand16_step(e) == 1
}

/// Generates a 32-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[inline(always)]
pub unsafe fn rdrand32(e: &mut u32) -> bool {
    _rdrand32_step(e) == 1
}

/// Generates a 64-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn rdrand64(e: &mut u64) -> bool {
    _rdrand64_step(e) == 1
}

/// RdRand trait to implement the generic rdrand_slice function.
pub trait RdRand {
    /// Fills `self` with random bits. Returns true on success or false otherwise
    ///
    /// # Unsafe
    /// RDRAND is not supported on all architctures, so using this may crash you.
    unsafe fn fill_random(&mut self) -> bool;
}

impl RdRand for u16 {
    /// Fills the 16-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand16(self)
    }
}

impl RdRand for u32 {
    /// Fills the 32-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand32(self)
    }
}

#[cfg(target_arch = "x86_64")]
impl RdRand for u64 {
    /// Fills the 64-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand64(self)
    }
}

/// Fill a slice with random values.
///
/// Returns true if the iterator was successfully filled with
/// random values, otherwise false.
pub unsafe fn rdrand_slice<T: RdRand>(buffer: &mut [T]) -> bool {
    let mut worked = true;
    for element in buffer {
        worked &= element.fill_random();
    }
    worked
}

/// Generates a 16-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[inline(always)]
pub unsafe fn rdseed16(e: &mut u16) -> bool {
    _rdseed16_step(e) == 1
}

/// Generates a 32-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[inline(always)]
pub unsafe fn rdseed32(e: &mut u32) -> bool {
    _rdseed32_step(e) == 1
}

/// Generates a 64-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn rdseed64(e: &mut u64) -> bool {
    _rdseed64_step(e) == 1
}

/// RdSeed trait to implement the generic rdseed_slice function.
pub trait RdSeed {
    /// Fills `self` with random bits. Returns true on success or false otherwise
    ///
    /// # Unsafe
    /// RDSEED is not supported on all architctures, so using this may crash you.
    unsafe fn fill_random(&mut self) -> bool;
}

impl RdSeed for u16 {
    /// Fills the 16-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed16(self)
    }
}

impl RdSeed for u32 {
    /// Fills the 32-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed32(self)
    }
}

#[cfg(target_arch = "x86_64")]
impl RdSeed for u64 {
    /// Fills the 64-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed64(self)
    }
}

/// Fill a slice with random values.
///
/// Returns true if the iterator was successfully filled with
/// random values, otherwise false.
pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
    let mut worked = true;
    for element in buffer {
        worked &= element.fill_random();
    }
    worked
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn rdrand64_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u64; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdrand32_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u32; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdrand16_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u16; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);
            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed64_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u64; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed32_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u32; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed16_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u16; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);
            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }
}
<commit_msg>Properly check for RDSEED support in tests<commit_after>//! Instructions to generate random bits directly from the hardware (RDRAND and RDSEED).
//!
//! The decision process for which instruction to use is based on what
//! the output will be used for. If you wish to seed another pseudorandom
//! number generator (PRNG), use RDSEED. For all other purposes, use RDRAND
//!
//! See also: https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
//!
//! * RDRAND: Cryptographically secure pseudorandom number generator	NIST:SP 800-90A
//! * RDSEED: Non-deterministic random bit generator	NIST: SP 800-90B & C (drafts)
//!
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::{
    _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
};

#[cfg(target_arch = "x86")]
use core::arch::x86::{_rdrand16_step, _rdrand32_step, _rdseed16_step, _rdseed32_step};

/// Generates a 16-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[inline(always)]
pub unsafe fn rdrand16(e: &mut u16) -> bool {
    _rdrand16_step(e) == 1
}

/// Generates a 32-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[inline(always)]
pub unsafe fn rdrand32(e: &mut u32) -> bool {
    _rdrand32_step(e) == 1
}

/// Generates a 64-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDRAND instructions are not supported.
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn rdrand64(e: &mut u64) -> bool {
    _rdrand64_step(e) == 1
}

/// RdRand trait to implement the generic rdrand_slice function.
pub trait RdRand {
    /// Fills `self` with random bits. Returns true on success or false otherwise
    ///
    /// # Unsafe
    /// RDRAND is not supported on all architctures, so using this may crash you.
    unsafe fn fill_random(&mut self) -> bool;
}

impl RdRand for u16 {
    /// Fills the 16-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand16(self)
    }
}

impl RdRand for u32 {
    /// Fills the 32-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand32(self)
    }
}

#[cfg(target_arch = "x86_64")]
impl RdRand for u64 {
    /// Fills the 64-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDRAND instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdrand64(self)
    }
}

/// Fill a slice with random values.
///
/// Returns true if the iterator was successfully filled with
/// random values, otherwise false.
pub unsafe fn rdrand_slice<T: RdRand>(buffer: &mut [T]) -> bool {
    let mut worked = true;
    for element in buffer {
        worked &= element.fill_random();
    }
    worked
}

/// Generates a 16-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[inline(always)]
pub unsafe fn rdseed16(e: &mut u16) -> bool {
    _rdseed16_step(e) == 1
}

/// Generates a 32-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[inline(always)]
pub unsafe fn rdseed32(e: &mut u32) -> bool {
    _rdseed32_step(e) == 1
}

/// Generates a 64-bit random value and stores it in `e`.
///
/// # Unsafe
/// Will crash if RDSEED instructions are not supported.
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn rdseed64(e: &mut u64) -> bool {
    _rdseed64_step(e) == 1
}

/// RdSeed trait to implement the generic rdseed_slice function.
pub trait RdSeed {
    /// Fills `self` with random bits. Returns true on success or false otherwise
    ///
    /// # Unsafe
    /// RDSEED is not supported on all architctures, so using this may crash you.
    unsafe fn fill_random(&mut self) -> bool;
}

impl RdSeed for u16 {
    /// Fills the 16-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed16(self)
    }
}

impl RdSeed for u32 {
    /// Fills the 32-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed32(self)
    }
}

#[cfg(target_arch = "x86_64")]
impl RdSeed for u64 {
    /// Fills the 64-bit value with a random bit string
    ///
    /// # Unsafe
    /// Will crash if RDSEED instructions are not supported.
    unsafe fn fill_random(&mut self) -> bool {
        rdseed64(self)
    }
}

/// Fill a slice with random values.
///
/// Returns true if the iterator was successfully filled with
/// random values, otherwise false.
pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
    let mut worked = true;
    for element in buffer {
        worked &= element.fill_random();
    }
    worked
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn rdrand64_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u64; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdrand32_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u32; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdrand16_test() {
        let has_rdrand = crate::cpuid::CpuId::new()
            .get_feature_info()
            .map_or(false, |finfo| finfo.has_rdrand());
        if !has_rdrand {
            return;
        }

        unsafe {
            let mut buf: [u16; 4] = [0, 0, 0, 0];
            rdrand_slice(&mut buf);
            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed64_test() {
        let has_rdseed = crate::cpuid::CpuId::new()
            .get_extended_feature_info()
            .map_or(false, |efinfo| efinfo.has_rdseed());
        if !has_rdseed {
            return;
        }

        unsafe {
            let mut buf: [u64; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed32_test() {
        let has_rdseed = crate::cpuid::CpuId::new()
            .get_extended_feature_info()
            .map_or(false, |efinfo| efinfo.has_rdseed());
        if !has_rdseed {
            return;
        }

        unsafe {
            let mut buf: [u32; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);

            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }

    #[test]
    fn rdseed16_test() {
        let has_rdseed = crate::cpuid::CpuId::new()
            .get_extended_feature_info()
            .map_or(false, |efinfo| efinfo.has_rdseed());
        if !has_rdseed {
            return;
        }

        unsafe {
            let mut buf: [u16; 4] = [0, 0, 0, 0];
            rdseed_slice(&mut buf);
            assert_ne!(buf[0], 0);
            assert_ne!(buf[1], 0);
            assert_ne!(buf[2], 0);
            assert_ne!(buf[3], 0);
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::{PartialOrd, Ordering};
use std::iter::repeat;
use std::usize;

use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

impl PartialOrd for Point {
   fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for Point {
   fn cmp(&self, other: &Point) -> Ordering {
      if self.y < other.y {
         Ordering::Less
      } else if self.y > other.y {
         Ordering::Greater
      } else if self.x < other.x {
         Ordering::Less
      } else if self.x > other.x {
         Ordering::Greater
      } else {
         Ordering::Equal
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
         self.check_segments_orientation(poly);
         self.check_edges_orientation(poly);
      }

      self.check_index_coverage();
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn check_segments_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];
         let ref segment = self.segments[edge.segment];

         let ref less = self.points[segment.p1];
         let ref greater = self.points[segment.p2];

         if greater <= less {
            panic!("Wrong segment orientation : {:?} / {:?}", edge, segment);
         }
      }
   }

   fn check_edges_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let tail = self.edge_tail(edge);
         let head = self.edge_head(edge);

         let reversed = edge.reversed();

         if (reversed && tail <= head) || (!reversed && head <= tail) {
            panic!("Wrong edge orientation : {:?}", edge);
         }
      }
   }

   fn check_index_coverage(&self) {
      self.check_edge_index_coverage();
      self.check_circle_index_coverage();
   }

   fn check_edge_index_coverage(&self) {
      let len = self.edges.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for poly in &self.polys {
         for edge_index in poly.start..poly.end {
            coverage[edge_index] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced edge found");
      }
   }

   fn check_circle_index_coverage(&self) {
      let len = self.circles.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         if edge.circle != usize::MAX {
            coverage[edge.circle] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced circle found");
      }
   }

   // TODO: Combine into edge_head_tail method?

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<commit_msg>Checking segment index coverage<commit_after>use std::cmp::{PartialOrd, Ordering};
use std::iter::repeat;
use std::usize;

use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

impl PartialOrd for Point {
   fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for Point {
   fn cmp(&self, other: &Point) -> Ordering {
      if self.y < other.y {
         Ordering::Less
      } else if self.y > other.y {
         Ordering::Greater
      } else if self.x < other.x {
         Ordering::Less
      } else if self.x > other.x {
         Ordering::Greater
      } else {
         Ordering::Equal
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
         self.check_segments_orientation(poly);
         self.check_edges_orientation(poly);
      }

      self.check_index_coverage();
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn check_segments_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];
         let ref segment = self.segments[edge.segment];

         let ref less = self.points[segment.p1];
         let ref greater = self.points[segment.p2];

         if greater <= less {
            panic!("Wrong segment orientation : {:?} / {:?}", edge, segment);
         }
      }
   }

   fn check_edges_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let tail = self.edge_tail(edge);
         let head = self.edge_head(edge);

         let reversed = edge.reversed();

         if (reversed && tail <= head) || (!reversed && head <= tail) {
            panic!("Wrong edge orientation : {:?}", edge);
         }
      }
   }

   fn check_index_coverage(&self) {
      self.check_edge_index_coverage();
      self.check_circle_index_coverage();
      self.check_segment_index_coverage();
   }

   fn check_edge_index_coverage(&self) {
      let len = self.edges.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for poly in &self.polys {
         for edge_index in poly.start..poly.end {
            coverage[edge_index] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced edge found");
      }
   }

   fn check_circle_index_coverage(&self) {
      let len = self.circles.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         if edge.circle != usize::MAX {
            coverage[edge.circle] = true;
         }
      }

      if coverage.contains(&false) {
         panic!("Unreferenced circle found");
      }
   }

   fn check_segment_index_coverage(&self) {
      let len = self.segments.len();
      let mut coverage: Vec<bool> = repeat(false).take(len).collect();

      for edge in &self.edges {
         coverage[edge.segment] = true;
      }

      if coverage.contains(&false) {
         panic!("Unreferenced segment found");
      }
   }

   // TODO: Combine into edge_head_tail method?

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 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.

macro_rules! define_set {
    ($name:ident, $exec_build:expr, $text_ty:ty, $as_bytes:expr) => {
        pub mod $name {
            use std::fmt;
            use std::iter;
            use std::slice;
            use std::vec;

            use error::Error;
            use exec::{Exec, ExecBuilder};
            use re_trait::RegularExpression;

/// Match multiple (possibly overlapping) regular expressions in a single scan.
///
/// A regex set corresponds to the union of two or more regular expressions.
/// That is, a regex set will match text where at least one of its
/// constituent regular expressions matches. A regex set as its formulated here
/// provides a touch more power: it will also report *which* regular
/// expressions in the set match. Indeed, this is the key difference between
/// regex sets and a single `Regex` with many alternates, since only one
/// alternate can match at a time.
///
/// For example, consider regular expressions to match email addresses and
/// domains: `[a-z]+@[a-z]+\.(com|org|net)` and `[a-z]+\.(com|org|net)`. If a
/// regex set is constructed from those regexes, then searching the text
/// `foo@example.com` will report both regexes as matching. Of course, one
/// could accomplish this by compiling each regex on its own and doing two
/// searches over the text. The key advantage of using a regex set is that it
/// will report the matching regexes using a *single pass through the text*.
/// If one has hundreds or thousands of regexes to match repeatedly (like a URL
/// router for a complex web application or a user agent matcher), then a regex
/// set can realize huge performance gains.
///
/// # Example
///
/// This shows how the above two regexes (for matching email addresses and
/// domains) might work:
///
/// ```rust
/// # use regex::RegexSet;
/// let set = RegexSet::new(&[
///     r"[a-z]+@[a-z]+\.(com|org|net)",
///     r"[a-z]+\.(com|org|net)",
/// ]).unwrap();
///
/// // Ask whether any regexes in the set match.
/// assert!(set.is_match("foo@example.com"));
///
/// // Identify which regexes in the set match.
/// let matches: Vec<_> = set.matches("foo@example.com").into_iter().collect();
/// assert_eq!(vec![0, 1], matches);
///
/// // Try again, but with text that only matches one of the regexes.
/// let matches: Vec<_> = set.matches("example.com").into_iter().collect();
/// assert_eq!(vec![1], matches);
///
/// // Try again, but with text that doesn't match any regex in the set.
/// let matches: Vec<_> = set.matches("example").into_iter().collect();
/// assert!(matches.is_empty());
/// ```
///
/// Note that it would be possible to adapt the above example to using `Regex`
/// with an expression like:
///
/// ```ignore
/// (?P<email>[a-z]+@(?P<email_domain>[a-z]+[.](com|org|net)))|(?P<domain>[a-z]+[.](com|org|net))
/// ```
///
/// After a match, one could then inspect the capture groups to figure out
/// which alternates matched. The problem is that it is hard to make this
/// approach scale when there are many regexes since the overlap between each
/// alternate isn't always obvious to reason about.
///
/// # Limitations
///
/// Regex sets are limited to answering the following two questions:
///
/// 1. Does any regex in the set match?
/// 2. If so, which regexes in the set match?
///
/// As with the main `Regex` type, it is cheaper to ask (1) instead of (2)
/// since the matching engines can stop after the first match is found.
///
/// Other features like finding the location of successive matches or their
/// sub-captures aren't supported. If you need this functionality, the
/// recommended approach is to compile each regex in the set independently and
/// selectively match them based on which regexes in the set matched.
///
/// # Performance
///
/// A `RegexSet` has the same performance characteristics as `Regex`. Namely,
/// search takes `O(mn)` time, where `m` is proportional to the size of the
/// regex set and `n` is proportional to the length of the search text.
#[derive(Clone)]
pub struct RegexSet(Exec);

impl RegexSet {
    /// Create a new regex set with the given regular expressions.
    ///
    /// This takes an iterator of `S`, where `S` is something that can produce
    /// a `&str`. If any of the strings in the iterator are not valid regular
    /// expressions, then an error is returned.
    ///
    /// # Example
    ///
    /// Create a new regex set from an iterator of strings:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap();
    /// assert!(set.is_match("foo"));
    /// ```
    pub fn new<I, S>(exprs: I) -> Result<RegexSet, Error>
            where S: AsRef<str>, I: IntoIterator<Item=S> {
        let exec = try!($exec_build(exprs));
        Ok(RegexSet(exec))
    }

    /// Returns true if and only if one of the regexes in this set matches
    /// the text given.
    ///
    /// This method should be preferred if you only need to test whether any
    /// of the regexes in the set should match, but don't care about *which*
    /// regexes matched. This is because the underlying matching engine will
    /// quit immediately after seeing the first match instead of continuing to
    /// find all matches.
    ///
    /// Note that as with searches using `Regex`, the expression is unanchored
    /// by default. That is, if the regex does not start with `^` or `\A`, or
    /// end with `$` or `\z`, then it is permitted to match anywhere in the
    /// text.
    ///
    /// # Example
    ///
    /// Tests whether a set matches some text:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap();
    /// assert!(set.is_match("foo"));
    /// assert!(!set.is_match("☃"));
    /// ```
    pub fn is_match(&self, text: $text_ty) -> bool {
        self.0.searcher().is_match_at($as_bytes(text), 0)
    }

    /// Returns the set of regular expressions that match in the given text.
    ///
    /// The set returned contains the index of each regular expression that
    /// matches in the given text. The index is in correspondence with the
    /// order of regular expressions given to `RegexSet`'s constructor.
    ///
    /// The set can also be used to iterate over the matched indices.
    ///
    /// Note that as with searches using `Regex`, the expression is unanchored
    /// by default. That is, if the regex does not start with `^` or `\A`, or
    /// end with `$` or `\z`, then it is permitted to match anywhere in the
    /// text.
    ///
    /// # Example
    ///
    /// Tests which regular expressions match the given text:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[
    ///     r"\w+",
    ///     r"\d+",
    ///     r"\pL+",
    ///     r"foo",
    ///     r"bar",
    ///     r"barfoo",
    ///     r"foobar",
    /// ]).unwrap();
    /// let matches: Vec<_> = set.matches("foobar").into_iter().collect();
    /// assert_eq!(matches, vec![0, 2, 3, 4, 6]);
    ///
    /// // You can also test whether a particular regex matched:
    /// let matches = set.matches("foobar");
    /// assert!(!matches.matched(5));
    /// assert!(matches.matched(6));
    /// ```
    pub fn matches(&self, text: $text_ty) -> SetMatches {
        let mut matches = vec![false; self.0.regex_strings().len()];
        let any = self.0.searcher().many_matches_at(
            &mut matches, $as_bytes(text), 0);
        SetMatches {
            matched_any: any,
            matches: matches,
        }
    }

    /// Returns the total number of regular expressions in this set.
    pub fn len(&self) -> usize {
        self.0.regex_strings().len()
    }
}

/// A set of matches returned by a regex set.
#[derive(Clone, Debug)]
pub struct SetMatches {
    matched_any: bool,
    matches: Vec<bool>,
}

impl SetMatches {
    /// Whether this set contains any matches.
    pub fn matched_any(&self) -> bool {
        self.matched_any
    }

    /// Whether the regex at the given index matched.
    ///
    /// The index for a regex is determined by its insertion order upon the
    /// initial construction of a `RegexSet`, starting at `0`.
    ///
    /// # Panics
    ///
    /// If `regex_index` is greater than or equal to `self.len()`.
    pub fn matched(&self, regex_index: usize) -> bool {
        self.matches[regex_index]
    }

    /// The total number of regexes in the set that created these matches.
    pub fn len(&self) -> usize {
        self.matches.len()
    }

    /// Returns an iterator over indexes in the regex that matched.
    pub fn iter(&self) -> SetMatchesIter {
        SetMatchesIter((&*self.matches).into_iter().enumerate())
    }
}

impl IntoIterator for SetMatches {
    type IntoIter = SetMatchesIntoIter;
    type Item = usize;

    fn into_iter(self) -> Self::IntoIter {
        SetMatchesIntoIter(self.matches.into_iter().enumerate())
    }
}

impl<'a> IntoIterator for &'a SetMatches {
    type IntoIter = SetMatchesIter<'a>;
    type Item = usize;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

/// An owned iterator over the set of matches from a regex set.
pub struct SetMatchesIntoIter(iter::Enumerate<vec::IntoIter<bool>>);

impl Iterator for SetMatchesIntoIter {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.0.next() {
                None => return None,
                Some((_, false)) => {}
                Some((i, true)) => return Some(i),
            }
        }
    }
}

impl DoubleEndedIterator for SetMatchesIntoIter {
    fn next_back(&mut self) -> Option<usize> {
        loop {
            match self.0.next_back() {
                None => return None,
                Some((_, false)) => {}
                Some((i, true)) => return Some(i),
            }
        }
    }
}

/// A borrowed iterator over the set of matches from a regex set.
///
/// The lifetime `'a` refers to the lifetime of a `SetMatches` value.
#[derive(Clone)]
pub struct SetMatchesIter<'a>(iter::Enumerate<slice::Iter<'a, bool>>);

impl<'a> Iterator for SetMatchesIter<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.0.next() {
                None => return None,
                Some((_, &false)) => {}
                Some((i, &true)) => return Some(i),
            }
        }
    }
}

impl<'a> DoubleEndedIterator for SetMatchesIter<'a> {
    fn next_back(&mut self) -> Option<usize> {
        loop {
            match self.0.next_back() {
                None => return None,
                Some((_, &false)) => {}
                Some((i, &true)) => return Some(i),
            }
        }
    }
}

#[doc(hidden)]
impl From<Exec> for RegexSet {
    fn from(exec: Exec) -> Self {
        RegexSet(exec)
    }
}

impl fmt::Debug for RegexSet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RegexSet({:?})", self.0.regex_strings())
    }
}

#[allow(dead_code)] fn as_bytes_str(text: &str) -> &[u8] { text.as_bytes() }
#[allow(dead_code)] fn as_bytes_bytes(text: &[u8]) -> &[u8] { text }
        }
    }
}

define_set! {
    unicode,
    |exprs| ExecBuilder::new_many(exprs).build(),
    &str,
    as_bytes_str
}

define_set! {
    bytes,
    |exprs| ExecBuilder::new_many(exprs).only_utf8(false).build(),
    &[u8],
    as_bytes_bytes
}
<commit_msg>Use separate example for RegexSet and bytes::RegexSet<commit_after>// Copyright 2014-2015 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.

macro_rules! define_set {
    ($name:ident, $exec_build:expr, $text_ty:ty, $as_bytes:expr,
     $(#[$doc_regexset_example:meta])* ) => {
        pub mod $name {
            use std::fmt;
            use std::iter;
            use std::slice;
            use std::vec;

            use error::Error;
            use exec::{Exec, ExecBuilder};
            use re_trait::RegularExpression;

/// Match multiple (possibly overlapping) regular expressions in a single scan.
///
/// A regex set corresponds to the union of two or more regular expressions.
/// That is, a regex set will match text where at least one of its
/// constituent regular expressions matches. A regex set as its formulated here
/// provides a touch more power: it will also report *which* regular
/// expressions in the set match. Indeed, this is the key difference between
/// regex sets and a single `Regex` with many alternates, since only one
/// alternate can match at a time.
///
/// For example, consider regular expressions to match email addresses and
/// domains: `[a-z]+@[a-z]+\.(com|org|net)` and `[a-z]+\.(com|org|net)`. If a
/// regex set is constructed from those regexes, then searching the text
/// `foo@example.com` will report both regexes as matching. Of course, one
/// could accomplish this by compiling each regex on its own and doing two
/// searches over the text. The key advantage of using a regex set is that it
/// will report the matching regexes using a *single pass through the text*.
/// If one has hundreds or thousands of regexes to match repeatedly (like a URL
/// router for a complex web application or a user agent matcher), then a regex
/// set can realize huge performance gains.
///
/// # Example
///
/// This shows how the above two regexes (for matching email addresses and
/// domains) might work:
///
$(#[$doc_regexset_example])*
///
/// Note that it would be possible to adapt the above example to using `Regex`
/// with an expression like:
///
/// ```ignore
/// (?P<email>[a-z]+@(?P<email_domain>[a-z]+[.](com|org|net)))|(?P<domain>[a-z]+[.](com|org|net))
/// ```
///
/// After a match, one could then inspect the capture groups to figure out
/// which alternates matched. The problem is that it is hard to make this
/// approach scale when there are many regexes since the overlap between each
/// alternate isn't always obvious to reason about.
///
/// # Limitations
///
/// Regex sets are limited to answering the following two questions:
///
/// 1. Does any regex in the set match?
/// 2. If so, which regexes in the set match?
///
/// As with the main `Regex` type, it is cheaper to ask (1) instead of (2)
/// since the matching engines can stop after the first match is found.
///
/// Other features like finding the location of successive matches or their
/// sub-captures aren't supported. If you need this functionality, the
/// recommended approach is to compile each regex in the set independently and
/// selectively match them based on which regexes in the set matched.
///
/// # Performance
///
/// A `RegexSet` has the same performance characteristics as `Regex`. Namely,
/// search takes `O(mn)` time, where `m` is proportional to the size of the
/// regex set and `n` is proportional to the length of the search text.
#[derive(Clone)]
pub struct RegexSet(Exec);

impl RegexSet {
    /// Create a new regex set with the given regular expressions.
    ///
    /// This takes an iterator of `S`, where `S` is something that can produce
    /// a `&str`. If any of the strings in the iterator are not valid regular
    /// expressions, then an error is returned.
    ///
    /// # Example
    ///
    /// Create a new regex set from an iterator of strings:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap();
    /// assert!(set.is_match("foo"));
    /// ```
    pub fn new<I, S>(exprs: I) -> Result<RegexSet, Error>
            where S: AsRef<str>, I: IntoIterator<Item=S> {
        let exec = try!($exec_build(exprs));
        Ok(RegexSet(exec))
    }

    /// Returns true if and only if one of the regexes in this set matches
    /// the text given.
    ///
    /// This method should be preferred if you only need to test whether any
    /// of the regexes in the set should match, but don't care about *which*
    /// regexes matched. This is because the underlying matching engine will
    /// quit immediately after seeing the first match instead of continuing to
    /// find all matches.
    ///
    /// Note that as with searches using `Regex`, the expression is unanchored
    /// by default. That is, if the regex does not start with `^` or `\A`, or
    /// end with `$` or `\z`, then it is permitted to match anywhere in the
    /// text.
    ///
    /// # Example
    ///
    /// Tests whether a set matches some text:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap();
    /// assert!(set.is_match("foo"));
    /// assert!(!set.is_match("☃"));
    /// ```
    pub fn is_match(&self, text: $text_ty) -> bool {
        self.0.searcher().is_match_at($as_bytes(text), 0)
    }

    /// Returns the set of regular expressions that match in the given text.
    ///
    /// The set returned contains the index of each regular expression that
    /// matches in the given text. The index is in correspondence with the
    /// order of regular expressions given to `RegexSet`'s constructor.
    ///
    /// The set can also be used to iterate over the matched indices.
    ///
    /// Note that as with searches using `Regex`, the expression is unanchored
    /// by default. That is, if the regex does not start with `^` or `\A`, or
    /// end with `$` or `\z`, then it is permitted to match anywhere in the
    /// text.
    ///
    /// # Example
    ///
    /// Tests which regular expressions match the given text:
    ///
    /// ```rust
    /// # use regex::RegexSet;
    /// let set = RegexSet::new(&[
    ///     r"\w+",
    ///     r"\d+",
    ///     r"\pL+",
    ///     r"foo",
    ///     r"bar",
    ///     r"barfoo",
    ///     r"foobar",
    /// ]).unwrap();
    /// let matches: Vec<_> = set.matches("foobar").into_iter().collect();
    /// assert_eq!(matches, vec![0, 2, 3, 4, 6]);
    ///
    /// // You can also test whether a particular regex matched:
    /// let matches = set.matches("foobar");
    /// assert!(!matches.matched(5));
    /// assert!(matches.matched(6));
    /// ```
    pub fn matches(&self, text: $text_ty) -> SetMatches {
        let mut matches = vec![false; self.0.regex_strings().len()];
        let any = self.0.searcher().many_matches_at(
            &mut matches, $as_bytes(text), 0);
        SetMatches {
            matched_any: any,
            matches: matches,
        }
    }

    /// Returns the total number of regular expressions in this set.
    pub fn len(&self) -> usize {
        self.0.regex_strings().len()
    }
}

/// A set of matches returned by a regex set.
#[derive(Clone, Debug)]
pub struct SetMatches {
    matched_any: bool,
    matches: Vec<bool>,
}

impl SetMatches {
    /// Whether this set contains any matches.
    pub fn matched_any(&self) -> bool {
        self.matched_any
    }

    /// Whether the regex at the given index matched.
    ///
    /// The index for a regex is determined by its insertion order upon the
    /// initial construction of a `RegexSet`, starting at `0`.
    ///
    /// # Panics
    ///
    /// If `regex_index` is greater than or equal to `self.len()`.
    pub fn matched(&self, regex_index: usize) -> bool {
        self.matches[regex_index]
    }

    /// The total number of regexes in the set that created these matches.
    pub fn len(&self) -> usize {
        self.matches.len()
    }

    /// Returns an iterator over indexes in the regex that matched.
    pub fn iter(&self) -> SetMatchesIter {
        SetMatchesIter((&*self.matches).into_iter().enumerate())
    }
}

impl IntoIterator for SetMatches {
    type IntoIter = SetMatchesIntoIter;
    type Item = usize;

    fn into_iter(self) -> Self::IntoIter {
        SetMatchesIntoIter(self.matches.into_iter().enumerate())
    }
}

impl<'a> IntoIterator for &'a SetMatches {
    type IntoIter = SetMatchesIter<'a>;
    type Item = usize;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

/// An owned iterator over the set of matches from a regex set.
pub struct SetMatchesIntoIter(iter::Enumerate<vec::IntoIter<bool>>);

impl Iterator for SetMatchesIntoIter {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.0.next() {
                None => return None,
                Some((_, false)) => {}
                Some((i, true)) => return Some(i),
            }
        }
    }
}

impl DoubleEndedIterator for SetMatchesIntoIter {
    fn next_back(&mut self) -> Option<usize> {
        loop {
            match self.0.next_back() {
                None => return None,
                Some((_, false)) => {}
                Some((i, true)) => return Some(i),
            }
        }
    }
}

/// A borrowed iterator over the set of matches from a regex set.
///
/// The lifetime `'a` refers to the lifetime of a `SetMatches` value.
#[derive(Clone)]
pub struct SetMatchesIter<'a>(iter::Enumerate<slice::Iter<'a, bool>>);

impl<'a> Iterator for SetMatchesIter<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.0.next() {
                None => return None,
                Some((_, &false)) => {}
                Some((i, &true)) => return Some(i),
            }
        }
    }
}

impl<'a> DoubleEndedIterator for SetMatchesIter<'a> {
    fn next_back(&mut self) -> Option<usize> {
        loop {
            match self.0.next_back() {
                None => return None,
                Some((_, &false)) => {}
                Some((i, &true)) => return Some(i),
            }
        }
    }
}

#[doc(hidden)]
impl From<Exec> for RegexSet {
    fn from(exec: Exec) -> Self {
        RegexSet(exec)
    }
}

impl fmt::Debug for RegexSet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RegexSet({:?})", self.0.regex_strings())
    }
}

#[allow(dead_code)] fn as_bytes_str(text: &str) -> &[u8] { text.as_bytes() }
#[allow(dead_code)] fn as_bytes_bytes(text: &[u8]) -> &[u8] { text }
        }
    }
}

define_set! {
    unicode,
    |exprs| ExecBuilder::new_many(exprs).build(),
    &str,
    as_bytes_str,
/// ```rust
/// # use regex::RegexSet;
/// let set = RegexSet::new(&[
///     r"[a-z]+@[a-z]+\.(com|org|net)",
///     r"[a-z]+\.(com|org|net)",
/// ]).unwrap();
///
/// // Ask whether any regexes in the set match.
/// assert!(set.is_match("foo@example.com"));
///
/// // Identify which regexes in the set match.
/// let matches: Vec<_> = set.matches("foo@example.com").into_iter().collect();
/// assert_eq!(vec![0, 1], matches);
///
/// // Try again, but with text that only matches one of the regexes.
/// let matches: Vec<_> = set.matches("example.com").into_iter().collect();
/// assert_eq!(vec![1], matches);
///
/// // Try again, but with text that doesn't match any regex in the set.
/// let matches: Vec<_> = set.matches("example").into_iter().collect();
/// assert!(matches.is_empty());
/// ```
}

define_set! {
    bytes,
    |exprs| ExecBuilder::new_many(exprs).only_utf8(false).build(),
    &[u8],
    as_bytes_bytes,
/// ```rust
/// # use regex::bytes::RegexSet;
/// let set = RegexSet::new(&[
///     r"[a-z]+@[a-z]+\.(com|org|net)",
///     r"[a-z]+\.(com|org|net)",
/// ]).unwrap();
///
/// // Ask whether any regexes in the set match.
/// assert!(set.is_match(b"foo@example.com"));
///
/// // Identify which regexes in the set match.
/// let matches: Vec<_> = set.matches(b"foo@example.com").into_iter().collect();
/// assert_eq!(vec![0, 1], matches);
///
/// // Try again, but with text that only matches one of the regexes.
/// let matches: Vec<_> = set.matches(b"example.com").into_iter().collect();
/// assert_eq!(vec![1], matches);
///
/// // Try again, but with text that doesn't match any regex in the set.
/// let matches: Vec<_> = set.matches(b"example").into_iter().collect();
/// assert!(matches.is_empty());
/// ```
}
<|endoftext|>


<commit_before>use log::{error, warn};
use std::cmp;
use std::convert::TryInto;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Mutex;

#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
use rayon::prelude::*;

use super::parser;
use super::{Document, Object, ObjectId};
use crate::object_stream::ObjectStream;
use crate::xref::XrefEntry;
use crate::{Error, Result};
use crate::error::XrefError;

impl Document {
	/// Load a PDF document from a specified file path.
	#[inline]
	pub fn load<P: AsRef<Path>>(path: P) -> Result<Document> {
		let file = File::open(path)?;
		let capacity = Some(file.metadata()?.len() as usize);
		Self::load_internal(file, capacity)
	}

	/// Load a PDF document from an arbitrary source.
	#[inline]
	pub fn load_from<R: Read>(source: R) -> Result<Document> {
		Self::load_internal(source, None)
	}

	fn load_internal<R: Read>(mut source: R, capacity: Option<usize>) -> Result<Document> {
		let mut buffer = capacity.map(Vec::with_capacity).unwrap_or_else(Vec::new);
		source.read_to_end(&mut buffer)?;

		Reader {
			buffer: &buffer,
			document: Document::new(),
		}.read()
	}

	/// Load a PDF document from a memory slice.
	pub fn load_mem(buffer: &[u8]) -> Result<Document> {
		buffer.try_into()
	}
}

impl TryInto<Document> for &[u8] {
	type Error = Error;

	fn try_into(self) -> Result<Document> {
		Reader {
			buffer: self,
			document: Document::new(),
		}.read()
	}
}

pub struct Reader<'a> {
	buffer: &'a [u8],
	document: Document,
}

impl <'a> Reader<'a> {
	/// Read whole document.
	fn read(mut self) -> Result<Document> {
		// The document structure can be expressed in PEG as:
		//   document <- header indirect_object* xref trailer xref_start
		let version = parser::header(&self.buffer).ok_or(Error::Header)?;

		let xref_start = Self::get_xref_start(&self.buffer)?;
		if xref_start > self.buffer.len() {
			return Err(Error::Xref(XrefError::Start));
		}

		let (mut xref, mut trailer) = parser::xref_and_trailer(&self.buffer[xref_start..], &self)?;

		// Read previous Xrefs of linearized or incremental updated document.
		let mut prev_xref_start = trailer.remove(b"Prev");
		while let Some(prev) = prev_xref_start.and_then(|offset| offset.as_i64().ok()) {
			let prev = prev as usize;
			if prev > self.buffer.len() {
				return Err(Error::Xref(XrefError::PrevStart));
			}
			let (prev_xref, mut prev_trailer) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
			xref.extend(prev_xref);

			// Read xref stream in hybrid-reference file
			let prev_xref_stream_start = trailer.remove(b"XRefStm");
			if let Some(prev) = prev_xref_stream_start.and_then(|offset| offset.as_i64().ok()) {
				let prev = prev as usize;
				if prev > self.buffer.len() {
					return Err(Error::Xref(XrefError::StreamStart));
				}
				let (prev_xref, _) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
				xref.extend(prev_xref);
			}

			prev_xref_start = prev_trailer.remove(b"Prev");
		}

		let xref_entry_count = xref.max_id() + 1;
		if xref.size != xref_entry_count {
			warn!("Size entry of trailer dictionary is {}, correct value is {}.", xref.size, xref_entry_count);
			xref.size = xref_entry_count;
		}

		self.document.version = version;
		self.document.max_id = xref.size - 1;
		self.document.trailer = trailer;
		self.document.reference_table = xref;

		let zero_length_streams = Mutex::new(vec![]);
		let object_streams = Mutex::new(vec![]);

		let entries_filter_map = |(_, entry): (&_, &_)| {
			if let XrefEntry::Normal { offset, .. } = *entry {
				let (object_id, mut object) = self.read_object(offset as usize, None)
					.map_err(|e| error!("Object load error: {:?}", e)).ok()?;
				if let Ok(ref mut stream) = object.as_stream_mut() {
					if stream.dict.type_is(b"ObjStm") {
						let obj_stream = ObjectStream::new(stream).ok()?;
						let mut object_streams = object_streams.lock().unwrap();
						object_streams.extend(obj_stream.objects);
					} else if stream.content.is_empty() {
						let mut zero_length_streams = zero_length_streams.lock().unwrap();
						zero_length_streams.push(object_id);
					}
				}
				Some((object_id, object))
			} else {
				None
			}
		};
		#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
		{
			self.document.objects =	self.document.reference_table.entries.par_iter().filter_map(entries_filter_map).collect();
		}
		#[cfg(all(target_arch =	"wasm32", not(target_os	= "emscripten")))]
		{
			self.document.objects =	self.document.reference_table.entries.iter().filter_map(entries_filter_map).collect();
		}
		self.document.objects.extend(object_streams.into_inner().unwrap());

		for object_id in zero_length_streams.into_inner().unwrap() {
			let _ = self.set_stream_content(object_id);
		}

		Ok(self.document)
	}

	fn set_stream_content(&mut self, object_id: ObjectId) -> Result<()> {
		let length = self.get_stream_length(object_id)?;
		let stream = self.document.get_object_mut(object_id).and_then(Object::as_stream_mut)?;
		let start = stream.start_position.ok_or(Error::ObjectNotFound)?;

		let end = start + length as usize;
		stream.set_content(self.buffer[start..end].to_vec());
		Ok(())
	}

	fn get_stream_length(&self, object_id: ObjectId) -> Result<i64> {
		let object = self.document.get_object(object_id)?;
		let stream = object.as_stream()?;

		stream.dict.get(b"Length").and_then(|value| {
			if let Ok(id) = value.as_reference() {
				return self.document.get_object(id).and_then(Object::as_i64);
			}
			value.as_i64()
		})
	}

	/// Get object offset by object id.
	fn get_offset(&self, id: ObjectId) -> Result<u32> {
		let entry = self.document.reference_table.get(id.0).ok_or(Error::ObjectNotFound)?;
		match *entry {
			XrefEntry::Normal { offset, generation } => {
				if id.1 == generation {
					Ok(offset)
				} else {
					Err(Error::ObjectNotFound)
				}
			}
			_ => Err(Error::ObjectNotFound),
		}
	}

	pub fn get_object(&self, id: ObjectId) -> Result<Object> {
		let offset = self.get_offset(id)?;
		let (_, obj) = self.read_object(offset as usize, Some(id))?;

		Ok(obj)
	}

	fn read_object(&self, offset: usize, expected_id: Option<ObjectId>) -> Result<(ObjectId, Object)> {
		if offset > self.buffer.len() {
			return Err(Error::Offset(offset));
		}

		parser::indirect_object(&self.buffer, offset, expected_id, self)
	}

	fn get_xref_start(buffer: &[u8]) -> Result<usize> {
		let seek_pos = buffer.len() - cmp::min(buffer.len(), 512);
		Self::search_substring(buffer, b"%%EOF", seek_pos)
			.and_then(|eof_pos| if eof_pos > 25 { Some(eof_pos) } else { None })
			.and_then(|eof_pos| Self::search_substring(buffer, b"startxref", eof_pos - 25))
			.ok_or(Error::Xref(XrefError::Start))
			.and_then(|xref_pos| if xref_pos <= buffer.len() {
				match parser::xref_start(&buffer[xref_pos..]) {
					Some(startxref) => Ok(startxref as usize),
					None => Err(Error::Xref(XrefError::Start)),
				}
			} else {
				Err(Error::Xref(XrefError::Start))
			})
	}

	fn search_substring(buffer: &[u8], pattern: &[u8], start_pos: usize) -> Option<usize> {
		let mut seek_pos = start_pos;
		let mut index = 0;

		while seek_pos < buffer.len() && index < pattern.len() {
			if buffer[seek_pos] == pattern[index] {
				index += 1;
			} else if index > 0 {
				seek_pos -= index;
				index = 0;
			}
			seek_pos += 1;

			if index == pattern.len() {
				let res = seek_pos - index;
				return Self::search_substring(buffer, pattern, res + 1).or(Some(res));
			}
		}

		None
	}
}

#[test]
fn load_document() {
	let mut doc = Document::load("assets/example.pdf").unwrap();
	assert_eq!(doc.version, "1.5");
	doc.save("test_2_load.pdf").unwrap();
}
<commit_msg>Add a test for #93 (#95)<commit_after>use log::{error, warn};
use std::cmp;
use std::convert::TryInto;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Mutex;

#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
use rayon::prelude::*;

use super::parser;
use super::{Document, Object, ObjectId};
use crate::object_stream::ObjectStream;
use crate::xref::XrefEntry;
use crate::{Error, Result};
use crate::error::XrefError;

impl Document {
	/// Load a PDF document from a specified file path.
	#[inline]
	pub fn load<P: AsRef<Path>>(path: P) -> Result<Document> {
		let file = File::open(path)?;
		let capacity = Some(file.metadata()?.len() as usize);
		Self::load_internal(file, capacity)
	}

	/// Load a PDF document from an arbitrary source.
	#[inline]
	pub fn load_from<R: Read>(source: R) -> Result<Document> {
		Self::load_internal(source, None)
	}

	fn load_internal<R: Read>(mut source: R, capacity: Option<usize>) -> Result<Document> {
		let mut buffer = capacity.map(Vec::with_capacity).unwrap_or_else(Vec::new);
		source.read_to_end(&mut buffer)?;

		Reader {
			buffer: &buffer,
			document: Document::new(),
		}.read()
	}

	/// Load a PDF document from a memory slice.
	pub fn load_mem(buffer: &[u8]) -> Result<Document> {
		buffer.try_into()
	}
}

impl TryInto<Document> for &[u8] {
	type Error = Error;

	fn try_into(self) -> Result<Document> {
		Reader {
			buffer: self,
			document: Document::new(),
		}.read()
	}
}

pub struct Reader<'a> {
	buffer: &'a [u8],
	document: Document,
}

impl <'a> Reader<'a> {
	/// Read whole document.
	fn read(mut self) -> Result<Document> {
		// The document structure can be expressed in PEG as:
		//   document <- header indirect_object* xref trailer xref_start
		let version = parser::header(&self.buffer).ok_or(Error::Header)?;

		let xref_start = Self::get_xref_start(&self.buffer)?;
		if xref_start > self.buffer.len() {
			return Err(Error::Xref(XrefError::Start));
		}

		let (mut xref, mut trailer) = parser::xref_and_trailer(&self.buffer[xref_start..], &self)?;

		// Read previous Xrefs of linearized or incremental updated document.
		let mut prev_xref_start = trailer.remove(b"Prev");
		while let Some(prev) = prev_xref_start.and_then(|offset| offset.as_i64().ok()) {
			let prev = prev as usize;
			if prev > self.buffer.len() {
				return Err(Error::Xref(XrefError::PrevStart));
			}
			let (prev_xref, mut prev_trailer) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
			xref.extend(prev_xref);

			// Read xref stream in hybrid-reference file
			let prev_xref_stream_start = trailer.remove(b"XRefStm");
			if let Some(prev) = prev_xref_stream_start.and_then(|offset| offset.as_i64().ok()) {
				let prev = prev as usize;
				if prev > self.buffer.len() {
					return Err(Error::Xref(XrefError::StreamStart));
				}
				let (prev_xref, _) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
				xref.extend(prev_xref);
			}

			prev_xref_start = prev_trailer.remove(b"Prev");
		}

		let xref_entry_count = xref.max_id() + 1;
		if xref.size != xref_entry_count {
			warn!("Size entry of trailer dictionary is {}, correct value is {}.", xref.size, xref_entry_count);
			xref.size = xref_entry_count;
		}

		self.document.version = version;
		self.document.max_id = xref.size - 1;
		self.document.trailer = trailer;
		self.document.reference_table = xref;

		let zero_length_streams = Mutex::new(vec![]);
		let object_streams = Mutex::new(vec![]);

		let entries_filter_map = |(_, entry): (&_, &_)| {
			if let XrefEntry::Normal { offset, .. } = *entry {
				let (object_id, mut object) = self.read_object(offset as usize, None)
					.map_err(|e| error!("Object load error: {:?}", e)).ok()?;
				if let Ok(ref mut stream) = object.as_stream_mut() {
					if stream.dict.type_is(b"ObjStm") {
						let obj_stream = ObjectStream::new(stream).ok()?;
						let mut object_streams = object_streams.lock().unwrap();
						object_streams.extend(obj_stream.objects);
					} else if stream.content.is_empty() {
						let mut zero_length_streams = zero_length_streams.lock().unwrap();
						zero_length_streams.push(object_id);
					}
				}
				Some((object_id, object))
			} else {
				None
			}
		};
		#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
		{
			self.document.objects =	self.document.reference_table.entries.par_iter().filter_map(entries_filter_map).collect();
		}
		#[cfg(all(target_arch =	"wasm32", not(target_os	= "emscripten")))]
		{
			self.document.objects =	self.document.reference_table.entries.iter().filter_map(entries_filter_map).collect();
		}
		self.document.objects.extend(object_streams.into_inner().unwrap());

		for object_id in zero_length_streams.into_inner().unwrap() {
			let _ = self.set_stream_content(object_id);
		}

		Ok(self.document)
	}

	fn set_stream_content(&mut self, object_id: ObjectId) -> Result<()> {
		let length = self.get_stream_length(object_id)?;
		let stream = self.document.get_object_mut(object_id).and_then(Object::as_stream_mut)?;
		let start = stream.start_position.ok_or(Error::ObjectNotFound)?;

		let end = start + length as usize;
		stream.set_content(self.buffer[start..end].to_vec());
		Ok(())
	}

	fn get_stream_length(&self, object_id: ObjectId) -> Result<i64> {
		let object = self.document.get_object(object_id)?;
		let stream = object.as_stream()?;

		stream.dict.get(b"Length").and_then(|value| {
			if let Ok(id) = value.as_reference() {
				return self.document.get_object(id).and_then(Object::as_i64);
			}
			value.as_i64()
		})
	}

	/// Get object offset by object id.
	fn get_offset(&self, id: ObjectId) -> Result<u32> {
		let entry = self.document.reference_table.get(id.0).ok_or(Error::ObjectNotFound)?;
		match *entry {
			XrefEntry::Normal { offset, generation } => {
				if id.1 == generation {
					Ok(offset)
				} else {
					Err(Error::ObjectNotFound)
				}
			}
			_ => Err(Error::ObjectNotFound),
		}
	}

	pub fn get_object(&self, id: ObjectId) -> Result<Object> {
		let offset = self.get_offset(id)?;
		let (_, obj) = self.read_object(offset as usize, Some(id))?;

		Ok(obj)
	}

	fn read_object(&self, offset: usize, expected_id: Option<ObjectId>) -> Result<(ObjectId, Object)> {
		if offset > self.buffer.len() {
			return Err(Error::Offset(offset));
		}

		parser::indirect_object(&self.buffer, offset, expected_id, self)
	}

	fn get_xref_start(buffer: &[u8]) -> Result<usize> {
		let seek_pos = buffer.len() - cmp::min(buffer.len(), 512);
		Self::search_substring(buffer, b"%%EOF", seek_pos)
			.and_then(|eof_pos| if eof_pos > 25 { Some(eof_pos) } else { None })
			.and_then(|eof_pos| Self::search_substring(buffer, b"startxref", eof_pos - 25))
			.ok_or(Error::Xref(XrefError::Start))
			.and_then(|xref_pos| if xref_pos <= buffer.len() {
				match parser::xref_start(&buffer[xref_pos..]) {
					Some(startxref) => Ok(startxref as usize),
					None => Err(Error::Xref(XrefError::Start)),
				}
			} else {
				Err(Error::Xref(XrefError::Start))
			})
	}

	fn search_substring(buffer: &[u8], pattern: &[u8], start_pos: usize) -> Option<usize> {
		let mut seek_pos = start_pos;
		let mut index = 0;

		while seek_pos < buffer.len() && index < pattern.len() {
			if buffer[seek_pos] == pattern[index] {
				index += 1;
			} else if index > 0 {
				seek_pos -= index;
				index = 0;
			}
			seek_pos += 1;

			if index == pattern.len() {
				let res = seek_pos - index;
				return Self::search_substring(buffer, pattern, res + 1).or(Some(res));
			}
		}

		None
	}
}

#[test]
fn load_document() {
	let mut doc = Document::load("assets/example.pdf").unwrap();
	assert_eq!(doc.version, "1.5");
	doc.save("test_2_load.pdf").unwrap();
}

#[test]
#[should_panic(expected = "Xref(Start)")]
fn load_short_document() {
	let _doc = Document::load_mem(b"%PDF-1.5\n%%EOF\n").unwrap();
}
<|endoftext|>


<commit_before>use log::{error, warn};
use std::cmp;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Mutex;

use rayon::prelude::*;

use super::parser;
use super::{Document, Object, ObjectId};
use crate::object_stream::ObjectStream;
use crate::xref::XrefEntry;
use crate::{Error, Result};
use crate::error::XrefError;

impl Document {
	/// Load a PDF document from a specified file path.
	#[inline]
	pub fn load<P: AsRef<Path>>(path: P) -> Result<Document> {
		let file = File::open(path)?;
		let buffer = Vec::with_capacity(file.metadata()?.len() as usize);
		Self::load_internal(file, buffer)
	}

	/// Load a PDF document from an arbitrary source.
	#[inline]
	pub fn load_from<R: Read>(source: R) -> Result<Document> {
		let buffer = Vec::<u8>::new();
		Self::load_internal(source, buffer)
	}

	fn load_internal<R: Read>(mut source: R, mut buffer: Vec<u8>) -> Result<Document> {
		source.read_to_end(&mut buffer)?;

		let mut reader = Reader {
			buffer: &buffer,
			document: Document::new(),
		};

		reader.read()?;
		Ok(reader.document)
	}

	/// Load a PDF document from a memory slice.
	pub fn load_mem(buffer: &[u8]) -> Result<Document> {
		let mut reader = Reader {
			buffer,
			document: Document::new(),
		};
		reader.read()?;
		Ok(reader.document)
	}
}

pub struct Reader<'a> {
	buffer: &'a [u8],
	document: Document,
}

impl <'a> Reader<'a> {
	/// Read whole document.
	fn read(&mut self) -> Result<()> {
		// The document structure can be expressed in PEG as:
		//   document <- header indirect_object* xref trailer xref_start
		let version = parser::header(&self.buffer).ok_or(Error::Header)?;

		let xref_start = Self::get_xref_start(&self.buffer)?;
		if xref_start > self.buffer.len() {
			return Err(Error::Xref(XrefError::Start));
		}

		let (mut xref, mut trailer) = parser::xref_and_trailer(&self.buffer[xref_start..], self)?;

		// Read previous Xrefs of linearized or incremental updated document.
		let mut prev_xref_start = trailer.remove(b"Prev");
		while let Some(prev) = prev_xref_start.and_then(|offset| offset.as_i64().ok()) {
			let prev = prev as usize;
			if prev > self.buffer.len() {
				return Err(Error::Xref(XrefError::PrevStart));
			}
			let (prev_xref, mut prev_trailer) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
			xref.extend(prev_xref);

			// Read xref stream in hybrid-reference file
			let prev_xref_stream_start = trailer.remove(b"XRefStm");
			if let Some(prev) = prev_xref_stream_start.and_then(|offset| offset.as_i64().ok()) {
				let prev = prev as usize;
				if prev > self.buffer.len() {
					return Err(Error::Xref(XrefError::StreamStart));
				}
				let (prev_xref, _) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
				xref.extend(prev_xref);
			}

			prev_xref_start = prev_trailer.remove(b"Prev");
		}

		let xref_entry_count = xref.max_id() + 1;
		if xref.size != xref_entry_count {
			warn!("Size entry of trailer dictionary is {}, correct value is {}.", xref.size, xref_entry_count);
			xref.size = xref_entry_count;
		}

		self.document.version = version;
		self.document.max_id = xref.size - 1;
		self.document.trailer = trailer;
		self.document.reference_table = xref;

		let zero_length_streams = Mutex::new(vec![]);
		let object_streams = Mutex::new(vec![]);

		self.document.objects = self.document.reference_table.entries.par_iter().filter_map(|(_, entry)| {
			if let XrefEntry::Normal { offset, .. } = *entry {
				let (object_id, mut object) = self.read_object(offset as usize)
					.map_err(|e| error!("Object load error: {:?}", e)).ok()?;
				if let Ok(ref mut stream) = object.as_stream_mut() {
					if stream.dict.type_is(b"ObjStm") {
						let obj_stream = ObjectStream::new(stream).ok()?;
						let mut object_streams = object_streams.lock().unwrap();
						object_streams.extend(obj_stream.objects);
					} else if stream.content.is_empty() {
						let mut zero_length_streams = zero_length_streams.lock().unwrap();
						zero_length_streams.push(object_id);
					}
				}
				Some((object_id, object))
			} else {
				None
			}
		}).collect();

		self.document.objects.extend(object_streams.into_inner().unwrap());

		for object_id in zero_length_streams.into_inner().unwrap() {
			let _ = self.set_stream_content(object_id);
		}

		Ok(())
	}

	fn set_stream_content(&mut self, object_id: ObjectId) -> Result<()> {
		let length = self.get_stream_length(object_id)?;
		let stream = self.document.get_object_mut(object_id).and_then(Object::as_stream_mut)?;
		let start = stream.start_position.ok_or(Error::ObjectNotFound)?;

		let end = start + length as usize;
		stream.set_content(self.buffer[start..end].to_vec());
		Ok(())
	}

	fn get_stream_length(&self, object_id: ObjectId) -> Result<i64> {
		let object = self.document.get_object(object_id)?;
		let stream = object.as_stream()?;

		stream.dict.get(b"Length").and_then(|value| {
			if let Ok(id) = value.as_reference() {
				return self.document.get_object(id).and_then(Object::as_i64);
			}
			value.as_i64()
		})
	}

	/// Get object offset by object id.
	fn get_offset(&self, id: ObjectId) -> Result<u32> {
		let entry = self.document.reference_table.get(id.0).ok_or(Error::ObjectNotFound)?;
		match *entry {
			XrefEntry::Normal { offset, generation } => {
				if id.1 == generation {
					Ok(offset)
				} else {
					Err(Error::ObjectNotFound)
				}
			}
			_ => Err(Error::ObjectNotFound),
		}
	}

	pub fn get_object(&self, id: ObjectId) -> Result<Object> {
		let offset = self.get_offset(id)?;
		let (_, obj) = self.read_object(offset as usize)?;

		Ok(obj)
	}

	fn read_object(&self, offset: usize) -> Result<(ObjectId, Object)> {
		if offset > self.buffer.len() {
			return Err(Error::Offset(offset));
		}

		parser::indirect_object(&self.buffer, offset, self)
	}

	fn get_xref_start(buffer: &[u8]) -> Result<usize> {
		let seek_pos = buffer.len() - cmp::min(buffer.len(), 512);
		Self::search_substring(buffer, b"%%EOF", seek_pos)
			.and_then(|eof_pos| Self::search_substring(buffer, b"startxref", eof_pos - 25))
			.ok_or(Error::Xref(XrefError::Start))
			.and_then(|xref_pos| if xref_pos <= buffer.len() {
				match parser::xref_start(&buffer[xref_pos..]) {
					Some(startxref) => Ok(startxref as usize),
					None => Err(Error::Xref(XrefError::Start)),
				}
			} else {
				Err(Error::Xref(XrefError::Start))
			})
	}

	fn search_substring(buffer: &[u8], pattern: &[u8], start_pos: usize) -> Option<usize> {
		let mut seek_pos = start_pos;
		let mut index = 0;

		while seek_pos < buffer.len() && index < pattern.len() {
			if buffer[seek_pos] == pattern[index] {
				index += 1;
			} else if index > 0 {
				seek_pos -= index;
				index = 0;
			}
			seek_pos += 1;

			if index == pattern.len() {
				return Some(seek_pos - index);
			}
		}

		None
	}
}

#[test]
fn load_document() {
	let mut doc = Document::load("assets/example.pdf").unwrap();
	assert_eq!(doc.version, "1.5");
	doc.save("test_2_load.pdf").unwrap();
}
<commit_msg>Use TryInto.<commit_after>use log::{error, warn};
use std::cmp;
use std::convert::TryInto;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Mutex;

use rayon::prelude::*;

use super::parser;
use super::{Document, Object, ObjectId};
use crate::object_stream::ObjectStream;
use crate::xref::XrefEntry;
use crate::{Error, Result};
use crate::error::XrefError;

impl Document {
	/// Load a PDF document from a specified file path.
	#[inline]
	pub fn load<P: AsRef<Path>>(path: P) -> Result<Document> {
		let file = File::open(path)?;
		let buffer = Vec::with_capacity(file.metadata()?.len() as usize);
		Self::load_internal(file, buffer)
	}

	/// Load a PDF document from an arbitrary source.
	#[inline]
	pub fn load_from<R: Read>(source: R) -> Result<Document> {
		let buffer = Vec::<u8>::new();
		Self::load_internal(source, buffer)
	}

	fn load_internal<R: Read>(mut source: R, mut buffer: Vec<u8>) -> Result<Document> {
		source.read_to_end(&mut buffer)?;

		let mut reader = Reader {
			buffer: &buffer,
			document: Document::new(),
		};

		reader.read()?;
		Ok(reader.document)
	}

	/// Load a PDF document from a memory slice.
	pub fn load_mem(buffer: &[u8]) -> Result<Document> {
		buffer.try_into()
	}
}

impl TryInto<Document> for &[u8] {
	type Error = Error;

	fn try_into(self) -> Result<Document> {
		let mut reader = Reader {
			buffer: self,
			document: Document::new(),
		};
		reader.read()?;
		Ok(reader.document)
	}
}

pub struct Reader<'a> {
	buffer: &'a [u8],
	document: Document,
}

impl <'a> Reader<'a> {
	/// Read whole document.
	fn read(&mut self) -> Result<()> {
		// The document structure can be expressed in PEG as:
		//   document <- header indirect_object* xref trailer xref_start
		let version = parser::header(&self.buffer).ok_or(Error::Header)?;

		let xref_start = Self::get_xref_start(&self.buffer)?;
		if xref_start > self.buffer.len() {
			return Err(Error::Xref(XrefError::Start));
		}

		let (mut xref, mut trailer) = parser::xref_and_trailer(&self.buffer[xref_start..], self)?;

		// Read previous Xrefs of linearized or incremental updated document.
		let mut prev_xref_start = trailer.remove(b"Prev");
		while let Some(prev) = prev_xref_start.and_then(|offset| offset.as_i64().ok()) {
			let prev = prev as usize;
			if prev > self.buffer.len() {
				return Err(Error::Xref(XrefError::PrevStart));
			}
			let (prev_xref, mut prev_trailer) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
			xref.extend(prev_xref);

			// Read xref stream in hybrid-reference file
			let prev_xref_stream_start = trailer.remove(b"XRefStm");
			if let Some(prev) = prev_xref_stream_start.and_then(|offset| offset.as_i64().ok()) {
				let prev = prev as usize;
				if prev > self.buffer.len() {
					return Err(Error::Xref(XrefError::StreamStart));
				}
				let (prev_xref, _) = parser::xref_and_trailer(&self.buffer[prev..], &self)?;
				xref.extend(prev_xref);
			}

			prev_xref_start = prev_trailer.remove(b"Prev");
		}

		let xref_entry_count = xref.max_id() + 1;
		if xref.size != xref_entry_count {
			warn!("Size entry of trailer dictionary is {}, correct value is {}.", xref.size, xref_entry_count);
			xref.size = xref_entry_count;
		}

		self.document.version = version;
		self.document.max_id = xref.size - 1;
		self.document.trailer = trailer;
		self.document.reference_table = xref;

		let zero_length_streams = Mutex::new(vec![]);
		let object_streams = Mutex::new(vec![]);

		self.document.objects = self.document.reference_table.entries.par_iter().filter_map(|(_, entry)| {
			if let XrefEntry::Normal { offset, .. } = *entry {
				let (object_id, mut object) = self.read_object(offset as usize)
					.map_err(|e| error!("Object load error: {:?}", e)).ok()?;
				if let Ok(ref mut stream) = object.as_stream_mut() {
					if stream.dict.type_is(b"ObjStm") {
						let obj_stream = ObjectStream::new(stream).ok()?;
						let mut object_streams = object_streams.lock().unwrap();
						object_streams.extend(obj_stream.objects);
					} else if stream.content.is_empty() {
						let mut zero_length_streams = zero_length_streams.lock().unwrap();
						zero_length_streams.push(object_id);
					}
				}
				Some((object_id, object))
			} else {
				None
			}
		}).collect();

		self.document.objects.extend(object_streams.into_inner().unwrap());

		for object_id in zero_length_streams.into_inner().unwrap() {
			let _ = self.set_stream_content(object_id);
		}

		Ok(())
	}

	fn set_stream_content(&mut self, object_id: ObjectId) -> Result<()> {
		let length = self.get_stream_length(object_id)?;
		let stream = self.document.get_object_mut(object_id).and_then(Object::as_stream_mut)?;
		let start = stream.start_position.ok_or(Error::ObjectNotFound)?;

		let end = start + length as usize;
		stream.set_content(self.buffer[start..end].to_vec());
		Ok(())
	}

	fn get_stream_length(&self, object_id: ObjectId) -> Result<i64> {
		let object = self.document.get_object(object_id)?;
		let stream = object.as_stream()?;

		stream.dict.get(b"Length").and_then(|value| {
			if let Ok(id) = value.as_reference() {
				return self.document.get_object(id).and_then(Object::as_i64);
			}
			value.as_i64()
		})
	}

	/// Get object offset by object id.
	fn get_offset(&self, id: ObjectId) -> Result<u32> {
		let entry = self.document.reference_table.get(id.0).ok_or(Error::ObjectNotFound)?;
		match *entry {
			XrefEntry::Normal { offset, generation } => {
				if id.1 == generation {
					Ok(offset)
				} else {
					Err(Error::ObjectNotFound)
				}
			}
			_ => Err(Error::ObjectNotFound),
		}
	}

	pub fn get_object(&self, id: ObjectId) -> Result<Object> {
		let offset = self.get_offset(id)?;
		let (_, obj) = self.read_object(offset as usize)?;

		Ok(obj)
	}

	fn read_object(&self, offset: usize) -> Result<(ObjectId, Object)> {
		if offset > self.buffer.len() {
			return Err(Error::Offset(offset));
		}

		parser::indirect_object(&self.buffer, offset, self)
	}

	fn get_xref_start(buffer: &[u8]) -> Result<usize> {
		let seek_pos = buffer.len() - cmp::min(buffer.len(), 512);
		Self::search_substring(buffer, b"%%EOF", seek_pos)
			.and_then(|eof_pos| Self::search_substring(buffer, b"startxref", eof_pos - 25))
			.ok_or(Error::Xref(XrefError::Start))
			.and_then(|xref_pos| if xref_pos <= buffer.len() {
				match parser::xref_start(&buffer[xref_pos..]) {
					Some(startxref) => Ok(startxref as usize),
					None => Err(Error::Xref(XrefError::Start)),
				}
			} else {
				Err(Error::Xref(XrefError::Start))
			})
	}

	fn search_substring(buffer: &[u8], pattern: &[u8], start_pos: usize) -> Option<usize> {
		let mut seek_pos = start_pos;
		let mut index = 0;

		while seek_pos < buffer.len() && index < pattern.len() {
			if buffer[seek_pos] == pattern[index] {
				index += 1;
			} else if index > 0 {
				seek_pos -= index;
				index = 0;
			}
			seek_pos += 1;

			if index == pattern.len() {
				return Some(seek_pos - index);
			}
		}

		None
	}
}

#[test]
fn load_document() {
	let mut doc = Document::load("assets/example.pdf").unwrap();
	assert_eq!(doc.version, "1.5");
	doc.save("test_2_load.pdf").unwrap();
}
<|endoftext|>