<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use geometry::{DevicePixel, LayerPixel};
use layers::{BufferRequest, ContentAge, LayerBuffer};
use platform::surface::NativeCompositingGraphicsContext;
use texturegl::Texture;

use geom::length::Length;
use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::rect::{Rect, TypedRect};
use geom::size::{Size2D, TypedSize2D};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::iter::range_inclusive;
use std::mem;

pub struct Tile {
    /// The buffer displayed by this tile.
    buffer: Option<Box<LayerBuffer>>,

    /// The content age of any pending buffer request to avoid re-requesting
    /// a buffer while waiting for it to come back from rendering.
    content_age_of_pending_buffer: Option<ContentAge>,

    /// A handle to the GPU texture.
    pub texture: Texture,

    /// The transformation applied to this tiles texture.
    pub transform: Matrix4<f32>,

    /// The tile boundaries in the parent layer coordinates.
    pub bounds: Option<TypedRect<LayerPixel,f32>>,
}

impl Tile {
    fn new() -> Tile {
        Tile {
            buffer: None,
            texture: Texture::zero(),
            transform: identity(),
            content_age_of_pending_buffer: None,
            bounds: None,
        }
    }

    fn should_use_new_buffer(&self, new_buffer: &Box<LayerBuffer>) -> bool {
        match self.buffer {
            Some(ref buffer) => new_buffer.content_age >= buffer.content_age,
            None => true,
        }
    }

    fn replace_buffer(&mut self, buffer: Box<LayerBuffer>) -> Option<Box<LayerBuffer>> {
        if !self.should_use_new_buffer(&buffer) {
            warn!("Layer received an old buffer.");
            return Some(buffer);
        }

        let old_buffer = self.buffer.take();
        self.buffer = Some(buffer);
        self.texture = Texture::zero(); // The old texture is bound to the old buffer.
        self.content_age_of_pending_buffer = None;
        return old_buffer;
    }

    fn create_texture(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        match self.buffer {
            Some(ref buffer) => {
                let size = Size2D(buffer.screen_pos.size.width as isize,
                                  buffer.screen_pos.size.height as isize);

                // If we already have a texture it should still be valid.
                if !self.texture.is_zero() {
                    return;
                }

                // Make a new texture and bind the LayerBuffer's surface to it.
                self.texture = Texture::new_with_buffer(buffer);
                debug!("Tile: binding to native surface {}",
                       buffer.native_surface.get_id() as isize);
                buffer.native_surface.bind_to_texture(graphics_context, &self.texture, size);

                // Set the layer's transform.
                let rect = buffer.rect;
                let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
                self.transform = transform.scale(rect.size.width, rect.size.height, 1.0);
                self.bounds = Some(Rect::from_untyped(&rect));
            },
            None => {},
        }
    }

    fn should_request_buffer(&self, content_age: ContentAge) -> bool {
        // Don't resend a request if our buffer's content age matches the current content age.
        match self.buffer {
            Some(ref buffer) => {
                if buffer.content_age >= content_age {
                    return false;
                }
            }
            None => {}
        }

        // Don't resend a request, if we already have one pending.
        match self.content_age_of_pending_buffer {
            Some(pending_content_age) => pending_content_age != content_age,
            None => true,
        }
    }
}

pub struct TileGrid {
    pub tiles: HashMap<Point2D<usize>, Tile>,

    /// The size of tiles in this grid in device pixels.
    tile_size: Length<DevicePixel, usize>,

    // Buffers that are currently unused.
    unused_buffers: Vec<Box<LayerBuffer>>,
}

pub fn rect_uint_as_rect_f32(rect: Rect<usize>) -> Rect<f32> {
    Rect(Point2D(rect.origin.x as f32, rect.origin.y as f32),
         Size2D(rect.size.width as f32, rect.size.height as f32))
}

impl TileGrid {
    pub fn new(tile_size: usize) -> TileGrid {
        TileGrid {
            tiles: HashMap::new(),
            tile_size: Length::new(tile_size),
            unused_buffers: Vec::new(),
        }
    }

    pub fn get_tile_index_range_for_rect(&self,
                                         rect: TypedRect<DevicePixel, f32>)
                                         -> (Point2D<usize>, Point2D<usize>) {
        let rect = rect.to_untyped();

        // NB: Even in the case of an empty rect, the semantics of Rust floating-point-to-integer
        // casts mean this will corrently round to zero.
        (Point2D((rect.origin.x / self.tile_size.get() as f32) as usize,
                 (rect.origin.y / self.tile_size.get() as f32) as usize),
         Point2D(((rect.origin.x + rect.size.width - 1.0) / self.tile_size.get() as f32) as usize,
                 ((rect.origin.y + rect.size.height - 1.0) / self.tile_size.get() as f32) as usize))
    }

    pub fn get_rect_for_tile_index(&self,
                                   tile_index: Point2D<usize>,
                                   current_layer_size: TypedSize2D<DevicePixel, f32>)
                                   -> TypedRect<DevicePixel, usize> {

        let origin = Point2D(self.tile_size.get() * tile_index.x,
                             self.tile_size.get() * tile_index.y);

        // Don't let tiles extend beyond the layer boundaries.
        let tile_size = self.tile_size.get() as f32;
        let size = Size2D(tile_size.min(current_layer_size.width.get() - origin.x as f32),
                          tile_size.min(current_layer_size.height.get() - origin.y as f32));

        // Round up to texture pixels.
        let size = Size2D(size.width.ceil() as usize, size.height.ceil() as usize);

        Rect::from_untyped(&Rect(origin, size))
    }

    pub fn take_unused_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut unused_buffers = Vec::new();
        mem::swap(&mut unused_buffers, &mut self.unused_buffers);
        return unused_buffers;
    }

    pub fn add_unused_buffer(&mut self, buffer: Option<Box<LayerBuffer>>) {
        match buffer {
            Some(buffer) => self.unused_buffers.push(buffer),
            None => {},
        }
    }

    pub fn mark_tiles_outside_of_rect_as_unused(&mut self,
                                                rect: TypedRect<DevicePixel, f32>,
                                                current_layer_size: TypedSize2D<DevicePixel, f32>) {
        let mut tile_indexes_to_take = Vec::new();
        for tile_index in self.tiles.keys() {
            let tile_rect = self.get_rect_for_tile_index(*tile_index, current_layer_size);
            if !tile_rect.as_f32().intersects(&rect) {
                tile_indexes_to_take.push(tile_index.clone());
            }
        }

        for tile_index in tile_indexes_to_take.iter() {
            match self.tiles.remove(tile_index) {
                Some(ref mut tile) => self.add_unused_buffer(tile.buffer.take()),
                None => {},
            }
        }
    }

    pub fn get_buffer_request_for_tile(&mut self,
                                       tile_index: Point2D<usize>,
                                       current_layer_size: TypedSize2D<DevicePixel, f32>,
                                       current_content_age: ContentAge)
                                       -> Option<BufferRequest> {
        let tile_rect = self.get_rect_for_tile_index(tile_index, current_layer_size);
        let tile = match self.tiles.entry(tile_index) {
            Entry::Occupied(occupied) => occupied.into_mut(),
            Entry::Vacant(vacant) => vacant.insert(Tile::new()),
        };

        if tile_rect.is_empty() {
            return None;
        }

        if !tile.should_request_buffer(current_content_age) {
            return None;
        }

        tile.content_age_of_pending_buffer = Some(current_content_age);

        return Some(BufferRequest::new(tile_rect.to_untyped(),
                                       tile_rect.as_f32().to_untyped(),
                                       current_content_age));
    }

    pub fn get_buffer_requests_in_rect(&mut self,
                                       rect_in_layer: TypedRect<DevicePixel, f32>,
                                       current_layer_size: TypedSize2D<DevicePixel, f32>,
                                       current_content_age: ContentAge)
                                       -> Vec<BufferRequest> {
        let mut buffer_requests = Vec::new();
        let (top_left_index, bottom_right_index) =
            self.get_tile_index_range_for_rect(rect_in_layer);

        for x in range_inclusive(top_left_index.x, bottom_right_index.x) {
            for y in range_inclusive(top_left_index.y, bottom_right_index.y) {
                match self.get_buffer_request_for_tile(Point2D(x, y),
                                                       current_layer_size,
                                                       current_content_age) {
                    Some(buffer) => buffer_requests.push(buffer),
                    None => {},
                }
            }
        }

        self.mark_tiles_outside_of_rect_as_unused(rect_in_layer, current_layer_size);
        return buffer_requests;
    }

    pub fn get_tile_index_for_point(&self, point: Point2D<usize>) -> Point2D<usize> {
        assert!(point.x % self.tile_size.get() == 0);
        assert!(point.y % self.tile_size.get() == 0);
        Point2D((point.x / self.tile_size.get()) as usize,
                (point.y / self.tile_size.get()) as usize)
    }

    pub fn add_buffer(&mut self, buffer: Box<LayerBuffer>) {
        let index = self.get_tile_index_for_point(buffer.screen_pos.origin.clone());
        if !self.tiles.contains_key(&index) {
            warn!("Received buffer for non-existent tile!");
            self.add_unused_buffer(Some(buffer));
            return;
        }

        let replaced_buffer = self.tiles.get_mut(&index).unwrap().replace_buffer(buffer);
        self.add_unused_buffer(replaced_buffer);
    }

    pub fn do_for_all_tiles<F: Fn(&Tile)>(&self, f: F) {
        for tile in self.tiles.values() {
            f(tile);
        }
    }

    pub fn collect_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut collected_buffers = Vec::new();

        collected_buffers.extend(self.take_unused_buffers().into_iter());

        // We need to replace the HashMap since it cannot be used again after move_iter().
        let mut tile_map = HashMap::new();
        mem::swap(&mut tile_map, &mut self.tiles);

        for (_, mut tile) in tile_map.into_iter() {
            match tile.buffer.take() {
                Some(buffer) => collected_buffers.push(buffer),
                None => {},
            }
        }

        return collected_buffers;
    }

    pub fn create_textures(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        for (_, ref mut tile) in self.tiles.iter_mut() {
            tile.create_texture(graphics_context);
        }
    }
}
<commit_msg>Remove `mark_tiles_outside_of_rect_as_unused`.<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use geometry::{DevicePixel, LayerPixel};
use layers::{BufferRequest, ContentAge, LayerBuffer};
use platform::surface::NativeCompositingGraphicsContext;
use texturegl::Texture;

use geom::length::Length;
use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::rect::{Rect, TypedRect};
use geom::size::{Size2D, TypedSize2D};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::iter::range_inclusive;
use std::mem;

pub struct Tile {
    /// The buffer displayed by this tile.
    buffer: Option<Box<LayerBuffer>>,

    /// The content age of any pending buffer request to avoid re-requesting
    /// a buffer while waiting for it to come back from rendering.
    content_age_of_pending_buffer: Option<ContentAge>,

    /// A handle to the GPU texture.
    pub texture: Texture,

    /// The transformation applied to this tiles texture.
    pub transform: Matrix4<f32>,

    /// The tile boundaries in the parent layer coordinates.
    pub bounds: Option<TypedRect<LayerPixel,f32>>,
}

impl Tile {
    fn new() -> Tile {
        Tile {
            buffer: None,
            texture: Texture::zero(),
            transform: identity(),
            content_age_of_pending_buffer: None,
            bounds: None,
        }
    }

    fn should_use_new_buffer(&self, new_buffer: &Box<LayerBuffer>) -> bool {
        match self.buffer {
            Some(ref buffer) => new_buffer.content_age >= buffer.content_age,
            None => true,
        }
    }

    fn replace_buffer(&mut self, buffer: Box<LayerBuffer>) -> Option<Box<LayerBuffer>> {
        if !self.should_use_new_buffer(&buffer) {
            warn!("Layer received an old buffer.");
            return Some(buffer);
        }

        let old_buffer = self.buffer.take();
        self.buffer = Some(buffer);
        self.texture = Texture::zero(); // The old texture is bound to the old buffer.
        self.content_age_of_pending_buffer = None;
        return old_buffer;
    }

    fn create_texture(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        match self.buffer {
            Some(ref buffer) => {
                let size = Size2D(buffer.screen_pos.size.width as isize,
                                  buffer.screen_pos.size.height as isize);

                // If we already have a texture it should still be valid.
                if !self.texture.is_zero() {
                    return;
                }

                // Make a new texture and bind the LayerBuffer's surface to it.
                self.texture = Texture::new_with_buffer(buffer);
                debug!("Tile: binding to native surface {}",
                       buffer.native_surface.get_id() as isize);
                buffer.native_surface.bind_to_texture(graphics_context, &self.texture, size);

                // Set the layer's transform.
                let rect = buffer.rect;
                let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
                self.transform = transform.scale(rect.size.width, rect.size.height, 1.0);
                self.bounds = Some(Rect::from_untyped(&rect));
            },
            None => {},
        }
    }

    fn should_request_buffer(&self, content_age: ContentAge) -> bool {
        // Don't resend a request if our buffer's content age matches the current content age.
        match self.buffer {
            Some(ref buffer) => {
                if buffer.content_age >= content_age {
                    return false;
                }
            }
            None => {}
        }

        // Don't resend a request, if we already have one pending.
        match self.content_age_of_pending_buffer {
            Some(pending_content_age) => pending_content_age != content_age,
            None => true,
        }
    }
}

pub struct TileGrid {
    pub tiles: HashMap<Point2D<usize>, Tile>,

    /// The size of tiles in this grid in device pixels.
    tile_size: Length<DevicePixel, usize>,

    // Buffers that are currently unused.
    unused_buffers: Vec<Box<LayerBuffer>>,
}

pub fn rect_uint_as_rect_f32(rect: Rect<usize>) -> Rect<f32> {
    Rect(Point2D(rect.origin.x as f32, rect.origin.y as f32),
         Size2D(rect.size.width as f32, rect.size.height as f32))
}

impl TileGrid {
    pub fn new(tile_size: usize) -> TileGrid {
        TileGrid {
            tiles: HashMap::new(),
            tile_size: Length::new(tile_size),
            unused_buffers: Vec::new(),
        }
    }

    pub fn get_tile_index_range_for_rect(&self,
                                         rect: TypedRect<DevicePixel, f32>)
                                         -> (Point2D<usize>, Point2D<usize>) {
        let rect = rect.to_untyped();

        // NB: Even in the case of an empty rect, the semantics of Rust floating-point-to-integer
        // casts mean this will corrently round to zero.
        (Point2D((rect.origin.x / self.tile_size.get() as f32) as usize,
                 (rect.origin.y / self.tile_size.get() as f32) as usize),
         Point2D(((rect.origin.x + rect.size.width - 1.0) / self.tile_size.get() as f32) as usize,
                 ((rect.origin.y + rect.size.height - 1.0) / self.tile_size.get() as f32) as usize))
    }

    pub fn get_rect_for_tile_index(&self,
                                   tile_index: Point2D<usize>,
                                   current_layer_size: TypedSize2D<DevicePixel, f32>)
                                   -> TypedRect<DevicePixel, usize> {

        let origin = Point2D(self.tile_size.get() * tile_index.x,
                             self.tile_size.get() * tile_index.y);

        // Don't let tiles extend beyond the layer boundaries.
        let tile_size = self.tile_size.get() as f32;
        let size = Size2D(tile_size.min(current_layer_size.width.get() - origin.x as f32),
                          tile_size.min(current_layer_size.height.get() - origin.y as f32));

        // Round up to texture pixels.
        let size = Size2D(size.width.ceil() as usize, size.height.ceil() as usize);

        Rect::from_untyped(&Rect(origin, size))
    }

    pub fn take_unused_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut unused_buffers = Vec::new();
        mem::swap(&mut unused_buffers, &mut self.unused_buffers);
        return unused_buffers;
    }

    pub fn add_unused_buffer(&mut self, buffer: Option<Box<LayerBuffer>>) {
        match buffer {
            Some(buffer) => self.unused_buffers.push(buffer),
            None => {},
        }
    }

    pub fn get_buffer_request_for_tile(&mut self,
                                       tile_index: Point2D<usize>,
                                       current_layer_size: TypedSize2D<DevicePixel, f32>,
                                       current_content_age: ContentAge)
                                       -> Option<BufferRequest> {
        let tile_rect = self.get_rect_for_tile_index(tile_index, current_layer_size);
        let tile = match self.tiles.entry(tile_index) {
            Entry::Occupied(occupied) => occupied.into_mut(),
            Entry::Vacant(vacant) => vacant.insert(Tile::new()),
        };

        if tile_rect.is_empty() {
            return None;
        }

        if !tile.should_request_buffer(current_content_age) {
            return None;
        }

        tile.content_age_of_pending_buffer = Some(current_content_age);

        return Some(BufferRequest::new(tile_rect.to_untyped(),
                                       tile_rect.as_f32().to_untyped(),
                                       current_content_age));
    }

    pub fn get_buffer_requests_in_rect(&mut self,
                                       rect_in_layer: TypedRect<DevicePixel, f32>,
                                       current_layer_size: TypedSize2D<DevicePixel, f32>,
                                       current_content_age: ContentAge)
                                       -> Vec<BufferRequest> {
        let mut buffer_requests = Vec::new();
        let (top_left_index, bottom_right_index) =
            self.get_tile_index_range_for_rect(rect_in_layer);

        for x in range_inclusive(top_left_index.x, bottom_right_index.x) {
            for y in range_inclusive(top_left_index.y, bottom_right_index.y) {
                match self.get_buffer_request_for_tile(Point2D(x, y),
                                                       current_layer_size,
                                                       current_content_age) {
                    Some(buffer) => buffer_requests.push(buffer),
                    None => {},
                }
            }
        }

        return buffer_requests;
    }

    pub fn get_tile_index_for_point(&self, point: Point2D<usize>) -> Point2D<usize> {
        assert!(point.x % self.tile_size.get() == 0);
        assert!(point.y % self.tile_size.get() == 0);
        Point2D((point.x / self.tile_size.get()) as usize,
                (point.y / self.tile_size.get()) as usize)
    }

    pub fn add_buffer(&mut self, buffer: Box<LayerBuffer>) {
        let index = self.get_tile_index_for_point(buffer.screen_pos.origin.clone());
        if !self.tiles.contains_key(&index) {
            warn!("Received buffer for non-existent tile!");
            self.add_unused_buffer(Some(buffer));
            return;
        }

        let replaced_buffer = self.tiles.get_mut(&index).unwrap().replace_buffer(buffer);
        self.add_unused_buffer(replaced_buffer);
    }

    pub fn do_for_all_tiles<F: Fn(&Tile)>(&self, f: F) {
        for tile in self.tiles.values() {
            f(tile);
        }
    }

    pub fn collect_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut collected_buffers = Vec::new();

        collected_buffers.extend(self.take_unused_buffers().into_iter());

        // We need to replace the HashMap since it cannot be used again after move_iter().
        let mut tile_map = HashMap::new();
        mem::swap(&mut tile_map, &mut self.tiles);

        for (_, mut tile) in tile_map.into_iter() {
            match tile.buffer.take() {
                Some(buffer) => collected_buffers.push(buffer),
                None => {},
            }
        }

        return collected_buffers;
    }

    pub fn create_textures(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        for (_, ref mut tile) in self.tiles.iter_mut() {
            tile.create_texture(graphics_context);
        }
    }
}
<|endoftext|>


<commit_before>//! Randomization of big integers

use rand::distributions::uniform::{SampleUniform, UniformSampler};
use rand::prelude::*;

use BigInt;
use BigUint;
use Sign::*;

use bigint::{into_magnitude, magnitude};

use integer::Integer;
use traits::Zero;

pub trait RandBigInt {
    /// Generate a random `BigUint` of the given bit size.
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint;

    /// Generate a random BigInt of the given bit size.
    fn gen_bigint(&mut self, bit_size: usize) -> BigInt;

    /// Generate a random `BigUint` less than the given bound. Fails
    /// when the bound is zero.
    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;

    /// Generate a random `BigUint` within the given range. The lower
    /// bound is inclusive; the upper bound is exclusive. Fails when
    /// the upper bound is not greater than the lower bound.
    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;

    /// Generate a random `BigInt` within the given range. The lower
    /// bound is inclusive; the upper bound is exclusive. Fails when
    /// the upper bound is not greater than the lower bound.
    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
}

fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: usize) {
    // `fill` is faster than many `gen::<u32>` calls
    rng.fill(data);
    if rem > 0 {
        let last = data.len() - 1;
        data[last] >>= 32 - rem;
    }
}

impl<R: Rng + ?Sized> RandBigInt for R {
    #[cfg(not(u64_digit))]
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
        let (digits, rem) = bit_size.div_rem(&32);
        let mut data = vec![0u32; digits + (rem > 0) as usize];
        gen_bits(self, &mut data, rem);
        BigUint::new_native(data)
    }

    #[cfg(u64_digit)]
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
        let (digits, rem) = bit_size.div_rem(&32);
        let native_digits = bit_size.div_ceil(&64);
        let mut data = vec![0u64; native_digits];
        unsafe {
            // Generate bits in a `&mut [u32]` slice for value stability
            let ptr = data.as_mut_ptr() as *mut u32;
            let len = digits + (rem > 0) as usize;
            debug_assert!(native_digits * 2 >= len);
            let data = std::slice::from_raw_parts_mut(ptr, len);
            gen_bits(self, data, rem);
        }
        #[cfg(target_endian = "big")]
        for digit in &mut data {
            // swap u32 digits into u64 endianness
            *digit = (*digit << 32) | (*digit >> 32);
        }
        BigUint::new_native(data)
    }

    fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
        loop {
            // Generate a random BigUint...
            let biguint = self.gen_biguint(bit_size);
            // ...and then randomly assign it a Sign...
            let sign = if biguint.is_zero() {
                // ...except that if the BigUint is zero, we need to try
                // again with probability 0.5. This is because otherwise,
                // the probability of generating a zero BigInt would be
                // double that of any other number.
                if self.gen() {
                    continue;
                } else {
                    NoSign
                }
            } else if self.gen() {
                Plus
            } else {
                Minus
            };
            return BigInt::from_biguint(sign, biguint);
        }
    }

    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
        assert!(!bound.is_zero());
        let bits = bound.bits();
        loop {
            let n = self.gen_biguint(bits);
            if n < *bound {
                return n;
            }
        }
    }

    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
        assert!(*lbound < *ubound);
        if lbound.is_zero() {
            self.gen_biguint_below(ubound)
        } else {
            lbound + self.gen_biguint_below(&(ubound - lbound))
        }
    }

    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
        assert!(*lbound < *ubound);
        if lbound.is_zero() {
            BigInt::from(self.gen_biguint_below(magnitude(&ubound)))
        } else if ubound.is_zero() {
            lbound + BigInt::from(self.gen_biguint_below(magnitude(&lbound)))
        } else {
            let delta = ubound - lbound;
            lbound + BigInt::from(self.gen_biguint_below(magnitude(&delta)))
        }
    }
}

/// The back-end implementing rand's `UniformSampler` for `BigUint`.
#[derive(Clone, Debug)]
pub struct UniformBigUint {
    base: BigUint,
    len: BigUint,
}

impl UniformSampler for UniformBigUint {
    type X = BigUint;

    #[inline]
    fn new(low: Self::X, high: Self::X) -> Self {
        assert!(low < high);
        UniformBigUint {
            len: high - &low,
            base: low,
        }
    }

    #[inline]
    fn new_inclusive(low: Self::X, high: Self::X) -> Self {
        assert!(low <= high);
        Self::new(low, high + 1u32)
    }

    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
        &self.base + rng.gen_biguint_below(&self.len)
    }

    #[inline]
    fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
        rng.gen_biguint_range(&low, &high)
    }
}

impl SampleUniform for BigUint {
    type Sampler = UniformBigUint;
}

/// The back-end implementing rand's `UniformSampler` for `BigInt`.
#[derive(Clone, Debug)]
pub struct UniformBigInt {
    base: BigInt,
    len: BigUint,
}

impl UniformSampler for UniformBigInt {
    type X = BigInt;

    #[inline]
    fn new(low: Self::X, high: Self::X) -> Self {
        assert!(low < high);
        UniformBigInt {
            len: into_magnitude(high - &low),
            base: low,
        }
    }

    #[inline]
    fn new_inclusive(low: Self::X, high: Self::X) -> Self {
        assert!(low <= high);
        Self::new(low, high + 1u32)
    }

    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
        &self.base + BigInt::from(rng.gen_biguint_below(&self.len))
    }

    #[inline]
    fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
        rng.gen_bigint_range(&low, &high)
    }
}

impl SampleUniform for BigInt {
    type Sampler = UniformBigInt;
}

/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
#[derive(Clone, Copy, Debug)]
pub struct RandomBits {
    bits: usize,
}

impl RandomBits {
    #[inline]
    pub fn new(bits: usize) -> RandomBits {
        RandomBits { bits }
    }
}

impl Distribution<BigUint> for RandomBits {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigUint {
        rng.gen_biguint(self.bits)
    }
}

impl Distribution<BigInt> for RandomBits {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigInt {
        rng.gen_bigint(self.bits)
    }
}
<commit_msg>Fix the assumption of extern crate prelude<commit_after>//! Randomization of big integers

use rand::distributions::uniform::{SampleUniform, UniformSampler};
use rand::prelude::*;

use BigInt;
use BigUint;
use Sign::*;

use bigint::{into_magnitude, magnitude};

use integer::Integer;
use traits::Zero;

pub trait RandBigInt {
    /// Generate a random `BigUint` of the given bit size.
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint;

    /// Generate a random BigInt of the given bit size.
    fn gen_bigint(&mut self, bit_size: usize) -> BigInt;

    /// Generate a random `BigUint` less than the given bound. Fails
    /// when the bound is zero.
    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;

    /// Generate a random `BigUint` within the given range. The lower
    /// bound is inclusive; the upper bound is exclusive. Fails when
    /// the upper bound is not greater than the lower bound.
    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;

    /// Generate a random `BigInt` within the given range. The lower
    /// bound is inclusive; the upper bound is exclusive. Fails when
    /// the upper bound is not greater than the lower bound.
    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
}

fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: usize) {
    // `fill` is faster than many `gen::<u32>` calls
    rng.fill(data);
    if rem > 0 {
        let last = data.len() - 1;
        data[last] >>= 32 - rem;
    }
}

impl<R: Rng + ?Sized> RandBigInt for R {
    #[cfg(not(u64_digit))]
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
        let (digits, rem) = bit_size.div_rem(&32);
        let mut data = vec![0u32; digits + (rem > 0) as usize];
        gen_bits(self, &mut data, rem);
        BigUint::new_native(data)
    }

    #[cfg(u64_digit)]
    fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
        use std::slice;

        let (digits, rem) = bit_size.div_rem(&32);
        let native_digits = bit_size.div_ceil(&64);
        let mut data = vec![0u64; native_digits];
        unsafe {
            // Generate bits in a `&mut [u32]` slice for value stability
            let ptr = data.as_mut_ptr() as *mut u32;
            let len = digits + (rem > 0) as usize;
            debug_assert!(native_digits * 2 >= len);
            let data = slice::from_raw_parts_mut(ptr, len);
            gen_bits(self, data, rem);
        }
        #[cfg(target_endian = "big")]
        for digit in &mut data {
            // swap u32 digits into u64 endianness
            *digit = (*digit << 32) | (*digit >> 32);
        }
        BigUint::new_native(data)
    }

    fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
        loop {
            // Generate a random BigUint...
            let biguint = self.gen_biguint(bit_size);
            // ...and then randomly assign it a Sign...
            let sign = if biguint.is_zero() {
                // ...except that if the BigUint is zero, we need to try
                // again with probability 0.5. This is because otherwise,
                // the probability of generating a zero BigInt would be
                // double that of any other number.
                if self.gen() {
                    continue;
                } else {
                    NoSign
                }
            } else if self.gen() {
                Plus
            } else {
                Minus
            };
            return BigInt::from_biguint(sign, biguint);
        }
    }

    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
        assert!(!bound.is_zero());
        let bits = bound.bits();
        loop {
            let n = self.gen_biguint(bits);
            if n < *bound {
                return n;
            }
        }
    }

    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
        assert!(*lbound < *ubound);
        if lbound.is_zero() {
            self.gen_biguint_below(ubound)
        } else {
            lbound + self.gen_biguint_below(&(ubound - lbound))
        }
    }

    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
        assert!(*lbound < *ubound);
        if lbound.is_zero() {
            BigInt::from(self.gen_biguint_below(magnitude(&ubound)))
        } else if ubound.is_zero() {
            lbound + BigInt::from(self.gen_biguint_below(magnitude(&lbound)))
        } else {
            let delta = ubound - lbound;
            lbound + BigInt::from(self.gen_biguint_below(magnitude(&delta)))
        }
    }
}

/// The back-end implementing rand's `UniformSampler` for `BigUint`.
#[derive(Clone, Debug)]
pub struct UniformBigUint {
    base: BigUint,
    len: BigUint,
}

impl UniformSampler for UniformBigUint {
    type X = BigUint;

    #[inline]
    fn new(low: Self::X, high: Self::X) -> Self {
        assert!(low < high);
        UniformBigUint {
            len: high - &low,
            base: low,
        }
    }

    #[inline]
    fn new_inclusive(low: Self::X, high: Self::X) -> Self {
        assert!(low <= high);
        Self::new(low, high + 1u32)
    }

    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
        &self.base + rng.gen_biguint_below(&self.len)
    }

    #[inline]
    fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
        rng.gen_biguint_range(&low, &high)
    }
}

impl SampleUniform for BigUint {
    type Sampler = UniformBigUint;
}

/// The back-end implementing rand's `UniformSampler` for `BigInt`.
#[derive(Clone, Debug)]
pub struct UniformBigInt {
    base: BigInt,
    len: BigUint,
}

impl UniformSampler for UniformBigInt {
    type X = BigInt;

    #[inline]
    fn new(low: Self::X, high: Self::X) -> Self {
        assert!(low < high);
        UniformBigInt {
            len: into_magnitude(high - &low),
            base: low,
        }
    }

    #[inline]
    fn new_inclusive(low: Self::X, high: Self::X) -> Self {
        assert!(low <= high);
        Self::new(low, high + 1u32)
    }

    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
        &self.base + BigInt::from(rng.gen_biguint_below(&self.len))
    }

    #[inline]
    fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
        rng.gen_bigint_range(&low, &high)
    }
}

impl SampleUniform for BigInt {
    type Sampler = UniformBigInt;
}

/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
#[derive(Clone, Copy, Debug)]
pub struct RandomBits {
    bits: usize,
}

impl RandomBits {
    #[inline]
    pub fn new(bits: usize) -> RandomBits {
        RandomBits { bits }
    }
}

impl Distribution<BigUint> for RandomBits {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigUint {
        rng.gen_biguint(self.bits)
    }
}

impl Distribution<BigInt> for RandomBits {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigInt {
        rng.gen_bigint(self.bits)
    }
}
<|endoftext|>


<commit_before>use clap::{Arg, ArgMatches, App, SubCommand, AppSettings};

pub fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .global_settings(&[AppSettings::ColoredHelp])
        .arg(Arg::with_name("infile")
                 .required(false)
                 .global(true)
                 .index(1)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .required(false)
                 .global(true)
                 .index(2)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("plain_hexdump")
                                 .short("p")
                                 .long("plain-hexdump")
                                 .required(false)
                                 .help("output in postscript plain hexdump style."))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("Hex")
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)")))
}
<commit_msg>Remove positional infile/outfile arguments<commit_after>use clap::{Arg, ArgMatches, App, SubCommand, AppSettings};

pub fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .global_settings(&[AppSettings::ColoredHelp])
        .arg(Arg::with_name("infile")
                 .short("i")
                 .long("input-file")
                 .required(false)
                 .global(true)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .short("o")
                 .long("output-file")
                 .required(false)
                 .global(true)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("plain_hexdump")
                                 .short("p")
                                 .long("plain-hexdump")
                                 .required(false)
                                 .help("output in postscript plain hexdump style."))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("Hex")
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)")))
}
<|endoftext|>


<commit_before>
extern crate webdriver;
use webdriver::*;
use webdriver::messages::LocationStrategy;
use webdriver::firefox::GeckoDriver;

extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;

fn execute_function<T>(name: &str, args: &str, sess: &DriverSession<T>) -> Result<(), Error> {
    match name {
        "back" => try!(sess.back()),
        "go" => try!(sess.go(args)),
        "refresh" => try!(sess.refresh()),
        "source" => println!("{}", try!(sess.get_page_source())),
        "url" => println!("{}", try!(sess.get_current_url())),
        "innerhtml" => {
            for (idx, elem) in sess.find_elements(args, LocationStrategy::Css)?.iter().enumerate() {
                println!("#{} {}", idx, elem.inner_html()?);
            }
        }
        "outerhtml" => {
            for (idx, elem) in sess.find_elements(args, LocationStrategy::Css)?.iter().enumerate() {
                println!("#{} {}", idx, elem.outer_html()?);
            }
        }
        "windows" => {
            for (idx, handle) in sess.get_window_handles()?.iter().enumerate() {
                println!("#{} {}", idx, handle)
            }
        }
        _ => println!("Unknown function: \"{}\"", name),
    }
    Ok(())
}

fn execute<T>(line: &str, sess: &DriverSession<T>) -> Result<(), Error>{
    let (cmd, args) = line.find(' ')
        .map_or((line, "".as_ref()), |idx| line.split_at(idx));
    execute_function(cmd, args, sess)
}

fn main() {
    let gecko = GeckoDriver::new()
        .expect("Unable to start geckodriver");
    let sess = DriverSession::new(gecko)
        .expect("Unable to start WebDriver session");

    let mut rl = Editor::<()>::new();
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                if let Err(err) = execute(line.trim_matches('\n'), &sess) {
                    println!("{}", err);
                }
            },
            Err(ReadlineError::Interrupted) => {
                break
            },
            Err(ReadlineError::Eof) => {
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }

}
<commit_msg>Add execute command to shell.<commit_after>
extern crate webdriver;
use webdriver::*;
use webdriver::messages::{ ExecuteCmd, LocationStrategy };
use webdriver::firefox::GeckoDriver;

extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;

fn execute_function<T>(name: &str, args: &str, sess: &DriverSession<T>) -> Result<(), Error> {
    match name {
        "back" => try!(sess.back()),
        "go" => try!(sess.go(args)),
        "execute" => {
            let out = (sess.execute(ExecuteCmd { script: From::from(args), args: vec![] }))?;
            println!("{}", out);
        },
        "refresh" => try!(sess.refresh()),
        "source" => println!("{}", try!(sess.get_page_source())),
        "url" => println!("{}", try!(sess.get_current_url())),
        "innerhtml" => {
            for (idx, elem) in sess.find_elements(args, LocationStrategy::Css)?.iter().enumerate() {
                println!("#{} {}", idx, elem.inner_html()?);
            }
        }
        "outerhtml" => {
            for (idx, elem) in sess.find_elements(args, LocationStrategy::Css)?.iter().enumerate() {
                println!("#{} {}", idx, elem.outer_html()?);
            }
        }
        "windows" => {
            for (idx, handle) in sess.get_window_handles()?.iter().enumerate() {
                println!("#{} {}", idx, handle)
            }
        }
        _ => println!("Unknown function: \"{}\"", name),
    }
    Ok(())
}

fn execute<T>(line: &str, sess: &DriverSession<T>) -> Result<(), Error>{
    let (cmd, args) = line.find(' ')
        .map_or((line, "".as_ref()), |idx| line.split_at(idx));
    execute_function(cmd, args, sess)
}

fn main() {
    let gecko = GeckoDriver::new()
        .expect("Unable to start geckodriver");
    let sess = DriverSession::new(gecko)
        .expect("Unable to start WebDriver session");

    let mut rl = Editor::<()>::new();
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                if let Err(err) = execute(line.trim_matches('\n'), &sess) {
                    println!("{}", err);
                }
            },
            Err(ReadlineError::Interrupted) => {
                break
            },
            Err(ReadlineError::Eof) => {
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }

}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::cmp;
use std::time::Duration;
use r2d2::Pool;
use r2d2::config::Config;
use r2d2_redis::{RedisConnectionManager, Error};
use redis::{self, Value, Connection, Commands};

use APP_CONF;

pub struct CacheStoreBuilder;

pub struct CacheStore {
    pool: Pool<RedisConnectionManager>,
}

#[derive(Debug)]
pub enum CacheStoreError {
    Disconnected,
    Failed,
    Invalid,
    Corrupted,
    TooLarge,
}

#[derive(Debug)]
pub enum CachePurgeVariant {
    Bucket,
    Auth,
}

type CacheResult = Result<Option<String>, CacheStoreError>;

impl CacheStoreBuilder {
    pub fn new() -> CacheStore {
        info!("binding to store backend at {}", APP_CONF.redis.inet);

        let tcp_addr_raw =
            format!(
            "redis://{}:{}/{}",
            APP_CONF.redis.inet.ip(),
            APP_CONF.redis.inet.port(),
            APP_CONF.redis.database,
        );

        match RedisConnectionManager::new(tcp_addr_raw.as_ref()) {
            Ok(manager) => {
                let config = Config::<Connection, Error>::builder()
                    .test_on_check_out(false)
                    .pool_size(APP_CONF.redis.pool_size)
                    .idle_timeout(Some(
                        Duration::from_secs(APP_CONF.redis.idle_timeout_seconds),
                    ))
                    .connection_timeout(Duration::from_secs(
                        APP_CONF.redis.connection_timeout_seconds,
                    ))
                    .build();

                match Pool::new(config, manager) {
                    Ok(pool) => {
                        info!("bound to store backend");

                        CacheStore { pool: pool }
                    }
                    Err(_) => panic!("could not spawn redis pool"),
                }
            }
            Err(_) => panic!("could not create redis connection manager"),
        }
    }
}

impl CacheStore {
    pub fn get(&self, key: &str) -> CacheResult {
        get_cache_store_client!(self, client {
            match (*client).get::<_, Value>(key) {
                Ok(value) => {
                    match value {
                        Value::Data(bytes) => {
                            // Decode raw bytes to string
                            if let Ok(string) = String::from_utf8(bytes) {
                                Ok(Some(string))
                            } else {
                                Err(CacheStoreError::Corrupted)
                            }
                        },
                        Value::Nil => Ok(None),
                        _ => Err(CacheStoreError::Invalid),
                    }
                },
                _ => Err(CacheStoreError::Failed),
            }
        })
    }

    pub fn set(
        &self,
        key: &str,
        value: &str,
        ttl: usize,
        key_bucket: Option<String>,
    ) -> CacheResult {
        get_cache_store_client!(self, client {
            // Cap TTL to 'max_key_expiration'
            let ttl_cap = cmp::min(ttl, APP_CONF.redis.max_key_expiration);

            // Ensure value is not larger than 'max_key_size'
            if value.len() > APP_CONF.redis.max_key_size {
                Err(CacheStoreError::TooLarge)
            } else {
                match key_bucket {
                    Some(key_bucket_value) => {
                        // Bucket (MULTI operation for main data + bucket marker)
                        gen_cache_store_empty_result!(
                            redis::pipe()
                                .atomic()
                                .cmd("SETEX").arg(key).arg(ttl_cap).arg(value).ignore()
                                .cmd("SETEX").arg(key_bucket_value).arg(ttl_cap).arg("").ignore()
                                .query::<()>(&*client)
                        )
                    },
                    None => {
                        gen_cache_store_empty_result!(
                            (*client).set_ex::<_, _, ()>(key, value, ttl_cap)
                        )
                    },
                }
            }
        })
    }

    pub fn purge_pattern(&self, variant: &CachePurgeVariant, key_pattern: &str) -> CacheResult {
        get_cache_store_client!(self, client {
            // Invoke keyspace cleanup script for key pattern
            gen_cache_store_empty_result!(
                redis::Script::new(variant.get_script())
                    .arg(key_pattern)
                    .invoke::<()>(&*client)
            )
        })
    }
}

impl CachePurgeVariant {
    fn get_script(&self) -> &'static str {
        match *self {
            CachePurgeVariant::Bucket => {
                r#"
                    local re = '^(.+):b:.+$'
                    local targets = {}

                    for _, bucket_key in pairs(redis.call('KEYS', ARGV[1])) do
                        local base_key = bucket_key:match(re)

                        if base_key then
                            table.insert(targets, base_key)
                        end

                        table.insert(targets, bucket_key)
                    end

                    if next(targets) then
                        redis.call('DEL', unpack(targets))
                    end
                "#
            }
            CachePurgeVariant::Auth => {
                r#"
                    local targets = redis.call('KEYS', ARGV[1])

                    if next(targets) then
                        redis.call('DEL', unpack(targets))
                    end
                "#
            }
        }
    }
}
<commit_msg>Enforcing r2d2 PING is less efficient but safer if Redis goes down and back up<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::cmp;
use std::time::Duration;
use r2d2::Pool;
use r2d2::config::Config;
use r2d2_redis::{RedisConnectionManager, Error};
use redis::{self, Value, Connection, Commands};

use APP_CONF;

pub struct CacheStoreBuilder;

pub struct CacheStore {
    pool: Pool<RedisConnectionManager>,
}

#[derive(Debug)]
pub enum CacheStoreError {
    Disconnected,
    Failed,
    Invalid,
    Corrupted,
    TooLarge,
}

#[derive(Debug)]
pub enum CachePurgeVariant {
    Bucket,
    Auth,
}

type CacheResult = Result<Option<String>, CacheStoreError>;

impl CacheStoreBuilder {
    pub fn new() -> CacheStore {
        info!("binding to store backend at {}", APP_CONF.redis.inet);

        let tcp_addr_raw =
            format!(
            "redis://{}:{}/{}",
            APP_CONF.redis.inet.ip(),
            APP_CONF.redis.inet.port(),
            APP_CONF.redis.database,
        );

        match RedisConnectionManager::new(tcp_addr_raw.as_ref()) {
            Ok(manager) => {
                let config = Config::<Connection, Error>::builder()
                    .pool_size(APP_CONF.redis.pool_size)
                    .idle_timeout(Some(
                        Duration::from_secs(APP_CONF.redis.idle_timeout_seconds),
                    ))
                    .connection_timeout(Duration::from_secs(
                        APP_CONF.redis.connection_timeout_seconds,
                    ))
                    .build();

                match Pool::new(config, manager) {
                    Ok(pool) => {
                        info!("bound to store backend");

                        CacheStore { pool: pool }
                    }
                    Err(_) => panic!("could not spawn redis pool"),
                }
            }
            Err(_) => panic!("could not create redis connection manager"),
        }
    }
}

impl CacheStore {
    pub fn get(&self, key: &str) -> CacheResult {
        get_cache_store_client!(self, client {
            match (*client).get::<_, Value>(key) {
                Ok(value) => {
                    match value {
                        Value::Data(bytes) => {
                            // Decode raw bytes to string
                            if let Ok(string) = String::from_utf8(bytes) {
                                Ok(Some(string))
                            } else {
                                Err(CacheStoreError::Corrupted)
                            }
                        },
                        Value::Nil => Ok(None),
                        _ => Err(CacheStoreError::Invalid),
                    }
                },
                _ => Err(CacheStoreError::Failed),
            }
        })
    }

    pub fn set(
        &self,
        key: &str,
        value: &str,
        ttl: usize,
        key_bucket: Option<String>,
    ) -> CacheResult {
        get_cache_store_client!(self, client {
            // Cap TTL to 'max_key_expiration'
            let ttl_cap = cmp::min(ttl, APP_CONF.redis.max_key_expiration);

            // Ensure value is not larger than 'max_key_size'
            if value.len() > APP_CONF.redis.max_key_size {
                Err(CacheStoreError::TooLarge)
            } else {
                match key_bucket {
                    Some(key_bucket_value) => {
                        // Bucket (MULTI operation for main data + bucket marker)
                        gen_cache_store_empty_result!(
                            redis::pipe()
                                .atomic()
                                .cmd("SETEX").arg(key).arg(ttl_cap).arg(value).ignore()
                                .cmd("SETEX").arg(key_bucket_value).arg(ttl_cap).arg("").ignore()
                                .query::<()>(&*client)
                        )
                    },
                    None => {
                        gen_cache_store_empty_result!(
                            (*client).set_ex::<_, _, ()>(key, value, ttl_cap)
                        )
                    },
                }
            }
        })
    }

    pub fn purge_pattern(&self, variant: &CachePurgeVariant, key_pattern: &str) -> CacheResult {
        get_cache_store_client!(self, client {
            // Invoke keyspace cleanup script for key pattern
            gen_cache_store_empty_result!(
                redis::Script::new(variant.get_script())
                    .arg(key_pattern)
                    .invoke::<()>(&*client)
            )
        })
    }
}

impl CachePurgeVariant {
    fn get_script(&self) -> &'static str {
        match *self {
            CachePurgeVariant::Bucket => {
                r#"
                    local re = '^(.+):b:.+$'
                    local targets = {}

                    for _, bucket_key in pairs(redis.call('KEYS', ARGV[1])) do
                        local base_key = bucket_key:match(re)

                        if base_key then
                            table.insert(targets, base_key)
                        end

                        table.insert(targets, bucket_key)
                    end

                    if next(targets) then
                        redis.call('DEL', unpack(targets))
                    end
                "#
            }
            CachePurgeVariant::Auth => {
                r#"
                    local targets = redis.call('KEYS', ARGV[1])

                    if next(targets) then
                        redis.call('DEL', unpack(targets))
                    end
                "#
            }
        }
    }
}
<|endoftext|>


<commit_before>use common::*;
use core::ops::Drop;

use super::{MemoryBlockCapability};

/// Untyped memory and page table are memory management tricks, those are not
/// actually accessible in the virtual memory.

pub struct UntypedMemoryCapability {
    block_start_addr: PhysicalAddress,
    block_size: usize,
    parent_pool_cap_ptr: *mut CapabilityUnion,
    next_block_ptr: Option<*mut CapabilityUnion>,
    prev_block_ptr: Option<*mut CapabilityUnion>,
    referred: bool,
}

impl MemoryBlockCapability for UntypedMemoryCapability {
    fn block_start_addr(&self) -> PhysicalAddress { self.block_start_addr }
    unsafe fn set_block_start_addr(&self, addr: PhysicalAddress) { self.block_start_addr = addr }

    fn block_size(&self) -> usize { self.physical_size }
    unsafe fn set_block_size(&self, size: usize) { self.block_size = size }

    unsafe fn next_block_ptr(&self) -> Option<*mut CapabilityUnion> { self.next_block_ptr }
    unsafe fn set_next_block_ptr(&self, ptr: Option<*mut CapabilityUnion>) { self.next_block_ptr = ptr }

    unsafe fn prev_block_ptr(&self) -> Option<*mut CapabilityUnion> { self.prev_block_ptr }
    unsafe fn set_prev_block_ptr(&self, ptr: Option<*mut CapabilityUnion>) { self.prev_block_ptr = ptr }
}

impl Capability for UntypedMemoryCapability {
    fn referred(&self) -> bool { self.referred }
    unsafe fn set_referred(&self, x: bool) { self.referred = x }

    unsafe fn parent_pool_cap_ptr(&self) -> *mut CapabilityUnion { self.parent_pool_cap_ptr }
    unsafe fn set_parent_pool_cap_ptr(&self, ptr: *mut CapabilityUnion) { self.parent_pool_cap_ptr = ptr }
}

impl UntypedMemoryCapability {
    pub fn from_untyped(cap: UntypedMemoryCapability, size: usize)
                        -> (UntypedMemoryCapability, Option<UntypedMemoryCapability>) {
        if cap.start_addr() + size + 1 >= cap.end_addr() {
            (cap, None)
        } else {
            let new_cap = UntypedMemoryCapability {
                start_addr: cap.start_addr(),
                size: size,
            };

            let cap = UntypedMemoryCapability::resize(cap, &new_cap);
            (new_cap, cap)
        }
    }

    pub fn resize<T: MemoryBlockCapability>(mut untyped: UntypedMemoryCapability, other: &T)
                                            -> Option<UntypedMemoryCapability> {
        assert!(untyped.physical_start_addr() == other.physical_start_addr(),
                "To resize, two capability's starting physical address must be the same.");
        assert!(untyped.physical_end_addr() >= other.physical_end_addr(),
                "To resize, the other capability must be within the untyped.");

        untyped.start_addr = other.physical_end_addr() + 1;
        untyped.size = untyped.size - other.physical_size();

        if untyped.size == 0 {
            None
        } else {
            Some(untyped)
        }
    }
}
<commit_msg>Add retype<commit_after>use common::*;
use core::ops::Drop;

use super::{MemoryBlockCapability};

/// Untyped memory and page table are memory management tricks, those are not
/// actually accessible in the virtual memory.

pub struct UntypedMemoryCapability {
    block_start_addr: PhysicalAddress,
    block_size: usize,
    parent_pool_cap_ptr: *mut CapabilityUnion,
    next_block_ptr: Option<*mut CapabilityUnion>,
    prev_block_ptr: Option<*mut CapabilityUnion>,
    first_child_block_ptr: Option<*mut CapabilityUnion>
    referred: bool,
}

impl MemoryBlockCapability for UntypedMemoryCapability {
    fn block_start_addr(&self) -> PhysicalAddress { self.block_start_addr }
    unsafe fn set_block_start_addr(&self, addr: PhysicalAddress) { self.block_start_addr = addr }

    fn block_size(&self) -> usize { self.physical_size }
    unsafe fn set_block_size(&self, size: usize) { self.block_size = size }

    unsafe fn next_block_ptr(&self) -> Option<*mut CapabilityUnion> { self.next_block_ptr }
    unsafe fn set_next_block_ptr(&self, ptr: Option<*mut CapabilityUnion>) { self.next_block_ptr = ptr }

    unsafe fn prev_block_ptr(&self) -> Option<*mut CapabilityUnion> { self.prev_block_ptr }
    unsafe fn set_prev_block_ptr(&self, ptr: Option<*mut CapabilityUnion>) { self.prev_block_ptr = ptr }
}

impl Capability for UntypedMemoryCapability {
    fn referred(&self) -> bool { self.referred }
    unsafe fn set_referred(&self, x: bool) { self.referred = x }

    unsafe fn parent_pool_cap_ptr(&self) -> *mut CapabilityUnion { self.parent_pool_cap_ptr }
    unsafe fn set_parent_pool_cap_ptr(&self, ptr: *mut CapabilityUnion) { self.parent_pool_cap_ptr = ptr }
}

impl UntypedMemoryCapability {
    pub unsafe fn retype_to_untyped(&mut self, block_size: usize)
                                    -> Option<UntypedMemoryCapability> {
        if (self.block_start_addr() + block_size >= self.block_end_addr()) {
            None
        } else {

        }
    }

    pub fn find_free_start_addr(&mut self, block_size: usize) -> Option<usize> {
        if self.
    }

    pub fn first_child_block(&mut self) -> Option<Referrer<CapabilityUnion>> {

    }

    pub fn from_untyped(cap: UntypedMemoryCapability, size: usize)
                        -> (UntypedMemoryCapability, Option<UntypedMemoryCapability>) {
        if cap.start_addr() + size + 1 >= cap.end_addr() {
            (cap, None)
        } else {
            let new_cap = UntypedMemoryCapability {
                start_addr: cap.start_addr(),
                size: size,
            };

            let cap = UntypedMemoryCapability::resize(cap, &new_cap);
            (new_cap, cap)
        }
    }

    pub fn resize<T: MemoryBlockCapability>(mut untyped: UntypedMemoryCapability, other: &T)
                                            -> Option<UntypedMemoryCapability> {
        assert!(untyped.physical_start_addr() == other.physical_start_addr(),
                "To resize, two capability's starting physical address must be the same.");
        assert!(untyped.physical_end_addr() >= other.physical_end_addr(),
                "To resize, the other capability must be within the untyped.");

        untyped.start_addr = other.physical_end_addr() + 1;
        untyped.size = untyped.size - other.physical_size();

        if untyped.size == 0 {
            None
        } else {
            Some(untyped)
        }
    }
}
<|endoftext|>


<commit_before>//! Standard Rust log crate adapter to slog-rs based on slog-scope.
//!
//! Note: this is a fork of a `slog-stdlog` that unlike original does
//! share logging scopes with `slog-scope` crate. It is currently advised
//! to prefer `slog-scope-stdlog`.
//!
//! This crate provides two way compatibility with legacy `log` crate logging.
//!
//! ### `log` -> `slog`
//!
//! After calling `init` legacy `log` crate logging statements (eg. `debug!(...)`) will
//! be redirected just like they originated from the logger returned by `slog_scope::logger()`.
//! See documentation of `slog-scope` for examples of logging scope usage.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is a `slog::Drain` implementation that will log logging `Record`s just like
//! they were created using legacy `log` statements.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily created:
//! `log` -> `slog` -> `log` -> ...
//!
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_scope;
extern crate log;

use slog::ser;

use log::LogMetadata;
use std::{io, fmt};
use std::io::Write;

use slog::Level;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            level: level,
            file: file,
            line: line,
            column: 0,
            function: "",
            module: module,
            target: target,
        };
        slog_scope::logger().log(&slog::Record::new(&s, *args, &[]))
    }
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        Box::new(Logger)
    })
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values : &'a slog::OwnedKeyValueList
}

impl<'a> LazyLogString<'a> {

    fn new(info : &'a slog::Record, logger_values : &'a slog::OwnedKeyValueList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io, ": ".into());

        let res = {
            || -> io::Result<()> {

            for (k, v) in self.logger_values.iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }

            for &(k, v) in self.info.values().iter() {
                try!(ser.io().write_all(", ".as_bytes()));
                try!(v.serialize(self.info, k, &mut ser));
            }
            Ok(())
        }
        }().map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Error = io::Error;
    fn log(&self, info: &slog::Record, logger_values : &slog::OwnedKeyValueList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.target();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    separator: String,
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W, separator: String) -> Self {
        KSV {
            io: io,
            separator: separator,
        }
    }

    fn io(&mut self) -> &mut W {
        &mut self.io
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> ser::Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}
<commit_msg>`cargo fmt`<commit_after>//! Standard Rust log crate adapter to slog-rs based on slog-scope.
//!
//! Note: this is a fork of a `slog-stdlog` that unlike original does
//! share logging scopes with `slog-scope` crate. It is currently advised
//! to prefer `slog-scope-stdlog`.
//!
//! This crate provides two way compatibility with legacy `log` crate logging.
//!
//! ### `log` -> `slog`
//!
//! After calling `init` legacy `log` crate logging statements (eg. `debug!(...)`) will
//! be redirected just like they originated from the logger returned by `slog_scope::logger()`.
//! See documentation of `slog-scope` for examples of logging scope usage.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is a `slog::Drain` implementation that will log logging `Record`s just like
//! they were created using legacy `log` statements.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily created:
//! `log` -> `slog` -> `log` -> ...
//!
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_scope;
extern crate log;

use slog::ser;

use log::LogMetadata;
use std::{io, fmt};
use std::io::Write;

use slog::Level;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            level: level,
            file: file,
            line: line,
            column: 0,
            function: "",
            module: module,
            target: target,
        };
        slog_scope::logger().log(&slog::Record::new(&s, *args, &[]))
    }
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        Box::new(Logger)
    })
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKeyValueList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKeyValueList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io, ": ".into());

        let res = {
                || -> io::Result<()> {

                    for (k, v) in self.logger_values.iter() {
                        try!(ser.io().write_all(", ".as_bytes()));
                        try!(v.serialize(self.info, k, &mut ser));
                    }

                    for &(k, v) in self.info.values().iter() {
                        try!(ser.io().write_all(", ".as_bytes()));
                        try!(v.serialize(self.info, k, &mut ser));
                    }
                    Ok(())
                }
            }()
            .map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Error = io::Error;
    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKeyValueList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.target();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    separator: String,
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W, separator: String) -> Self {
        KSV {
            io: io,
            separator: separator,
        }
    }

    fn io(&mut self) -> &mut W {
        &mut self.io
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> ser::Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}
<|endoftext|>