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

use gpu_store::GpuStoreAddress;
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use renderer::VertexDataStore;
use util::{MatrixHelpers, TransformedRect};
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
use webrender_traits::{LayerRect, LayerPoint, LayerSize};

const MAX_CLIP: f32 = 1000000.0;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ClipMode {
    Clip,           // Pixels inside the region are visible.
    ClipOut,        // Pixels outside the region are visible.
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegionMode {
    IncludeRect,
    ExcludeRect,
}

#[derive(Clone, Debug)]
pub enum ClipSource {
    Complex(LayerRect, f32, ClipMode),
    // The RegionMode here specifies whether to consider the rect
    // from the clip region as part of the mask. This is true
    // for clip/scroll nodes, but false for primitives, where
    // the clip rect is handled in local space.
    Region(ClipRegion, RegionMode),
}

impl ClipSource {
    pub fn image_mask(&self) -> Option<ImageMask> {
        match self {
            &ClipSource::Complex(..) => None,
            &ClipSource::Region(ref region, _) => region.image_mask,
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    item_count: usize,
}

/// Represents a local rect and a device space
/// bounding rect that can be updated when the
/// transform changes.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
}

impl Geometry {
    fn new(local_rect: LayerRect) -> Geometry {
        Geometry {
            local_rect: local_rect,
            bounding_rect: DeviceIntRect::zero(),
        }
    }

    fn update(&mut self,
              transform: &LayerToWorldTransform,
              device_pixel_ratio: f32) {
        let transformed = TransformedRect::new(&self.local_rect,
                                               &transform,
                                               device_pixel_ratio);
        self.bounding_rect = transformed.bounding_rect;
    }
}

/// Depending on the complexity of the clip, we may either
/// know the outer and/or inner rect, or neither or these.
/// In the case of a clip-out, we currently set the mask
/// bounds to be unknown. This is conservative, but ensures
/// correctness. In the future we can make this a lot
/// more clever with some proper region handling.
#[derive(Clone, Debug, PartialEq)]
pub enum MaskBounds {
    /// We know both the outer and inner rect. This is the
    /// fast path for, e.g. a simple rounded rect.
    OuterInner(Geometry, Geometry),
    /// We know the outer rect only.
    Outer(Geometry),
    /// We can't determine the bounds - draw mask over entire rect.
    /// This is currently used for clip-out operations on
    /// box shadows.
    None,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub effective_clip_count: usize,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub bounds: Option<MaskBounds>,
    pub is_aligned: bool,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(clips: &[ClipSource],
               clip_store: &mut VertexDataStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        if clips.is_empty() {
            return None;
        }

        let mut image = None;
        let mut clip_count = 0;

        // Work out how much clip data space we need to allocate
        // and if we have an image mask.
        for clip in clips {
            match clip {
                &ClipSource::Complex(..) => {
                    clip_count += 1;
                },
                &ClipSource::Region(ref region, region_mode) => {
                    if let Some(info) = region.image_mask {
                        debug_assert!(image.is_none());     // TODO(gw): Support >1 image mask!
                        image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
                    }

                    clip_count += region.complex.length;
                    if region_mode == RegionMode::IncludeRect {
                        clip_count += 1;
                    }
                },
            }
        }

        let clip_range = ClipAddressRange {
            start: if clip_count > 0 {
                clip_store.alloc(CLIP_DATA_GPU_SIZE * clip_count)
            } else {
                GpuStoreAddress(0)
            },
            item_count: clip_count,
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            effective_clip_count: clip_range.item_count,
            image: image,
            bounds: None,
            is_aligned: true,
        })
    }

    pub fn update(&mut self,
                  sources: &[ClipSource],
                  transform: &LayerToWorldTransform,
                  clip_store: &mut VertexDataStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {
        let is_aligned = transform.can_losslessly_transform_and_perspective_project_a_2d_rect();

        // If we haven't cached this info, or if the transform type has changed
        // we need to re-calculate the number of clips.
        if self.bounds.is_none() || self.is_aligned != is_aligned {
            let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
                                                     LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
            let mut local_inner: Option<LayerRect> = None;
            let mut has_clip_out = false;

            self.effective_clip_count = 0;
            self.is_aligned = is_aligned;

            for source in sources {
                match source {
                    &ClipSource::Complex(rect, radius, mode) => {
                        // Once we encounter a clip-out, we just assume the worst
                        // case clip mask size, for now.
                        if mode == ClipMode::ClipOut {
                            has_clip_out = true;
                        }
                        debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += 1;

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                        let data = ClipData::uniform(rect, radius, mode);
                        PrimitiveStore::populate_clip_data(slice, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&rect));
                        local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                        .get_inner_rect();
                    }
                    &ClipSource::Region(ref region, region_mode) => {
                        local_rect = local_rect.and_then(|r| r.intersection(&region.main));
                        local_inner = match region.image_mask {
                            Some(ref mask) if !mask.repeat => {
                                local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                                None
                            },
                            Some(_) => None,
                            None => local_rect,
                        };

                        let clips = aux_lists.complex_clip_regions(&region.complex);
                        if !self.is_aligned && region_mode == RegionMode::IncludeRect {
                            // we have an extra clip rect coming from the transformed layer
                            debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                            let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                            self.effective_clip_count += 1;

                            let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                            PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
                        }

                        debug_assert!(self.effective_clip_count + clips.len() < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += clips.len();

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
                        for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                            let data = ClipData::from_clip_region(clip);
                            PrimitiveStore::populate_clip_data(chunk, data);
                            local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                            local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                       .and_then(|ref inner| r.intersection(&inner)));
                        }
                    }
                }
            }

            // Work out the type of mask geometry we have, based on the
            // list of clip sources above.
            if has_clip_out {
                // For clip-out, the mask rect is not known.
                self.bounds = Some(MaskBounds::None);
            } else {
                // TODO(gw): local inner is only valid if there's a single clip (for now).
                // This can be improved in the future, with some proper
                // rectangle region handling.
                if sources.len() > 1 {
                    local_inner = None;
                }

                let local_rect = local_rect.unwrap_or(LayerRect::zero());

                self.bounds = match local_inner {
                    Some(local_inner) => {
                        Some(MaskBounds::OuterInner(Geometry::new(local_rect),
                                                    Geometry::new(local_inner)))
                    }
                    None => {
                        Some(MaskBounds::Outer(Geometry::new(local_rect)))
                    }
                };
            }
        }

        // Update the device space bounding rects of the mask
        // geometry.
        match self.bounds.as_mut().unwrap() {
            &mut MaskBounds::None => {}
            &mut MaskBounds::Outer(ref mut outer) => {
                outer.update(transform, device_pixel_ratio);
            }
            &mut MaskBounds::OuterInner(ref mut outer, ref mut inner) => {
                outer.update(transform, device_pixel_ratio);
                inner.update(transform, device_pixel_ratio);
            }
        }
    }

    /// Check if this `MaskCacheInfo` actually carries any masks. `effective_clip_count`
    /// can change during the `update` call depending on the transformation, so the mask may
    /// appear to be empty.
    pub fn is_masking(&self) -> bool {
        self.image.is_some() || self.effective_clip_count != 0
    }
}
<commit_msg>Assertion fix with `effective_clip_count`<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gpu_store::GpuStoreAddress;
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use renderer::VertexDataStore;
use util::{MatrixHelpers, TransformedRect};
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
use webrender_traits::{LayerRect, LayerPoint, LayerSize};

const MAX_CLIP: f32 = 1000000.0;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ClipMode {
    Clip,           // Pixels inside the region are visible.
    ClipOut,        // Pixels outside the region are visible.
}

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegionMode {
    IncludeRect,
    ExcludeRect,
}

#[derive(Clone, Debug)]
pub enum ClipSource {
    Complex(LayerRect, f32, ClipMode),
    // The RegionMode here specifies whether to consider the rect
    // from the clip region as part of the mask. This is true
    // for clip/scroll nodes, but false for primitives, where
    // the clip rect is handled in local space.
    Region(ClipRegion, RegionMode),
}

impl ClipSource {
    pub fn image_mask(&self) -> Option<ImageMask> {
        match self {
            &ClipSource::Complex(..) => None,
            &ClipSource::Region(ref region, _) => region.image_mask,
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipAddressRange {
    pub start: GpuStoreAddress,
    item_count: usize,
}

/// Represents a local rect and a device space
/// bounding rect that can be updated when the
/// transform changes.
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
}

impl Geometry {
    fn new(local_rect: LayerRect) -> Geometry {
        Geometry {
            local_rect: local_rect,
            bounding_rect: DeviceIntRect::zero(),
        }
    }

    fn update(&mut self,
              transform: &LayerToWorldTransform,
              device_pixel_ratio: f32) {
        let transformed = TransformedRect::new(&self.local_rect,
                                               &transform,
                                               device_pixel_ratio);
        self.bounding_rect = transformed.bounding_rect;
    }
}

/// Depending on the complexity of the clip, we may either
/// know the outer and/or inner rect, or neither or these.
/// In the case of a clip-out, we currently set the mask
/// bounds to be unknown. This is conservative, but ensures
/// correctness. In the future we can make this a lot
/// more clever with some proper region handling.
#[derive(Clone, Debug, PartialEq)]
pub enum MaskBounds {
    /// We know both the outer and inner rect. This is the
    /// fast path for, e.g. a simple rounded rect.
    OuterInner(Geometry, Geometry),
    /// We know the outer rect only.
    Outer(Geometry),
    /// We can't determine the bounds - draw mask over entire rect.
    /// This is currently used for clip-out operations on
    /// box shadows.
    None,
}

#[derive(Clone, Debug)]
pub struct MaskCacheInfo {
    pub clip_range: ClipAddressRange,
    pub effective_clip_count: usize,
    pub image: Option<(ImageMask, GpuStoreAddress)>,
    pub bounds: Option<MaskBounds>,
    pub is_aligned: bool,
}

impl MaskCacheInfo {
    /// Create a new mask cache info. It allocates the GPU store data but leaves
    /// it unitialized for the following `update()` call to deal with.
    pub fn new(clips: &[ClipSource],
               clip_store: &mut VertexDataStore<GpuBlock32>)
               -> Option<MaskCacheInfo> {
        if clips.is_empty() {
            return None;
        }

        let mut image = None;
        let mut clip_count = 0;

        // Work out how much clip data space we need to allocate
        // and if we have an image mask.
        for clip in clips {
            match clip {
                &ClipSource::Complex(..) => {
                    clip_count += 1;
                },
                &ClipSource::Region(ref region, region_mode) => {
                    if let Some(info) = region.image_mask {
                        debug_assert!(image.is_none());     // TODO(gw): Support >1 image mask!
                        image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
                    }

                    clip_count += region.complex.length;
                    if region_mode == RegionMode::IncludeRect {
                        clip_count += 1;
                    }
                },
            }
        }

        let clip_range = ClipAddressRange {
            start: if clip_count > 0 {
                clip_store.alloc(CLIP_DATA_GPU_SIZE * clip_count)
            } else {
                GpuStoreAddress(0)
            },
            item_count: clip_count,
        };

        Some(MaskCacheInfo {
            clip_range: clip_range,
            effective_clip_count: clip_range.item_count,
            image: image,
            bounds: None,
            is_aligned: true,
        })
    }

    pub fn update(&mut self,
                  sources: &[ClipSource],
                  transform: &LayerToWorldTransform,
                  clip_store: &mut VertexDataStore<GpuBlock32>,
                  device_pixel_ratio: f32,
                  aux_lists: &AuxiliaryLists) {
        let is_aligned = transform.can_losslessly_transform_and_perspective_project_a_2d_rect();

        // If we haven't cached this info, or if the transform type has changed
        // we need to re-calculate the number of clips.
        if self.bounds.is_none() || self.is_aligned != is_aligned {
            let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
                                                     LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
            let mut local_inner: Option<LayerRect> = None;
            let mut has_clip_out = false;

            self.effective_clip_count = 0;
            self.is_aligned = is_aligned;

            for source in sources {
                match source {
                    &ClipSource::Complex(rect, radius, mode) => {
                        // Once we encounter a clip-out, we just assume the worst
                        // case clip mask size, for now.
                        if mode == ClipMode::ClipOut {
                            has_clip_out = true;
                        }
                        debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += 1;

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                        let data = ClipData::uniform(rect, radius, mode);
                        PrimitiveStore::populate_clip_data(slice, data);
                        local_rect = local_rect.and_then(|r| r.intersection(&rect));
                        local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
                                                        .get_inner_rect();
                    }
                    &ClipSource::Region(ref region, region_mode) => {
                        local_rect = local_rect.and_then(|r| r.intersection(&region.main));
                        local_inner = match region.image_mask {
                            Some(ref mask) if !mask.repeat => {
                                local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                                None
                            },
                            Some(_) => None,
                            None => local_rect,
                        };

                        let clips = aux_lists.complex_clip_regions(&region.complex);
                        if !self.is_aligned && region_mode == RegionMode::IncludeRect {
                            // we have an extra clip rect coming from the transformed layer
                            debug_assert!(self.effective_clip_count < self.clip_range.item_count);
                            let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                            self.effective_clip_count += 1;

                            let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                            PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
                        }

                        debug_assert!(self.effective_clip_count + clips.len() <= self.clip_range.item_count);
                        let address = self.clip_range.start + self.effective_clip_count * CLIP_DATA_GPU_SIZE;
                        self.effective_clip_count += clips.len();

                        let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
                        for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
                            let data = ClipData::from_clip_region(clip);
                            PrimitiveStore::populate_clip_data(chunk, data);
                            local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                            local_inner = local_inner.and_then(|r| clip.get_inner_rect()
                                                                       .and_then(|ref inner| r.intersection(&inner)));
                        }
                    }
                }
            }

            // Work out the type of mask geometry we have, based on the
            // list of clip sources above.
            if has_clip_out {
                // For clip-out, the mask rect is not known.
                self.bounds = Some(MaskBounds::None);
            } else {
                // TODO(gw): local inner is only valid if there's a single clip (for now).
                // This can be improved in the future, with some proper
                // rectangle region handling.
                if sources.len() > 1 {
                    local_inner = None;
                }

                let local_rect = local_rect.unwrap_or(LayerRect::zero());

                self.bounds = match local_inner {
                    Some(local_inner) => {
                        Some(MaskBounds::OuterInner(Geometry::new(local_rect),
                                                    Geometry::new(local_inner)))
                    }
                    None => {
                        Some(MaskBounds::Outer(Geometry::new(local_rect)))
                    }
                };
            }
        }

        // Update the device space bounding rects of the mask
        // geometry.
        match self.bounds.as_mut().unwrap() {
            &mut MaskBounds::None => {}
            &mut MaskBounds::Outer(ref mut outer) => {
                outer.update(transform, device_pixel_ratio);
            }
            &mut MaskBounds::OuterInner(ref mut outer, ref mut inner) => {
                outer.update(transform, device_pixel_ratio);
                inner.update(transform, device_pixel_ratio);
            }
        }
    }

    /// Check if this `MaskCacheInfo` actually carries any masks. `effective_clip_count`
    /// can change during the `update` call depending on the transformation, so the mask may
    /// appear to be empty.
    pub fn is_masking(&self) -> bool {
        self.image.is_some() || self.effective_clip_count != 0
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment algorithms.

pub mod pairwise;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

/// An alignment, consisting of a score, a start in sequence y, a start in sequence x, a length
/// and its edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }
        else {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    pub fn pretty(&self, x: &[u8], y: &[u8]) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i : usize = self.xstart;
            let mut y_i : usize = self.ystart;

            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[diff..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                // x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[diff..x_i])));
                // y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else {
                for i in 0..x_i {
                    x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
                    y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
                }
            }

            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    },
                }
            }

            for i in x_i..x.len() {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
            }
            for i in y_i..y.len() {
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
            }
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<commit_msg>add a function for the pretty alignment<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various alignment algorithms.

pub mod pairwise;

/// Alignment operations (Match, Subst, Del and Ins).
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum AlignmentOperation {
    Match,
    Subst,
    Del,
    Ins
}

/// An alignment, consisting of a score, a start in sequence y, a start in sequence x, a length
/// and its edit operations (see alignment::pairwise for meaning of x and y).
#[derive(Debug)]
pub struct Alignment {
    pub score: i32,
    pub ystart: usize,
    pub xstart: usize,
    pub xlen: usize,
    pub operations: Vec<AlignmentOperation>
}

impl Alignment {
    /// Calculate the cigar string.
    pub fn cigar(&self, hard_clip: bool) -> String {
        let add_op = |op, k, cigar: &mut String| {
            cigar.push_str(&format!("{}{}", k, match op {
                AlignmentOperation::Match => "=",
                AlignmentOperation::Subst => "X",
                AlignmentOperation::Del => "D",
                AlignmentOperation::Ins => "I",
            }));
        };

        let op_len = |op: AlignmentOperation| {
            (op == AlignmentOperation::Match || op == AlignmentOperation::Subst || op == AlignmentOperation::Ins) as usize
        };

        let clip_str = if hard_clip {"H"} else {"S"};

        let mut cigar = String::new();

        if !self.operations.is_empty() {
            if self.xstart > 0 {
                cigar.push_str(&format!("{}{}", self.xstart, clip_str));
            }

            let mut last = self.operations[0];
            let mut k = 1;
            let mut alen = op_len(last);
            for &op in self.operations[1..].iter() {
                if op == last {
                    k += 1;
                } else {
                    add_op(last, k, &mut cigar);
                    k = 1;
                }
                last = op;
                alen += op_len(op);
            }
            add_op(last, k, &mut cigar);

            let clip = self.xlen - alen;
            if clip > 0 {
                cigar.push_str(&format!("{}{}", clip, clip_str));
            }
        }
        else {
            cigar.push_str(&format!("{}{}", self.xlen, clip_str));
        }

        cigar
    }

    /// Return the pretty formatted alignment as a String.
    pub fn pretty(&self, x: &[u8], y: &[u8]) -> String {
        let mut x_pretty = String::new();
        let mut y_pretty = String::new();
        let mut inb_pretty = String::new();

        if !self.operations.is_empty() {
            let mut x_i : usize = self.xstart;
            let mut y_i : usize = self.ystart;

            // Add '-' before aligned subsequences and un-aligned 5' substrings of sequences.
            if x_i > y_i {
                let diff = x_i - y_i;
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                for _ in 0..diff {
                    y_pretty.push('-');
                }
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..y_i])));
            } else if x_i < y_i {
                let diff = y_i - x_i;
                for _ in 0..diff {
                    x_pretty.push('-');
                }
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&x[0..x_i])));
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&y[0..y_i])));
            } else {
                for i in 0..x_i {
                    x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
                    y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
                }
            }
            for _ in 0..x_pretty.len() {
                inb_pretty.push(' ');
            }

            // Process the alignment.
            for i in 0..self.operations.len() {
                match self.operations[i] {
                    AlignmentOperation::Match => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push_str("|");

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Subst => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Del => {
                        x_pretty.push('-');

                        inb_pretty.push(' ');

                        y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[y_i]])));
                        y_i += 1;
                    },
                    AlignmentOperation::Ins => {
                        x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[x_i]])));
                        x_i += 1;

                        inb_pretty.push(' ');

                        y_pretty.push('-');
                    },
                }
            }

            // Add un-aligned 3' substrings of sequences.
            for i in x_i..x.len() {
                x_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[x[i]])));
            }
            for i in y_i..y.len() {
                y_pretty.push_str(&format!("{}", String::from_utf8_lossy(&[y[i]])));
            }

            // Add trailing '-'.
            if x_pretty.len() > y_pretty.len() {
                for _ in y_pretty.len()..x_pretty.len() {
                    y_pretty.push('-');
                }
            } else {
                for _ in x_pretty.len()..y_pretty.len() {
                    x_pretty.push('-');
                }
            }
        }

        format!("{}\n{}\n{}", x_pretty, inb_pretty, y_pretty)
    }
}

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

    #[test]
    fn test_cigar() {
        let alignment = Alignment { score: 5, xstart: 3, ystart: 0, xlen: 10, operations: vec![Match, Match, Match, Subst, Ins, Ins, Del, Del] };
        assert_eq!(alignment.cigar(false), "3S3=1X2I2D4S");
    }
}
<|endoftext|>


<commit_before>//! RLPx protocol implementation in Rust

extern crate secp256k1;
extern crate rand;

extern crate sha3;
extern crate sha2;
extern crate byteorder;
extern crate crypto;
extern crate etcommon_bigint as bigint;
extern crate etcommon_crypto as hash;
extern crate etcommon_rlp as rlp;
extern crate etcommon_util;
extern crate bytes;
#[macro_use]
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;

mod util;
pub mod ecies;
mod peer;
mod mac;
mod errors;

pub use peer::{PeerStream, CapabilityInfo};

use bigint::H512;
use util::pk2id;
use hash::SECP256K1;
use secp256k1::key::{PublicKey, SecretKey};
use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use std::io;
use std::net::SocketAddr;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Sending node type specifying either all, any or a particular peer
pub enum Node {
    Any,
    All,
    Peer(H512),
}

/// A RLPx stream and sink
pub struct RLPxStream {
    streams: Vec<PeerStream>,
    futures: Vec<Box<Future<Item = PeerStream, Error = io::Error>>>,
    secret_key: SecretKey,
    protocol_version: usize,
    client_version: String,
    capabilities: Vec<CapabilityInfo>,
    port: u16,
    handle: Handle,
}

impl RLPxStream {
    /// Create a new RLPx stream
    pub fn new(handle: &Handle, secret_key: SecretKey, protocol_version: usize,
               client_version: String, capabilities: Vec<CapabilityInfo>,
               port: u16) -> RLPxStream {
        RLPxStream {
            streams: Vec::new(),
            futures: Vec::new(),
            secret_key, protocol_version, client_version,
            capabilities, port,
            handle: handle.clone(),
        }
    }

    /// Append a new peer to this RLPx stream
    pub fn add_peer(
        &mut self, addr: &SocketAddr, remote_id: H512
    ) {
        let future = PeerStream::connect(addr, &self.handle, self.secret_key.clone(),
                                         remote_id, self.protocol_version,
                                         self.client_version.clone(),
                                         self.capabilities.clone(), self.port);
        self.futures.push(future);
    }

    /// Poll over new peers to resolve them to TCP streams
    pub fn poll_new_peers(&mut self) -> Poll<(), io::Error> {
        let ref mut futures = self.futures;
        let ref mut streams = self.streams;

        let mut all_ready = true;

        retain_mut(futures, |ref mut future| {
            match future.poll() {
                Ok(Async::NotReady) => {
                    all_ready = false;
                    true
                },
                Ok(Async::Ready(peer)) => {
                    streams.push(peer);
                    false
                },
                Err(e) => false,
            }
        });

        if all_ready {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }

    /// Active peers count
    pub fn active_peers_len(&self) -> usize {
        self.futures.len() + self.streams.len()
    }
}

fn retain_mut<T, F>(vec: &mut Vec<T>, mut f: F)
    where F: FnMut(&mut T) -> bool
{
    let len = vec.len();
    let mut del = 0;
    {
        let v = &mut **vec;

        for i in 0..len {
            if !f(&mut v[i]) {
                del += 1;
            } else if del > 0 {
                v.swap(i - del, i);
            }
        }
    }
    if del > 0 {
        vec.truncate(len - del);
    }
}

impl Stream for RLPxStream {
    type Item = (H512, CapabilityInfo, usize, Vec<u8>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_new_peers();

        let ref mut streams = self.streams;

        let mut ret: Option<Self::Item> = None;
        retain_mut(streams, |ref mut peer| {
            if ret.is_some() {
                return true;
            }

            let id = peer.remote_id();
            match peer.poll() {
                Ok(Async::NotReady) => true,
                Ok(Async::Ready(None)) => false,
                Ok(Async::Ready(Some((cap, message_id, data)))) => {
                    ret = Some((id, cap, message_id, data));
                    true
                },
                Err(e) => false,
            }
        });

        if ret.is_some() {
            Ok(Async::Ready(ret))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl Sink for RLPxStream {
    type SinkItem = (Node, CapabilityInfo, usize, Vec<u8>);
    type SinkError = io::Error;

    fn start_send(&mut self, (node, cap, message_id, data): (Node, CapabilityInfo, usize, Vec<u8>)) -> StartSend<Self::SinkItem, Self::SinkError> {
        self.poll_new_peers();

        let ref mut streams = self.streams;

        let mut any_ready = false;

        retain_mut(streams, |ref mut peer| {
            let id = peer.remote_id();

            if match node {
                Node::Peer(peer_id) => peer_id == id,
                Node::All => true,
                Node::Any => !any_ready,
            } {
                match peer.start_send((cap.clone(), message_id, data.clone())) {
                    Ok(AsyncSink::Ready) => {
                        any_ready = true;
                        true
                    },
                    Ok(AsyncSink::NotReady(_)) => true,
                    Err(e) => false,
                }
            } else {
                true
            }
        });

        if any_ready {
            Ok(AsyncSink::Ready)
        } else {
            Ok(AsyncSink::NotReady((node, cap, message_id, data)))
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        let ref mut streams = self.streams;

        let mut all_ready = true;

        retain_mut(streams, |ref mut peer| {
            match peer.poll_complete() {
                Ok(Async::Ready(())) => true,
                Ok(Async::NotReady) => {
                    all_ready = false;
                    true
                },
                Err(e) => false,
            }
        });

        if all_ready {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>rlpx: implement active_peers<commit_after>//! RLPx protocol implementation in Rust

extern crate secp256k1;
extern crate rand;

extern crate sha3;
extern crate sha2;
extern crate byteorder;
extern crate crypto;
extern crate etcommon_bigint as bigint;
extern crate etcommon_crypto as hash;
extern crate etcommon_rlp as rlp;
extern crate etcommon_util;
extern crate bytes;
#[macro_use]
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;

mod util;
pub mod ecies;
mod peer;
mod mac;
mod errors;

pub use peer::{PeerStream, CapabilityInfo};

use bigint::H512;
use util::pk2id;
use hash::SECP256K1;
use secp256k1::key::{PublicKey, SecretKey};
use futures::future;
use futures::{Poll, Async, StartSend, AsyncSink, Future, Stream, Sink};
use std::io;
use std::net::SocketAddr;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::{Framed, Encoder, Decoder};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Sending node type specifying either all, any or a particular peer
pub enum Node {
    Any,
    All,
    Peer(H512),
}

/// A RLPx stream and sink
pub struct RLPxStream {
    streams: Vec<PeerStream>,
    futures: Vec<(H512, Box<Future<Item = PeerStream, Error = io::Error>>)>,
    active_peers: Vec<H512>,
    secret_key: SecretKey,
    protocol_version: usize,
    client_version: String,
    capabilities: Vec<CapabilityInfo>,
    port: u16,
    handle: Handle,
}

impl RLPxStream {
    /// Create a new RLPx stream
    pub fn new(handle: &Handle, secret_key: SecretKey, protocol_version: usize,
               client_version: String, capabilities: Vec<CapabilityInfo>,
               port: u16) -> RLPxStream {
        RLPxStream {
            streams: Vec::new(),
            futures: Vec::new(),
            secret_key, protocol_version, client_version,
            capabilities, port,
            handle: handle.clone(),
            active_peers: Vec::new(),
        }
    }

    /// Append a new peer to this RLPx stream
    pub fn add_peer(
        &mut self, addr: &SocketAddr, remote_id: H512
    ) {
        let future = PeerStream::connect(addr, &self.handle, self.secret_key.clone(),
                                         remote_id, self.protocol_version,
                                         self.client_version.clone(),
                                         self.capabilities.clone(), self.port);
        self.futures.push((remote_id, future));
        self.active_peers.push(remote_id);
    }

    /// Poll over new peers to resolve them to TCP streams
    pub fn poll_new_peers(&mut self) -> Poll<(), io::Error> {
        let ref mut futures = self.futures;
        let ref mut streams = self.streams;
        let ref mut active_peers = self.active_peers;

        let mut all_ready = true;

        retain_mut(futures, |&mut (remote_id, ref mut future)| {
            match future.poll() {
                Ok(Async::NotReady) => {
                    all_ready = false;
                    true
                },
                Ok(Async::Ready(peer)) => {
                    streams.push(peer);
                    false
                },
                Err(e) => {
                    active_peers.retain(|peer_id| {
                        *peer_id != remote_id
                    });
                    false
                },
            }
        });

        if all_ready {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }

    /// Active peers
    pub fn active_peers(&self) -> &[H512] {
        self.active_peers.as_ref()
    }
}

fn retain_mut<T, F>(vec: &mut Vec<T>, mut f: F)
    where F: FnMut(&mut T) -> bool
{
    let len = vec.len();
    let mut del = 0;
    {
        let v = &mut **vec;

        for i in 0..len {
            if !f(&mut v[i]) {
                del += 1;
            } else if del > 0 {
                v.swap(i - del, i);
            }
        }
    }
    if del > 0 {
        vec.truncate(len - del);
    }
}

impl Stream for RLPxStream {
    type Item = (H512, CapabilityInfo, usize, Vec<u8>);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_new_peers();

        let ref mut streams = self.streams;
        let ref mut active_peers = self.active_peers;

        let mut ret: Option<Self::Item> = None;
        retain_mut(streams, |ref mut peer| {
            if ret.is_some() {
                return true;
            }

            let id = peer.remote_id();
            match peer.poll() {
                Ok(Async::NotReady) => true,
                Ok(Async::Ready(None)) => false,
                Ok(Async::Ready(Some((cap, message_id, data)))) => {
                    ret = Some((id, cap, message_id, data));
                    true
                },
                Err(e) => {
                    active_peers.retain(|peer_id| {
                        *peer_id != id
                    });
                    false
                },
            }
        });

        if ret.is_some() {
            Ok(Async::Ready(ret))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl Sink for RLPxStream {
    type SinkItem = (Node, CapabilityInfo, usize, Vec<u8>);
    type SinkError = io::Error;

    fn start_send(&mut self, (node, cap, message_id, data): (Node, CapabilityInfo, usize, Vec<u8>)) -> StartSend<Self::SinkItem, Self::SinkError> {
        self.poll_new_peers();

        let ref mut streams = self.streams;
        let ref mut active_peers = self.active_peers;

        let mut any_ready = false;

        retain_mut(streams, |ref mut peer| {
            let id = peer.remote_id();

            if match node {
                Node::Peer(peer_id) => peer_id == id,
                Node::All => true,
                Node::Any => !any_ready,
            } {
                let remote_id = peer.remote_id();
                match peer.start_send((cap.clone(), message_id, data.clone())) {
                    Ok(AsyncSink::Ready) => {
                        any_ready = true;
                        true
                    },
                    Ok(AsyncSink::NotReady(_)) => true,
                    Err(e) => {
                        active_peers.retain(|peer_id| {
                            *peer_id != remote_id
                        });
                        false
                    },
                }
            } else {
                true
            }
        });

        if any_ready {
            Ok(AsyncSink::Ready)
        } else {
            Ok(AsyncSink::NotReady((node, cap, message_id, data)))
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        let ref mut streams = self.streams;
        let ref mut active_peers = self.active_peers;

        let mut all_ready = true;

        retain_mut(streams, |ref mut peer| {
            let remote_id = peer.remote_id();
            match peer.poll_complete() {
                Ok(Async::Ready(())) => true,
                Ok(Async::NotReady) => {
                    all_ready = false;
                    true
                },
                Err(e) => {
                    active_peers.retain(|peer_id| {
                        *peer_id != remote_id
                    });
                    false
                },
            }
        });

        if all_ready {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use libc;
use std::{mem, ptr};
use std::ffi::CString;
use std::slice::from_raw_parts;

use events::Event;

use super::{events, ffi};
use super::XConnection;

#[derive(Debug)]
enum AxisType {
    HorizontalScroll,
    VerticalScroll
}

#[derive(Debug)]
struct Axis {
    id: i32,
    device_id: i32,
    axis_number: i32,
    axis_type: AxisType
}

#[derive(Debug)]
struct AxisValue {
    device_id: i32,
    axis_number: i32,
    value: f64
}

struct InputState {
    /// Last-seen cursor position within a window in (x, y)
    /// coordinates
    cursor_pos: (f64, f64),
    /// Last-seen positions of axes, used to report delta
    /// movements when a new absolute axis value is received
    axis_values: Vec<AxisValue>
}

pub struct XInputEventHandler {
    display: Arc<XConnection>,
    window: ffi::Window,
    ic: ffi::XIC,
    axis_list: Vec<Axis>,
    current_state: InputState
}

impl XInputEventHandler {
    pub fn new(display: &Arc<XConnection>, window: ffi::Window, ic: ffi::XIC) -> XInputEventHandler {
        // query XInput support
        let mut opcode: libc::c_int = 0;
        let mut event: libc::c_int = 0;
        let mut error: libc::c_int = 0;
        let xinput_str = CString::new("XInputExtension").unwrap();

        unsafe {
            if (display.xlib.XQueryExtension)(display.display, xinput_str.as_ptr(), &mut opcode, &mut event, &mut error) == ffi::False {
                panic!("XInput not available")
            }
        }

        let mut xinput_major_ver = ffi::XI_2_Major;
        let mut xinput_minor_ver = ffi::XI_2_Minor;

        unsafe {
            if (display.xinput2.XIQueryVersion)(display.display, &mut xinput_major_ver, &mut xinput_minor_ver) != ffi::Success as libc::c_int {
                panic!("Unable to determine XInput version");
            }
        }

        // specify the XInput events we want to receive.
        // Button clicks and mouse events are handled via XInput
        // events. Key presses are still handled via plain core
        // X11 events.
        let mut mask: [libc::c_uchar; 2] = [0, 0];
        let mut input_event_mask = ffi::XIEventMask {
            deviceid: ffi::XIAllMasterDevices,
            mask_len: mask.len() as i32,
            mask: mask.as_mut_ptr()
        };
        let events = &[
            ffi::XI_ButtonPress,
            ffi::XI_ButtonRelease,
            ffi::XI_Motion,
            ffi::XI_Enter,
            ffi::XI_Leave,
            ffi::XI_FocusIn,
            ffi::XI_FocusOut
        ];
        for event in events {
            ffi::XISetMask(&mut mask, *event);
        }

        unsafe {
            match (display.xinput2.XISelectEvents)(display.display, window, &mut input_event_mask, 1) {
                status if status as u8 == ffi::Success => (),
                err => panic!("Failed to select events {:?}", err)
            }
        }

        XInputEventHandler {
            display: display.clone(),
            window: window,
            ic: ic,
            axis_list: read_input_axis_info(display),
            current_state: InputState {
                cursor_pos: (0.0, 0.0),
                axis_values: Vec::new()
            }
        }
    }

    pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
        use events::Event::{KeyboardInput, ReceivedCharacter};
        use events::ElementState::{Pressed, Released};

        let mut translated_events = Vec::new();

        let state;
        if event.type_ == ffi::KeyPress {
            let raw_ev: *mut ffi::XKeyEvent = event;
            unsafe { (self.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window) };
            state = Pressed;
        } else {
            state = Released;
        }

        let mut kp_keysym = 0;

        let written = unsafe {
            use std::str;

            let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
            let raw_ev: *mut ffi::XKeyEvent = event;
            let count = (self.display.xlib.Xutf8LookupString)(self.ic, mem::transmute(raw_ev),
            mem::transmute(buffer.as_mut_ptr()),
            buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut());

            str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
        };

        for chr in written.chars() {
            translated_events.push(ReceivedCharacter(chr));
        }

        let mut keysym = unsafe {
            (self.display.xlib.XKeycodeToKeysym)(self.display.display, event.keycode as ffi::KeyCode, 0)
        };

        if (ffi::XK_KP_Space as libc::c_ulong <= keysym) && (keysym <= ffi::XK_KP_9 as libc::c_ulong) {
            keysym = kp_keysym
        };

        let vkey = events::keycode_to_element(keysym as libc::c_uint);

        translated_events.push(KeyboardInput(state, event.keycode as u8, vkey));
        translated_events
    }

    pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
        use events::Event::{Focused, MouseInput, MouseMoved, MouseWheel};
        use events::ElementState::{Pressed, Released};
        use events::MouseButton::{Left, Right, Middle};
        use events::MouseScrollDelta::{PixelDelta, LineDelta};

        match cookie.evtype {
            ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let state = if cookie.evtype == ffi::XI_ButtonPress {
                    Pressed
                } else {
                    Released
                };
                match event_data.detail as u32 {
                    ffi::Button1 => Some(MouseInput(state, Left)),
                    ffi::Button2 => Some(MouseInput(state, Middle)),
                    ffi::Button3 => Some(MouseInput(state, Right)),
                    ffi::Button4 | ffi::Button5 => {
                        if event_data.flags & ffi::XIPointerEmulated == 0 {
                            // scroll event from a traditional wheel with
                            // distinct 'clicks'
                            let delta = if event_data.detail as u32 == ffi::Button4 {
                                1.0
                            } else {
                                -1.0
                            };
                            Some(MouseWheel(LineDelta(0.0, delta)))
                        } else {
                            // emulated button event from a touch/smooth-scroll
                            // event. Ignore these events and handle scrolling
                            // via XI_Motion event handler instead
                            None
                        }
                    }
                    _ => None
                }
            },
            ffi::XI_Motion => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let axis_state = event_data.valuators;
                let mask = unsafe{ from_raw_parts(axis_state.mask, axis_state.mask_len as usize) };
                let mut axis_count = 0;

                let mut scroll_delta = (0.0, 0.0);
                for axis_id in 0..axis_state.mask_len {
                    if ffi::XIMaskIsSet(&mask, axis_id) {
                        let axis_value = unsafe{*axis_state.values.offset(axis_count)};
                        let delta = calc_scroll_deltas(event_data, axis_id, axis_value, &self.axis_list,
                                                       &mut self.current_state.axis_values);
                        scroll_delta.0 += delta.0;
                        scroll_delta.1 += delta.1;
                        axis_count += 1;
                    }
                }

                if scroll_delta.0.abs() > 0.0 || scroll_delta.1.abs() > 0.0 {
                    Some(MouseWheel(PixelDelta(scroll_delta.0 as f32, scroll_delta.1 as f32)))
                } else {
                    let new_cursor_pos = (event_data.event_x, event_data.event_y);
                    if new_cursor_pos != self.current_state.cursor_pos {
                        self.current_state.cursor_pos = new_cursor_pos;
                        Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
                    } else {
                        None
                    }
                }
            },
            ffi::XI_Enter => {
                // axis movements whilst the cursor is outside the window
                // will alter the absolute value of the axes. We only want to
                // report changes in the axis value whilst the cursor is above
                // our window however, so clear the previous axis state whenever
                // the cursor re-enters the window
                self.current_state.axis_values.clear();
                None
            },
            ffi::XI_Leave => None,
            ffi::XI_FocusIn => Some(Focused(true)),
            ffi::XI_FocusOut => Some(Focused(false)),
            _ => None
        }
    }
}

fn read_input_axis_info(display: &Arc<XConnection>) -> Vec<Axis> {
    let mut axis_list = Vec::new();
    let mut device_count = 0;

    // only get events from the master devices which are 'attached'
    // to the keyboard or cursor
    let devices = unsafe{
        (display.xinput2.XIQueryDevice)(display.display, ffi::XIAllMasterDevices, &mut device_count)
    };
    for i in 0..device_count {
        let device = unsafe { *(devices.offset(i as isize)) };
        for k in 0..device.num_classes {
            let class = unsafe { *(device.classes.offset(k as isize)) };
            match unsafe { (*class)._type } {
                // Note that scroll axis
                // are reported both as 'XIScrollClass' and 'XIValuatorClass'
                // axes. For the moment we only care about scrolling axes.
                ffi::XIScrollClass => {
                    let scroll_class: &ffi::XIScrollClassInfo = unsafe{mem::transmute(class)};
                    axis_list.push(Axis{
                        id: scroll_class.sourceid,
                        device_id: device.deviceid,
                        axis_number: scroll_class.number,
                        axis_type: match scroll_class.scroll_type {
                            ffi::XIScrollTypeHorizontal => AxisType::HorizontalScroll,
                            ffi::XIScrollTypeVertical => AxisType::VerticalScroll,
                            _ => { unreachable!() }
                        }
                    })
                },
                _ => {}
            }
        }
    }

    axis_list
}

/// Given an input motion event for an axis and the previous
/// state of the axes, return the horizontal/vertical
/// scroll deltas
fn calc_scroll_deltas(event: &ffi::XIDeviceEvent,
                     axis_id: i32,
                     axis_value: f64,
                     axis_list: &[Axis],
                     prev_axis_values: &mut Vec<AxisValue>) -> (f64, f64) {
    let prev_value_pos = prev_axis_values.iter().position(|prev_axis| {
        prev_axis.device_id == event.sourceid &&
            prev_axis.axis_number == axis_id
    });
    let delta = match prev_value_pos {
        Some(idx) => axis_value - prev_axis_values[idx].value,
        None => 0.0
    };

    let new_axis_value = AxisValue{
        device_id: event.sourceid,
        axis_number: axis_id,
        value: axis_value
    };

    match prev_value_pos {
        Some(idx) => prev_axis_values[idx] = new_axis_value,
        None => prev_axis_values.push(new_axis_value)
    }

    let mut scroll_delta = (0.0, 0.0);

    for axis in axis_list.iter() {
        if axis.id == event.sourceid &&
            axis.axis_number == axis_id {
                match axis.axis_type {
                    AxisType::HorizontalScroll => scroll_delta.0 = delta,
                    AxisType::VerticalScroll => scroll_delta.1 = delta
                }
            }
    }

    scroll_delta
}

<commit_msg>Handle touch events on X11<commit_after>use std::sync::Arc;

use libc;
use std::{mem, ptr};
use std::ffi::CString;
use std::slice::from_raw_parts;

use events::Event;

use super::{events, ffi};
use super::XConnection;

#[derive(Debug)]
enum AxisType {
    HorizontalScroll,
    VerticalScroll
}

#[derive(Debug)]
struct Axis {
    id: i32,
    device_id: i32,
    axis_number: i32,
    axis_type: AxisType
}

#[derive(Debug)]
struct AxisValue {
    device_id: i32,
    axis_number: i32,
    value: f64
}

struct InputState {
    /// Last-seen cursor position within a window in (x, y)
    /// coordinates
    cursor_pos: (f64, f64),
    /// Last-seen positions of axes, used to report delta
    /// movements when a new absolute axis value is received
    axis_values: Vec<AxisValue>
}

pub struct XInputEventHandler {
    display: Arc<XConnection>,
    window: ffi::Window,
    ic: ffi::XIC,
    axis_list: Vec<Axis>,
    current_state: InputState
}

impl XInputEventHandler {
    pub fn new(display: &Arc<XConnection>, window: ffi::Window, ic: ffi::XIC) -> XInputEventHandler {
        // query XInput support
        let mut opcode: libc::c_int = 0;
        let mut event: libc::c_int = 0;
        let mut error: libc::c_int = 0;
        let xinput_str = CString::new("XInputExtension").unwrap();

        unsafe {
            if (display.xlib.XQueryExtension)(display.display, xinput_str.as_ptr(), &mut opcode, &mut event, &mut error) == ffi::False {
                panic!("XInput not available")
            }
        }

        let mut xinput_major_ver = ffi::XI_2_Major;
        let mut xinput_minor_ver = ffi::XI_2_Minor;

        unsafe {
            if (display.xinput2.XIQueryVersion)(display.display, &mut xinput_major_ver, &mut xinput_minor_ver) != ffi::Success as libc::c_int {
                panic!("Unable to determine XInput version");
            }
        }

        // specify the XInput events we want to receive.
        // Button clicks and mouse events are handled via XInput
        // events. Key presses are still handled via plain core
        // X11 events.
        let mut mask: [libc::c_uchar; 3] = [0; 3];
        let mut input_event_mask = ffi::XIEventMask {
            deviceid: ffi::XIAllMasterDevices,
            mask_len: mask.len() as i32,
            mask: mask.as_mut_ptr()
        };
        let events = &[
            ffi::XI_ButtonPress,
            ffi::XI_ButtonRelease,
            ffi::XI_Motion,
            ffi::XI_Enter,
            ffi::XI_Leave,
            ffi::XI_FocusIn,
            ffi::XI_FocusOut,
            ffi::XI_TouchBegin,
            ffi::XI_TouchUpdate,
            ffi::XI_TouchEnd,
        ];
        for event in events {
            ffi::XISetMask(&mut mask, *event);
        }

        unsafe {
            match (display.xinput2.XISelectEvents)(display.display, window, &mut input_event_mask, 1) {
                status if status as u8 == ffi::Success => (),
                err => panic!("Failed to select events {:?}", err)
            }
        }

        XInputEventHandler {
            display: display.clone(),
            window: window,
            ic: ic,
            axis_list: read_input_axis_info(display),
            current_state: InputState {
                cursor_pos: (0.0, 0.0),
                axis_values: Vec::new()
            }
        }
    }

    pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
        use events::Event::{KeyboardInput, ReceivedCharacter};
        use events::ElementState::{Pressed, Released};

        let mut translated_events = Vec::new();

        let state;
        if event.type_ == ffi::KeyPress {
            let raw_ev: *mut ffi::XKeyEvent = event;
            unsafe { (self.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window) };
            state = Pressed;
        } else {
            state = Released;
        }

        let mut kp_keysym = 0;

        let written = unsafe {
            use std::str;

            let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
            let raw_ev: *mut ffi::XKeyEvent = event;
            let count = (self.display.xlib.Xutf8LookupString)(self.ic, mem::transmute(raw_ev),
            mem::transmute(buffer.as_mut_ptr()),
            buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut());

            str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
        };

        for chr in written.chars() {
            translated_events.push(ReceivedCharacter(chr));
        }

        let mut keysym = unsafe {
            (self.display.xlib.XKeycodeToKeysym)(self.display.display, event.keycode as ffi::KeyCode, 0)
        };

        if (ffi::XK_KP_Space as libc::c_ulong <= keysym) && (keysym <= ffi::XK_KP_9 as libc::c_ulong) {
            keysym = kp_keysym
        };

        let vkey = events::keycode_to_element(keysym as libc::c_uint);

        translated_events.push(KeyboardInput(state, event.keycode as u8, vkey));
        translated_events
    }

    pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
        use events::Event::{Focused, MouseInput, MouseMoved, MouseWheel};
        use events::ElementState::{Pressed, Released};
        use events::MouseButton::{Left, Right, Middle};
        use events::MouseScrollDelta::{PixelDelta, LineDelta};
        use events::{Touch, TouchPhase};

        match cookie.evtype {
            ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let state = if cookie.evtype == ffi::XI_ButtonPress {
                    Pressed
                } else {
                    Released
                };
                match event_data.detail as u32 {
                    ffi::Button1 => Some(MouseInput(state, Left)),
                    ffi::Button2 => Some(MouseInput(state, Middle)),
                    ffi::Button3 => Some(MouseInput(state, Right)),
                    ffi::Button4 | ffi::Button5 => {
                        if event_data.flags & ffi::XIPointerEmulated == 0 {
                            // scroll event from a traditional wheel with
                            // distinct 'clicks'
                            let delta = if event_data.detail as u32 == ffi::Button4 {
                                1.0
                            } else {
                                -1.0
                            };
                            Some(MouseWheel(LineDelta(0.0, delta)))
                        } else {
                            // emulated button event from a touch/smooth-scroll
                            // event. Ignore these events and handle scrolling
                            // via XI_Motion event handler instead
                            None
                        }
                    }
                    _ => None
                }
            },
            ffi::XI_Motion => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let axis_state = event_data.valuators;
                let mask = unsafe{ from_raw_parts(axis_state.mask, axis_state.mask_len as usize) };
                let mut axis_count = 0;

                let mut scroll_delta = (0.0, 0.0);
                for axis_id in 0..axis_state.mask_len {
                    if ffi::XIMaskIsSet(&mask, axis_id) {
                        let axis_value = unsafe{*axis_state.values.offset(axis_count)};
                        let delta = calc_scroll_deltas(event_data, axis_id, axis_value, &self.axis_list,
                                                       &mut self.current_state.axis_values);
                        scroll_delta.0 += delta.0;
                        scroll_delta.1 += delta.1;
                        axis_count += 1;
                    }
                }

                if scroll_delta.0.abs() > 0.0 || scroll_delta.1.abs() > 0.0 {
                    Some(MouseWheel(PixelDelta(scroll_delta.0 as f32, scroll_delta.1 as f32)))
                } else {
                    let new_cursor_pos = (event_data.event_x, event_data.event_y);
                    if new_cursor_pos != self.current_state.cursor_pos {
                        self.current_state.cursor_pos = new_cursor_pos;
                        Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
                    } else {
                        None
                    }
                }
            },
            ffi::XI_Enter => {
                // axis movements whilst the cursor is outside the window
                // will alter the absolute value of the axes. We only want to
                // report changes in the axis value whilst the cursor is above
                // our window however, so clear the previous axis state whenever
                // the cursor re-enters the window
                self.current_state.axis_values.clear();
                None
            },
            ffi::XI_Leave => None,
            ffi::XI_FocusIn => Some(Focused(true)),
            ffi::XI_FocusOut => Some(Focused(false)),
            ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
                let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
                let phase = match cookie.evtype {
                    ffi::XI_TouchBegin => TouchPhase::Started,
                    ffi::XI_TouchUpdate => TouchPhase::Moved,
                    ffi::XI_TouchEnd => TouchPhase::Ended,
                    _ => unreachable!()
                };
                Some(Event::Touch(Touch {
                    phase: phase,
                    location: (event_data.event_x, event_data.event_y),
                    id: event_data.detail as u64,
                }))
            }
            _ => None
        }
    }
}

fn read_input_axis_info(display: &Arc<XConnection>) -> Vec<Axis> {
    let mut axis_list = Vec::new();
    let mut device_count = 0;

    // only get events from the master devices which are 'attached'
    // to the keyboard or cursor
    let devices = unsafe{
        (display.xinput2.XIQueryDevice)(display.display, ffi::XIAllMasterDevices, &mut device_count)
    };
    for i in 0..device_count {
        let device = unsafe { *(devices.offset(i as isize)) };
        for k in 0..device.num_classes {
            let class = unsafe { *(device.classes.offset(k as isize)) };
            match unsafe { (*class)._type } {
                // Note that scroll axis
                // are reported both as 'XIScrollClass' and 'XIValuatorClass'
                // axes. For the moment we only care about scrolling axes.
                ffi::XIScrollClass => {
                    let scroll_class: &ffi::XIScrollClassInfo = unsafe{mem::transmute(class)};
                    axis_list.push(Axis{
                        id: scroll_class.sourceid,
                        device_id: device.deviceid,
                        axis_number: scroll_class.number,
                        axis_type: match scroll_class.scroll_type {
                            ffi::XIScrollTypeHorizontal => AxisType::HorizontalScroll,
                            ffi::XIScrollTypeVertical => AxisType::VerticalScroll,
                            _ => { unreachable!() }
                        }
                    })
                },
                _ => {}
            }
        }
    }

    axis_list
}

/// Given an input motion event for an axis and the previous
/// state of the axes, return the horizontal/vertical
/// scroll deltas
fn calc_scroll_deltas(event: &ffi::XIDeviceEvent,
                     axis_id: i32,
                     axis_value: f64,
                     axis_list: &[Axis],
                     prev_axis_values: &mut Vec<AxisValue>) -> (f64, f64) {
    let prev_value_pos = prev_axis_values.iter().position(|prev_axis| {
        prev_axis.device_id == event.sourceid &&
            prev_axis.axis_number == axis_id
    });
    let delta = match prev_value_pos {
        Some(idx) => axis_value - prev_axis_values[idx].value,
        None => 0.0
    };

    let new_axis_value = AxisValue{
        device_id: event.sourceid,
        axis_number: axis_id,
        value: axis_value
    };

    match prev_value_pos {
        Some(idx) => prev_axis_values[idx] = new_axis_value,
        None => prev_axis_values.push(new_axis_value)
    }

    let mut scroll_delta = (0.0, 0.0);

    for axis in axis_list.iter() {
        if axis.id == event.sourceid &&
            axis.axis_number == axis_id {
                match axis.axis_type {
                    AxisType::HorizontalScroll => scroll_delta.0 = delta,
                    AxisType::VerticalScroll => scroll_delta.1 = delta
                }
            }
    }

    scroll_delta
}

<|endoftext|>


<commit_before>use crate::descriptor::field_descriptor_proto::Type;
use crate::reflect::ReflectRepeatedMut;
use crate::reflect::ReflectValueBox;
use crate::reflect::RuntimeTypeBox;
use crate::rt;
use crate::wire_format::WireType;
use crate::CodedInputStream;
use crate::ProtobufError;
use crate::ProtobufResult;

/// Runtime type and protobuf type.
pub(crate) struct ProtobufTypeBox {
    runtime: RuntimeTypeBox,
    t: Type,
}

impl ProtobufTypeBox {
    pub(crate) fn new(runtime: RuntimeTypeBox, t: Type) -> ProtobufResult<ProtobufTypeBox> {
        match (t, &runtime) {
            (Type::TYPE_INT32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_INT64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_UINT32, RuntimeTypeBox::U32) => {}
            (Type::TYPE_UINT64, RuntimeTypeBox::U64) => {}
            (Type::TYPE_SINT32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_SINT64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_FIXED32, RuntimeTypeBox::U32) => {}
            (Type::TYPE_FIXED64, RuntimeTypeBox::U64) => {}
            (Type::TYPE_SFIXED32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_SFIXED64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_FLOAT, RuntimeTypeBox::F32) => {}
            (Type::TYPE_DOUBLE, RuntimeTypeBox::F64) => {}
            (Type::TYPE_BOOL, RuntimeTypeBox::Bool) => {}
            (Type::TYPE_STRING, RuntimeTypeBox::String) => {}
            (Type::TYPE_BYTES, RuntimeTypeBox::VecU8) => {}
            (Type::TYPE_MESSAGE, RuntimeTypeBox::Message(..)) => {}
            (Type::TYPE_ENUM, RuntimeTypeBox::Enum(..)) => {}
            (Type::TYPE_GROUP, ..) => return Err(ProtobufError::GroupIsNotImplemented),
            _ => return Err(ProtobufError::IncompatibleProtobufTypeAndRuntimeType),
        }
        Ok(ProtobufTypeBox { runtime, t })
    }

    pub(crate) fn read(
        &self,
        is: &mut CodedInputStream,
        wire_type: WireType,
    ) -> ProtobufResult<ReflectValueBox> {
        if wire_type != WireType::for_type(self.t) {
            return Err(rt::unexpected_wire_type(wire_type));
        }
        Ok(match self.t {
            Type::TYPE_DOUBLE => ReflectValueBox::F64(is.read_double()?),
            Type::TYPE_FLOAT => ReflectValueBox::F32(is.read_float()?),
            Type::TYPE_INT64 => ReflectValueBox::I64(is.read_int64()?),
            Type::TYPE_UINT64 => ReflectValueBox::U64(is.read_uint64()?),
            Type::TYPE_INT32 => ReflectValueBox::I32(is.read_int32()?),
            Type::TYPE_FIXED64 => ReflectValueBox::U64(is.read_fixed64()?),
            Type::TYPE_FIXED32 => ReflectValueBox::U32(is.read_fixed32()?),
            Type::TYPE_BOOL => ReflectValueBox::Bool(is.read_bool()?),
            Type::TYPE_UINT32 => ReflectValueBox::U32(is.read_uint32()?),
            Type::TYPE_SFIXED32 => ReflectValueBox::I32(is.read_sfixed32()?),
            Type::TYPE_SFIXED64 => ReflectValueBox::I64(is.read_sfixed64()?),
            Type::TYPE_SINT32 => ReflectValueBox::I32(is.read_sint32()?),
            Type::TYPE_SINT64 => ReflectValueBox::I64(is.read_sint64()?),
            Type::TYPE_STRING => ReflectValueBox::String(is.read_string()?),
            Type::TYPE_BYTES => ReflectValueBox::Bytes(is.read_bytes()?),
            Type::TYPE_ENUM => match &self.runtime {
                RuntimeTypeBox::Enum(e) => {
                    let v = is.read_enum_value()?;
                    ReflectValueBox::Enum(e.clone(), v)
                }
                _ => unreachable!(),
            },
            Type::TYPE_GROUP => return Err(ProtobufError::GroupIsNotImplemented),
            Type::TYPE_MESSAGE => match &self.runtime {
                RuntimeTypeBox::Message(m) => ReflectValueBox::Message(is.read_message_dyn(m)?),
                _ => unreachable!(),
            },
        })
    }

    pub(crate) fn read_repeated_into(
        &self,
        is: &mut CodedInputStream,
        wire_type: WireType,
        repeated: &mut ReflectRepeatedMut,
    ) -> ProtobufResult<()> {
        let _ = (is, wire_type, repeated);
        unimplemented!()
    }
}
<commit_msg>ProtobufTypeBox::read_repeated_into one more step<commit_after>use crate::descriptor::field_descriptor_proto::Type;
use crate::reflect::ReflectRepeatedMut;
use crate::reflect::ReflectValueBox;
use crate::reflect::RuntimeTypeBox;
use crate::rt;
use crate::wire_format::WireType;
use crate::CodedInputStream;
use crate::ProtobufError;
use crate::ProtobufResult;

/// Runtime type and protobuf type.
pub(crate) struct ProtobufTypeBox {
    runtime: RuntimeTypeBox,
    t: Type,
}

impl ProtobufTypeBox {
    pub(crate) fn new(runtime: RuntimeTypeBox, t: Type) -> ProtobufResult<ProtobufTypeBox> {
        match (t, &runtime) {
            (Type::TYPE_INT32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_INT64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_UINT32, RuntimeTypeBox::U32) => {}
            (Type::TYPE_UINT64, RuntimeTypeBox::U64) => {}
            (Type::TYPE_SINT32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_SINT64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_FIXED32, RuntimeTypeBox::U32) => {}
            (Type::TYPE_FIXED64, RuntimeTypeBox::U64) => {}
            (Type::TYPE_SFIXED32, RuntimeTypeBox::I32) => {}
            (Type::TYPE_SFIXED64, RuntimeTypeBox::I64) => {}
            (Type::TYPE_FLOAT, RuntimeTypeBox::F32) => {}
            (Type::TYPE_DOUBLE, RuntimeTypeBox::F64) => {}
            (Type::TYPE_BOOL, RuntimeTypeBox::Bool) => {}
            (Type::TYPE_STRING, RuntimeTypeBox::String) => {}
            (Type::TYPE_BYTES, RuntimeTypeBox::VecU8) => {}
            (Type::TYPE_MESSAGE, RuntimeTypeBox::Message(..)) => {}
            (Type::TYPE_ENUM, RuntimeTypeBox::Enum(..)) => {}
            (Type::TYPE_GROUP, ..) => return Err(ProtobufError::GroupIsNotImplemented),
            _ => return Err(ProtobufError::IncompatibleProtobufTypeAndRuntimeType),
        }
        Ok(ProtobufTypeBox { runtime, t })
    }

    pub(crate) fn read(
        &self,
        is: &mut CodedInputStream,
        wire_type: WireType,
    ) -> ProtobufResult<ReflectValueBox> {
        if wire_type != WireType::for_type(self.t) {
            return Err(rt::unexpected_wire_type(wire_type));
        }
        Ok(match self.t {
            Type::TYPE_DOUBLE => ReflectValueBox::F64(is.read_double()?),
            Type::TYPE_FLOAT => ReflectValueBox::F32(is.read_float()?),
            Type::TYPE_INT64 => ReflectValueBox::I64(is.read_int64()?),
            Type::TYPE_UINT64 => ReflectValueBox::U64(is.read_uint64()?),
            Type::TYPE_INT32 => ReflectValueBox::I32(is.read_int32()?),
            Type::TYPE_FIXED64 => ReflectValueBox::U64(is.read_fixed64()?),
            Type::TYPE_FIXED32 => ReflectValueBox::U32(is.read_fixed32()?),
            Type::TYPE_BOOL => ReflectValueBox::Bool(is.read_bool()?),
            Type::TYPE_UINT32 => ReflectValueBox::U32(is.read_uint32()?),
            Type::TYPE_SFIXED32 => ReflectValueBox::I32(is.read_sfixed32()?),
            Type::TYPE_SFIXED64 => ReflectValueBox::I64(is.read_sfixed64()?),
            Type::TYPE_SINT32 => ReflectValueBox::I32(is.read_sint32()?),
            Type::TYPE_SINT64 => ReflectValueBox::I64(is.read_sint64()?),
            Type::TYPE_STRING => ReflectValueBox::String(is.read_string()?),
            Type::TYPE_BYTES => ReflectValueBox::Bytes(is.read_bytes()?),
            Type::TYPE_ENUM => match &self.runtime {
                RuntimeTypeBox::Enum(e) => {
                    let v = is.read_enum_value()?;
                    ReflectValueBox::Enum(e.clone(), v)
                }
                _ => unreachable!(),
            },
            Type::TYPE_GROUP => return Err(ProtobufError::GroupIsNotImplemented),
            Type::TYPE_MESSAGE => match &self.runtime {
                RuntimeTypeBox::Message(m) => ReflectValueBox::Message(is.read_message_dyn(m)?),
                _ => unreachable!(),
            },
        })
    }

    pub(crate) fn read_repeated_into(
        &self,
        is: &mut CodedInputStream,
        wire_type: WireType,
        repeated: &mut ReflectRepeatedMut,
    ) -> ProtobufResult<()> {
        if wire_type == WireType::for_type(self.t) {
            let value = self.read(is, wire_type)?;
            repeated.push(value);
            Ok(())
        } else if wire_type == WireType::WireTypeLengthDelimited {
            // TODO: handle repeated packed.
            unimplemented!()
        } else {
            Err(rt::unexpected_wire_type(wire_type))
        }
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(ConfigKey::BurnAfter),
            "sweep.period" => Ok(ConfigKey::SweepPeriod),
            "sweep.time"   => Ok(ConfigKey::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => "burn.after",
            ConfigKey::SweepPeriod => "sweep.period",
            ConfigKey::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut config = BTreeMap::new();
        Self::insert_deeply(&mut config, &ConfigKey::BurnAfter  , "2 weeks".to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepPeriod, "daily"  .to_string());
        Self::insert_deeply(&mut config, &ConfigKey::SweepTime  , "00:00"  .to_string());

        Self::_new(toml::encode(&config))
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().next());
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    fn get<CK: Borrow<ConfigKey>>(key: CK) -> Result<String, CliError> {
        let key    = key.borrow();
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .map(|v| v.to_string())
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = ConfigKey::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set<CK: Borrow<ConfigKey>>(mut self, key: CK, value: String) -> Result<Self, ConfigError> {
        let mut config = match toml::decode::<BTreeMap<String, BTreeMap<String, String>>>(self.toml) {
            Some(decoded) => decoded,
            None          => return Err(ConfigError::new(ConfigErrorKind::Something)),
        };

        Self::insert_deeply(&mut config, key.borrow(), value);

        self.toml = toml::encode(&config);

        Ok(self)
    }

    fn insert_deeply<CK: Borrow<ConfigKey>>(table: &mut BTreeMap<String, BTreeMap<String, String>>, key: CK, value: String) {
        let (first, second) = key.borrow().to_pair();

        let second = second.to_string();

        if table.contains_key(first) {
            table.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            table.insert(first.to_string(), entry);
        }
    }

    pub fn validate<CK: Borrow<ConfigKey>, S: AsRef<str>>(key: CK, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key.borrow() {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}
<commit_msg>[Remedy] Create EditableToml<commit_after>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(ConfigKey::BurnAfter),
            "sweep.period" => Ok(ConfigKey::SweepPeriod),
            "sweep.time"   => Ok(ConfigKey::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => "burn.after",
            ConfigKey::SweepPeriod => "sweep.period",
            ConfigKey::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

type EditableTomlCore = BTreeMap<String, BTreeMap<String, String>>;

struct EditableToml(EditableTomlCore);

impl EditableToml {
    fn from(toml: Toml) -> Result<Self, ConfigError> {
        toml::decode::<EditableTomlCore>(toml)
            .map(|c| EditableToml(c))
            .ok_or(ConfigError::new(ConfigErrorKind::Something))
    }

    fn overwrite<CK: Borrow<ConfigKey>>(&mut self, key: CK, value: String) {
        let &mut EditableToml(ref mut toml) = self;

        let (first, second) = key.borrow().to_pair();
        let second          = second.to_string();

        if toml.contains_key(first) {
            toml.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            toml.insert(first.to_string(), entry);
        }
    }

    fn to_toml(self) -> Toml {
        let EditableToml(core) = self;
        toml::encode(&core)
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut editable = EditableToml(BTreeMap::new());
        editable.overwrite(ConfigKey::BurnAfter  , "2 weeks".to_string());
        editable.overwrite(ConfigKey::SweepPeriod, "daily"  .to_string());
        editable.overwrite(ConfigKey::SweepTime  , "00:00"  .to_string());

        Self::_new(editable.to_toml())
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().next());
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    fn get<CK: Borrow<ConfigKey>>(key: CK) -> Result<String, CliError> {
        let key    = key.borrow();
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .map(|v| v.to_string())
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = ConfigKey::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set<CK: Borrow<ConfigKey>>(mut self, key: CK, value: String) -> Result<Self, ConfigError> {
        let mut editable = try!(EditableToml::from(self.toml));

        editable.overwrite(key.borrow(), value);

        self.toml = editable.to_toml();

        Ok(self)
    }

    pub fn validate<CK: Borrow<ConfigKey>, S: AsRef<str>>(key: CK, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key.borrow() {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}
<|endoftext|>