<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 api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, DeviceIntSize, LayoutPrimitiveInfo};
use api::{LayoutRect, LayoutSize, LayoutVector2D, MAX_BLUR_RADIUS};
use clip::ClipItemKey;
use display_list_flattener::DisplayListFlattener;
use gpu_cache::GpuCacheHandle;
use gpu_types::BoxShadowStretchMode;
use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind};
use render_task::RenderTaskCacheEntryHandle;
use util::RectHelpers;

#[derive(Debug, Clone, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BoxShadowClipSource {
    // Parameters that define the shadow and are constant.
    pub shadow_radius: BorderRadius,
    pub blur_radius: f32,
    pub clip_mode: BoxShadowClipMode,
    pub stretch_mode_x: BoxShadowStretchMode,
    pub stretch_mode_y: BoxShadowStretchMode,

    // The current cache key (in device-pixels), and handles
    // to the cached clip region and blurred texture.
    pub cache_key: Option<(DeviceIntSize, BoxShadowCacheKey)>,
    pub cache_handle: Option<RenderTaskCacheEntryHandle>,
    pub clip_data_handle: GpuCacheHandle,

    // Local-space size of the required render task size.
    pub shadow_rect_alloc_size: LayoutSize,

    // Local-space size of the required render task size without any downscaling
    // applied. This is needed to stretch the shadow properly.
    pub original_alloc_size: LayoutSize,

    // The minimal shadow rect for the parameters above,
    // used when drawing the shadow rect to be blurred.
    pub minimal_shadow_rect: LayoutRect,

    // Local space rect for the shadow to be drawn or
    // stretched in the shadow primitive.
    pub prim_shadow_rect: LayoutRect,
}

// The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels.
pub const BLUR_SAMPLE_SCALE: f32 = 3.0;

// A cache key that uniquely identifies a minimally sized
// and blurred box-shadow rect that can be stored in the
// texture cache and applied to clip-masks.
#[derive(Debug, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BoxShadowCacheKey {
    pub blur_radius_dp: i32,
    pub clip_mode: BoxShadowClipMode,
    // NOTE(emilio): Only the original allocation size needs to be in the cache
    // key, since the actual size is derived from that.
    pub original_alloc_size: DeviceIntSize,
    pub br_top_left: DeviceIntSize,
    pub br_top_right: DeviceIntSize,
    pub br_bottom_right: DeviceIntSize,
    pub br_bottom_left: DeviceIntSize,
}

impl<'a> DisplayListFlattener<'a> {
    pub fn add_box_shadow(
        &mut self,
        clip_and_scroll: ScrollNodeAndClipChain,
        prim_info: &LayoutPrimitiveInfo,
        box_offset: &LayoutVector2D,
        color: ColorF,
        mut blur_radius: f32,
        spread_radius: f32,
        border_radius: BorderRadius,
        clip_mode: BoxShadowClipMode,
    ) {
        if color.a == 0.0 {
            return;
        }

        // Inset shadows get smaller as spread radius increases.
        let (spread_amount, prim_clip_mode) = match clip_mode {
            BoxShadowClipMode::Outset => (spread_radius, ClipMode::ClipOut),
            BoxShadowClipMode::Inset => (-spread_radius, ClipMode::Clip),
        };

        // Ensure the blur radius is somewhat sensible.
        blur_radius = f32::min(blur_radius, MAX_BLUR_RADIUS);

        // Adjust the border radius of the box shadow per CSS-spec.
        let shadow_radius = adjust_border_radius_for_box_shadow(border_radius, spread_amount);

        // Apply parameters that affect where the shadow rect
        // exists in the local space of the primitive.
        let shadow_rect = prim_info
            .rect
            .translate(box_offset)
            .inflate(spread_amount, spread_amount);

        // If blur radius is zero, we can use a fast path with
        // no blur applied.
        if blur_radius == 0.0 {
            // Trivial reject of box-shadows that are not visible.
            if box_offset.x == 0.0 && box_offset.y == 0.0 && spread_amount == 0.0 {
                return;
            }

            let mut clips = Vec::with_capacity(2);
            let (final_prim_rect, clip_radius) = match clip_mode {
                BoxShadowClipMode::Outset => {
                    if !shadow_rect.is_well_formed_and_nonempty() {
                        return;
                    }

                    // TODO(gw): Add a fast path for ClipOut + zero border radius!
                    clips.push(
                        (
                            prim_info.rect.origin,
                            ClipItemKey::rounded_rect(
                                prim_info.rect.size,
                                border_radius,
                                ClipMode::ClipOut,
                            ),
                        )
                    );

                    (shadow_rect, shadow_radius)
                }
                BoxShadowClipMode::Inset => {
                    if shadow_rect.is_well_formed_and_nonempty() {
                        clips.push(
                            (
                                shadow_rect.origin,
                                ClipItemKey::rounded_rect(
                                    shadow_rect.size,
                                    shadow_radius,
                                    ClipMode::ClipOut,
                                ),
                            )
                        );
                    }

                    (prim_info.rect, border_radius)
                }
            };

            clips.push(
                (
                    final_prim_rect.origin,
                    ClipItemKey::rounded_rect(
                        final_prim_rect.size,
                        clip_radius,
                        ClipMode::Clip,
                    ),
                )
            );

            self.add_primitive(
                clip_and_scroll,
                &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
                clips,
                PrimitiveKeyKind::Rectangle {
                    color: color.into(),
                },
            );
        } else {
            // Normal path for box-shadows with a valid blur radius.
            let blur_offset = (BLUR_SAMPLE_SCALE * blur_radius).ceil();
            let mut extra_clips = vec![];

            // Add a normal clip mask to clip out the contents
            // of the surrounding primitive.
            extra_clips.push(
                (
                    prim_info.rect.origin,
                    ClipItemKey::rounded_rect(
                        prim_info.rect.size,
                        border_radius,
                        prim_clip_mode,
                    ),
                )
            );

            // Get the local rect of where the shadow will be drawn,
            // expanded to include room for the blurred region.
            let dest_rect = shadow_rect.inflate(blur_offset, blur_offset);

            // Draw the box-shadow as a solid rect, using a box-shadow
            // clip mask item.
            let prim = PrimitiveKeyKind::Rectangle {
                color: color.into(),
            };

            // Create the box-shadow clip item.
            let shadow_clip_source = ClipItemKey::box_shadow(
                shadow_rect,
                shadow_radius,
                dest_rect.translate(&LayoutVector2D::new(-prim_info.rect.origin.x, -prim_info.rect.origin.y)),
                blur_radius,
                clip_mode,
            );

            let prim_info = match clip_mode {
                BoxShadowClipMode::Outset => {
                    // Certain spread-radii make the shadow invalid.
                    if !shadow_rect.is_well_formed_and_nonempty() {
                        return;
                    }

                    // Add the box-shadow clip source.
                    extra_clips.push(
                        (
                            prim_info.rect.origin,
                            shadow_clip_source,
                        ),
                    );

                    // Outset shadows are expanded by the shadow
                    // region from the original primitive.
                    LayoutPrimitiveInfo::with_clip_rect(dest_rect, prim_info.clip_rect)
                }
                BoxShadowClipMode::Inset => {
                    // If the inner shadow rect contains the prim
                    // rect, no pixels will be shadowed.
                    if border_radius.is_zero() && shadow_rect
                        .inflate(-blur_radius, -blur_radius)
                        .contains_rect(&prim_info.rect)
                    {
                        return;
                    }

                    // Inset shadows are still visible, even if the
                    // inset shadow rect becomes invalid (they will
                    // just look like a solid rectangle).
                    if shadow_rect.is_well_formed_and_nonempty() {
                        extra_clips.push(
                            (
                                prim_info.rect.origin,
                                shadow_clip_source,
                            ),
                        );
                    }

                    // Inset shadows draw inside the original primitive.
                    prim_info.clone()
                }
            };

            self.add_primitive(
                clip_and_scroll,
                &prim_info,
                extra_clips,
                prim,
            );
        }
    }
}

fn adjust_border_radius_for_box_shadow(radius: BorderRadius, spread_amount: f32) -> BorderRadius {
    BorderRadius {
        top_left: adjust_corner_for_box_shadow(radius.top_left, spread_amount),
        top_right: adjust_corner_for_box_shadow(radius.top_right, spread_amount),
        bottom_right: adjust_corner_for_box_shadow(radius.bottom_right, spread_amount),
        bottom_left: adjust_corner_for_box_shadow(radius.bottom_left, spread_amount),
    }
}

fn adjust_corner_for_box_shadow(corner: LayoutSize, spread_amount: f32) -> LayoutSize {
    LayoutSize::new(
        adjust_radius_for_box_shadow(corner.width, spread_amount),
        adjust_radius_for_box_shadow(corner.height, spread_amount),
    )
}

fn adjust_radius_for_box_shadow(border_radius: f32, spread_amount: f32) -> f32 {
    if border_radius > 0.0 {
        (border_radius + spread_amount).max(0.0)
    } else {
        0.0
    }
}
<commit_msg>Backed out changeset 9a347a546d90 (bug 1522351) for wrench bustage in reftests/boxshadow/no-stretch.png CLOSED TREE<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 api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, DeviceIntSize, LayoutPrimitiveInfo};
use api::{LayoutRect, LayoutSize, LayoutVector2D, MAX_BLUR_RADIUS};
use clip::ClipItemKey;
use display_list_flattener::DisplayListFlattener;
use gpu_cache::GpuCacheHandle;
use gpu_types::BoxShadowStretchMode;
use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind};
use render_task::RenderTaskCacheEntryHandle;
use util::RectHelpers;

#[derive(Debug, Clone, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BoxShadowClipSource {
    // Parameters that define the shadow and are constant.
    pub shadow_radius: BorderRadius,
    pub blur_radius: f32,
    pub clip_mode: BoxShadowClipMode,
    pub stretch_mode_x: BoxShadowStretchMode,
    pub stretch_mode_y: BoxShadowStretchMode,

    // The current cache key (in device-pixels), and handles
    // to the cached clip region and blurred texture.
    pub cache_key: Option<(DeviceIntSize, BoxShadowCacheKey)>,
    pub cache_handle: Option<RenderTaskCacheEntryHandle>,
    pub clip_data_handle: GpuCacheHandle,

    // Local-space size of the required render task size.
    pub shadow_rect_alloc_size: LayoutSize,

    // Local-space size of the required render task size without any downscaling
    // applied. This is needed to stretch the shadow properly.
    pub original_alloc_size: LayoutSize,

    // The minimal shadow rect for the parameters above,
    // used when drawing the shadow rect to be blurred.
    pub minimal_shadow_rect: LayoutRect,

    // Local space rect for the shadow to be drawn or
    // stretched in the shadow primitive.
    pub prim_shadow_rect: LayoutRect,
}

// The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels.
pub const BLUR_SAMPLE_SCALE: f32 = 3.0;

// A cache key that uniquely identifies a minimally sized
// and blurred box-shadow rect that can be stored in the
// texture cache and applied to clip-masks.
#[derive(Debug, Clone, Eq, Hash, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BoxShadowCacheKey {
    pub blur_radius_dp: i32,
    pub clip_mode: BoxShadowClipMode,
    // NOTE(emilio): Only the original allocation size needs to be in the cache
    // key, since the actual size is derived from that.
    pub original_alloc_size: DeviceIntSize,
    pub br_top_left: DeviceIntSize,
    pub br_top_right: DeviceIntSize,
    pub br_bottom_right: DeviceIntSize,
    pub br_bottom_left: DeviceIntSize,
}

impl<'a> DisplayListFlattener<'a> {
    pub fn add_box_shadow(
        &mut self,
        clip_and_scroll: ScrollNodeAndClipChain,
        prim_info: &LayoutPrimitiveInfo,
        box_offset: &LayoutVector2D,
        color: ColorF,
        mut blur_radius: f32,
        spread_radius: f32,
        border_radius: BorderRadius,
        clip_mode: BoxShadowClipMode,
    ) {
        if color.a == 0.0 {
            return;
        }

        // Inset shadows get smaller as spread radius increases.
        let (spread_amount, prim_clip_mode) = match clip_mode {
            BoxShadowClipMode::Outset => (spread_radius, ClipMode::ClipOut),
            BoxShadowClipMode::Inset => (-spread_radius, ClipMode::Clip),
        };

        // Ensure the blur radius is somewhat sensible.
        blur_radius = f32::min(blur_radius, MAX_BLUR_RADIUS);

        // Adjust the border radius of the box shadow per CSS-spec.
        let shadow_radius = adjust_border_radius_for_box_shadow(border_radius, spread_amount);

        // Apply parameters that affect where the shadow rect
        // exists in the local space of the primitive.
        let shadow_rect = prim_info
            .rect
            .translate(box_offset)
            .inflate(spread_amount, spread_amount);

        // If blur radius is zero, we can use a fast path with
        // no blur applied.
        if blur_radius == 0.0 {
            // Trivial reject of box-shadows that are not visible.
            if box_offset.x == 0.0 && box_offset.y == 0.0 && spread_amount == 0.0 {
                return;
            }

            let mut clips = Vec::with_capacity(2);
            let (final_prim_rect, clip_radius) = match clip_mode {
                BoxShadowClipMode::Outset => {
                    if !shadow_rect.is_well_formed_and_nonempty() {
                        return;
                    }

                    // TODO(gw): Add a fast path for ClipOut + zero border radius!
                    clips.push(
                        (
                            prim_info.rect.origin,
                            ClipItemKey::rounded_rect(
                                prim_info.rect.size,
                                border_radius,
                                ClipMode::ClipOut,
                            ),
                        )
                    );

                    (shadow_rect, shadow_radius)
                }
                BoxShadowClipMode::Inset => {
                    if shadow_rect.is_well_formed_and_nonempty() {
                        clips.push(
                            (
                                shadow_rect.origin,
                                ClipItemKey::rounded_rect(
                                    shadow_rect.size,
                                    shadow_radius,
                                    ClipMode::ClipOut,
                                ),
                            )
                        );
                    }

                    (prim_info.rect, border_radius)
                }
            };

            clips.push(
                (
                    final_prim_rect.origin,
                    ClipItemKey::rounded_rect(
                        final_prim_rect.size,
                        clip_radius,
                        ClipMode::Clip,
                    ),
                )
            );

            self.add_primitive(
                clip_and_scroll,
                &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
                clips,
                PrimitiveKeyKind::Rectangle {
                    color: color.into(),
                },
            );
        } else {
            // Normal path for box-shadows with a valid blur radius.
            let blur_offset = BLUR_SAMPLE_SCALE * blur_radius;
            let mut extra_clips = vec![];

            // Add a normal clip mask to clip out the contents
            // of the surrounding primitive.
            extra_clips.push(
                (
                    prim_info.rect.origin,
                    ClipItemKey::rounded_rect(
                        prim_info.rect.size,
                        border_radius,
                        prim_clip_mode,
                    ),
                )
            );

            // Get the local rect of where the shadow will be drawn,
            // expanded to include room for the blurred region.
            let dest_rect = shadow_rect.inflate(blur_offset, blur_offset);

            // Draw the box-shadow as a solid rect, using a box-shadow
            // clip mask item.
            let prim = PrimitiveKeyKind::Rectangle {
                color: color.into(),
            };

            // Create the box-shadow clip item.
            let shadow_clip_source = ClipItemKey::box_shadow(
                shadow_rect,
                shadow_radius,
                dest_rect.translate(&LayoutVector2D::new(-prim_info.rect.origin.x, -prim_info.rect.origin.y)),
                blur_radius,
                clip_mode,
            );

            let prim_info = match clip_mode {
                BoxShadowClipMode::Outset => {
                    // Certain spread-radii make the shadow invalid.
                    if !shadow_rect.is_well_formed_and_nonempty() {
                        return;
                    }

                    // Add the box-shadow clip source.
                    extra_clips.push(
                        (
                            prim_info.rect.origin,
                            shadow_clip_source,
                        ),
                    );

                    // Outset shadows are expanded by the shadow
                    // region from the original primitive.
                    LayoutPrimitiveInfo::with_clip_rect(dest_rect, prim_info.clip_rect)
                }
                BoxShadowClipMode::Inset => {
                    // If the inner shadow rect contains the prim
                    // rect, no pixels will be shadowed.
                    if border_radius.is_zero() && shadow_rect
                        .inflate(-blur_radius, -blur_radius)
                        .contains_rect(&prim_info.rect)
                    {
                        return;
                    }

                    // Inset shadows are still visible, even if the
                    // inset shadow rect becomes invalid (they will
                    // just look like a solid rectangle).
                    if shadow_rect.is_well_formed_and_nonempty() {
                        extra_clips.push(
                            (
                                prim_info.rect.origin,
                                shadow_clip_source,
                            ),
                        );
                    }

                    // Inset shadows draw inside the original primitive.
                    prim_info.clone()
                }
            };

            self.add_primitive(
                clip_and_scroll,
                &prim_info,
                extra_clips,
                prim,
            );
        }
    }
}

fn adjust_border_radius_for_box_shadow(radius: BorderRadius, spread_amount: f32) -> BorderRadius {
    BorderRadius {
        top_left: adjust_corner_for_box_shadow(radius.top_left, spread_amount),
        top_right: adjust_corner_for_box_shadow(radius.top_right, spread_amount),
        bottom_right: adjust_corner_for_box_shadow(radius.bottom_right, spread_amount),
        bottom_left: adjust_corner_for_box_shadow(radius.bottom_left, spread_amount),
    }
}

fn adjust_corner_for_box_shadow(corner: LayoutSize, spread_amount: f32) -> LayoutSize {
    LayoutSize::new(
        adjust_radius_for_box_shadow(corner.width, spread_amount),
        adjust_radius_for_box_shadow(corner.height, spread_amount),
    )
}

fn adjust_radius_for_box_shadow(border_radius: f32, spread_amount: f32) -> f32 {
    if border_radius > 0.0 {
        (border_radius + spread_amount).max(0.0)
    } else {
        0.0
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

#[derive(PartialEq, PartialOrd)]
pub struct Point {
    pub x : f64,
    pub y : f64,
}

pub struct Entry {
    pub position: Point,
    pub data: String,
}

pub type Id = i64;

pub struct Database {
    data: HashMap<Id, Entry>,
    last_id: Id,
}

fn distance(a: &Point, b: &Point) -> f64 {
    return distance_sq(a, b).sqrt();
}

fn distance_sq(a: &Point, b: &Point) -> f64 {
    return (a.x-b.x).powf(2.) + (a.y-b.y).powf(2.);
}

impl Database {
    pub fn insert(&mut self, e: Entry) {
        self.last_id += 1;
        self.data.insert(self.last_id, e);
    }

    pub fn new() -> Database {
        Database {
            data: HashMap::new(),
            last_id: 0
        }
    }

    pub fn in_radius_from(&self, from: Point, radius: f64) -> Vec<Id> {
        let radius_sq = radius.powf(2.);
        let mut items = Vec::new();
        for (id, entity) in self.data.iter() {
            if distance_sq(&from, &entity.position) < radius_sq {
                items.push(id.clone());
            }
        }
        return items;
    }

    pub fn distance_between(&self, a: &Id, b: &Id) -> Option<f64> {
        let ma = self.data.get(a);
        let mb = self.data.get(b);

        match (ma,mb) {
            (Some(a), Some (b)) => Some(distance(&a.position, &b.position)),
            _ => None
        }
    }
}
<commit_msg>Expressed distance_between as a lift of a pure function<commit_after>use std::collections::HashMap;

#[derive(PartialEq, PartialOrd)]
pub struct Point {
    pub x : f64,
    pub y : f64,
}

pub struct Entry {
    pub position: Point,
    pub data: String,
}

pub type Id = i64;

pub struct Database {
    data: HashMap<Id, Entry>,
    last_id: Id,
}

fn distance(a: &Point, b: &Point) -> f64 {
    return distance_sq(a, b).sqrt();
}

fn distance_sq(a: &Point, b: &Point) -> f64 {
    return (a.x-b.x).powf(2.) + (a.y-b.y).powf(2.);
}

fn distance_between_internal(a: &Entry, b: &Entry) -> f64 {
    distance(&a.position, &b.position);
}

impl Database {
    pub fn insert(&mut self, e: Entry) {
        self.last_id += 1;
        self.data.insert(self.last_id, e);
    }

    pub fn new() -> Database {
        Database {
            data: HashMap::new(),
            last_id: 0
        }
    }

    pub fn in_radius_from(&self, from: Point, radius: f64) -> Vec<Id> {
        let radius_sq = radius.powf(2.);
        let mut items = Vec::new();
        for (id, entity) in self.data.iter() {
            if distance_sq(&from, &entity.position) < radius_sq {
                items.push(id.clone());
            }
        }
        return items;
    }

    fn liftFromIds2<T>(&self, f: Fn(&Entry, &Entry) -> T) -> Fn(&Id, &Id) -> Option<T> {
        |a: &Id, b: &Id| {
            let ma = self.data.get(a);
            let mb = self.data.get(b);

            match (ma,mb) {
                (Some(a), Some (b)) => Some(f(&a, &b)),
                _ => None
            }
        }
    }

    pub fn distance_between(&self, a: &Id, b: &Id) -> Option<f64> {
        liftFromIds2(distance_between_internal)(a,b);
    }
}
<|endoftext|>


<commit_before>//! Collect definitions for `Residue` and `SheetConf` objects
//! into a `DataBase` which can be read from or saved to disk.

use coord::{Coord, Translate};
use describe::{describe_list_short, describe_list, Describe};
use iterator::AtomIterItem;
use surface;
use system::{Component, Residue};
use volume;

use serde_json;
use std::fmt::Write;
use std::io;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::fs::File;
use std::result;

#[derive(Copy, Clone, Debug)]
pub enum DataBaseError {
    BadPath,
}

#[macro_export]
/// Macro to wrap every object constructor into an enum with desired traits.
///
/// The traits are those important for the creation and display of system components.
/// The enum is used to hold created objects of different types in one container,
/// sharing one interface.
///
/// Implements `Describe`, `Component` and `Translate` for the enum. Also sets up
/// some getter functions directly to the object data.
///
/// # Requires
/// Wrapped objects have to implement the above traits and `Clone`, `Debug`,
/// `Deserialize` and `Serialize` (the last two from `serde`).
///
/// # Examples
/// Create two objects and let the macro create the wrapper and implement the traits for it.
///
/// ```
/// # #[macro_use] extern crate grafen;
/// # extern crate serde_json;
/// # #[macro_use] extern crate serde_derive;
/// # use grafen::coord::{Coord, Translate};
/// # use grafen::describe::Describe;
/// # use grafen::iterator::{AtomIterator, AtomIterItem};
/// # use grafen::system::{Component, Residue};
/// #
/// #[derive(Clone, Debug, Deserialize, Serialize)]
/// pub struct StructOne {
///     origin: Coord,
///     residue: Option<Residue>,
///     coords: Vec<Coord>
/// }
///
/// #[derive(Clone, Debug, Deserialize, Serialize)]
/// pub struct StructTwo {
///     origin: Coord,
///     residue: Option<Residue>,
///     coords: Vec<Coord>
/// }
///
/// // Not shown: implement required traits
/// # impl StructOne { fn calc_box_size(&self) -> Coord { Coord::default() } }
/// # impl StructTwo { fn calc_box_size(&self) -> Coord { Coord::default() } }
/// # impl Describe for StructOne {
/// #     fn describe(&self) -> String { "StructOne".to_string() }
/// #     fn describe_short(&self) -> String { self.describe() }
/// # }
/// # impl Describe for StructTwo {
/// #     fn describe(&self) -> String { "StructTwo".to_string() }
/// #     fn describe_short(&self) -> String { self.describe() }
/// # }
/// # impl_component![StructOne, StructTwo];
/// # impl_translate![StructOne, StructTwo];
///
/// // Construct the wrapping enum container
/// create_entry_wrapper![
///     Wrapper, // enum identifier
///     (StructOne => One), // Wrapper::One(StructOne)
///     (StructTwo => Two)  // Wrapper::Two(StructTwo)
/// ];
///
/// #
/// # fn main() {
/// let objects = vec![
///     Wrapper::One(StructOne {
///         origin: Coord::default(),
///         residue: None,
///         coords: vec![]
///     }),
///     Wrapper::Two(StructTwo {
///         origin: Coord::default(),
///         residue: None,
///         coords: vec![]
///     })
/// ];
///
/// assert_eq!("StructOne", &objects[0].describe());
/// assert_eq!(None, objects[0].iter_atoms().next());
///
/// assert_eq!("StructTwo", &objects[1].describe());
/// assert_eq!(None, objects[1].iter_atoms().next());
/// # }
/// ```
macro_rules! create_entry_wrapper {
    (
        $name:ident, // enum Identifier
        $( ($class:path => $entry:ident) ),+ // Identifier::Entry(Class)
    ) => {
        #[derive(Clone, Debug, Deserialize, Serialize)]
        /// Wrapper for accessing a shared interface from different components constructors.
        pub enum $name {
            $(
                $entry($class),
            )*
        }

        /// Getter function of linked data.
        impl<'a> $name {
            /// Get a reference to the coordinates of the component.
            pub fn get_coords(&'a self) -> &[Coord] {
                match *self {
                    $(
                        $name::$entry(ref object) => &object.coords,
                    )*
                }
            }

            /// Get a mutable reference to the coordinates of the component.
            pub fn get_coords_mut(&'a mut self) -> &mut Vec<Coord> {
                match *self {
                    $(
                        $name::$entry(ref mut object) => &mut object.coords,
                    )*
                }
            }

            /// Get a reference to the component's optional `Residue`.
            pub fn get_residue(&'a self) -> &'a Option<Residue> {
                match *self {
                    $(
                        $name::$entry(ref object) => &object.residue,
                    )*
                }
            }
        }

        impl Describe for $name {
            fn describe(&self) -> String {
                match *self {
                    $(
                        $name::$entry(ref object) => object.describe(),
                    )*
                }
            }

            fn describe_short(&self) -> String {
                match *self {
                    $(
                        $name::$entry(ref object) => object.describe_short(),
                    )*
                }
            }
        }

        impl<'a> Component<'a> for $name {
            fn box_size(&self) -> Coord {
                match *self {
                    $(
                        $name::$entry(ref object) => object.box_size(),
                    )*
                }
            }

            fn iter_atoms(&'a self) -> AtomIterItem {
                match *self {
                    $(
                        $name::$entry(ref object) => object.iter_atoms(),
                    )*
                }
            }

            fn num_atoms(&self) -> u64 {
                match *self {
                    $(
                        $name::$entry(ref object) => object.num_atoms(),
                    )*
                }
            }
        }

        impl Translate for $name {
            fn translate(self, coord: Coord) -> Self {
                match self {
                    $(
                        $name::$entry(object) => $name::$entry(object.translate(coord)),
                    )*
                }
            }

            fn translate_in_place(&mut self, coord: Coord) {
                match *self {
                    $(
                        $name::$entry(ref mut object)
                            => { object.translate_in_place(coord); }
                    )*
                }
            }
        }
    }
}

// Our wrapper for object constructors is `ComponentEntry`. Use the macro to construct it.
create_entry_wrapper![
    ComponentEntry,
    (volume::Cuboid => VolumeCuboid),
    (volume::Cylinder => VolumeCylinder),
    (surface::Sheet => SurfaceSheet),
    (surface::Cylinder => SurfaceCylinder)
];

#[derive(Clone, Debug, Deserialize, Serialize)]
/// A collection of residues and substrate configurations
/// which can be saved to and read from disk.
pub struct DataBase {
    #[serde(skip)]
    /// A path to the `DataBase` location on the hard drive.
    pub path: Option<PathBuf>,

    #[serde(rename = "residue_definitions", default = "Vec::new")]
    /// Definitions of `Residue` objects.
    pub residue_defs: Vec<Residue>,

    #[serde(rename = "component_definitions", default = "Vec::new")]
    /// New component constructors.
    pub component_defs: Vec<ComponentEntry>,
}

impl DataBase {
    /// Construct an empty `DataBase`.
    pub fn new() -> DataBase {
        DataBase {
            path: None,
            residue_defs: vec![],
            component_defs: vec![],
        }
    }

    /// Get the database path enclosed in single quotes if it exists,
    /// otherwise the unenclosed string "None".
    pub fn get_path_pretty(&self) -> String {
        self.path.as_ref()
            .map(|path| path.to_string_lossy().to_owned())
            .map(|path| format!("'{}'", path))
            .unwrap_or("None".to_string())
    }

    /// Set a new path for the `DataBase`. The input path is asserted to
    /// be a file and the extension is set to 'json'.
    pub fn set_path<T>(&mut self, new_path: &T) -> Result<(), DataBaseError>
            where T: ?Sized + AsRef<OsStr> {
        let mut path = PathBuf::from(new_path);

        if path.file_stem().is_some() {
            path.set_extension("json");
            self.path = Some(path);
            Ok(())
        } else {
            Err(DataBaseError::BadPath)
        }
    }

    /// Parse a reader for a JSON formatted `DataBase`.
    ///
    /// This and the `to_writer` method are defined to enable a unit
    /// test which ensures that the behaviour for reading and writing
    /// a `DataBase` is consistent.
    fn from_reader<R: io::Read>(reader: R) -> Result<DataBase, io::Error> {
        serde_json::from_reader(reader).map_err(|e| io::Error::from(e))
    }

    /// Write a `DataBase` as a JSON formatted object to an input writer.
    fn to_writer<W: io::Write>(&self, writer: &mut W) -> result::Result<(), io::Error> {
        serde_json::to_writer_pretty(writer, self).map_err(|e| io::Error::from(e))
    }
}

impl Describe for DataBase {
    fn describe(&self) -> String {
        let mut description = String::new();
        const ERR: &'static str = "Could not construct a string";

        writeln!(description, "Database path: {}\n", self.get_path_pretty()).expect(ERR);
        writeln!(description, "{}", describe_list_short("Component definitions", &self.component_defs)).expect(ERR);
        writeln!(description, "{}", describe_list("Residue definitions", &self.residue_defs)).expect(ERR);

        description
    }

    fn describe_short(&self) -> String {
        self.describe()
    }
}

/// Read a `DataBase` from a JSON formatted file.
/// The owned path is set to the input path.
pub fn read_database(from_path: &str) -> Result<DataBase, io::Error> {
    let path = Path::new(from_path);
    let buffer = File::open(&path)?;

    let mut database = DataBase::from_reader(buffer)?;
    database.path = Some(PathBuf::from(&from_path));

    Ok(database)
}

/// Write a `DataBase` as a JSON formatted file.
/// The function writes to that owned by the object.
pub fn write_database(database: &DataBase) -> Result<(), io::Error> {
    if let Some(ref path) = database.path {
        let mut buffer = File::create(&path)?;
        database.to_writer(&mut buffer)?;

        return Ok(());
    }

    Err(io::Error::new(
        io::ErrorKind::Other,
        "No path was set when trying to write the database to disk")
    )
}

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

    #[test]
    fn serialize_and_deserialize_residue_entry() {
        let base = Residue {
            code: "RES".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(3.0, 4.0, 5.0) },
            ]
        };

        let serialized = serde_json::to_string(&base).unwrap();
        let deserialized: Residue = serde_json::from_str(&serialized).unwrap();

        assert_eq!(base, deserialized);
    }

    #[test]
    fn database_by_default_sets_empty_vectors_if_not_available() {
        let database: DataBase = serde_json::from_str("{}").unwrap();
        assert!(database.residue_defs.is_empty());
        assert!(database.component_defs.is_empty());
    }

    #[test]
    fn read_and_write_database() {
        let base = Residue {
            code: "RES".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(3.0, 4.0, 5.0) },
            ]
        };

        let database = DataBase {
            path: Some(PathBuf::from("This/will/be/removed")),
            residue_defs: vec![base.clone()],
            component_defs: vec![],
        };

        let mut serialized: Vec<u8> = Vec::new();
        database.to_writer(&mut serialized).unwrap();
        let deserialized = DataBase::from_reader(serialized.as_slice()).unwrap();

        assert_eq!(None, deserialized.path);
        assert_eq!(database.residue_defs, deserialized.residue_defs);
    }

    #[test]
    fn set_database_path() {
        let mut database = DataBase::new();
        assert!(database.set_path("test").is_ok());
        assert_eq!("test.json", database.path.unwrap().to_str().unwrap());
    }

    #[test]
    fn set_database_to_empty_path_is_error() {
        let mut database = DataBase::new();
        database.path = Some(PathBuf::from("unchanged.json"));
        assert!(database.set_path("").is_err());
        assert_eq!("unchanged.json", database.path.unwrap().to_str().unwrap());
    }

    #[cfg(unix)]
    #[test]
    fn get_database_path() {
        let mut database = DataBase::new();
        assert_eq!("None", &database.get_path_pretty());

        database.set_path("/a/file.json").unwrap();
        assert_eq!("'/a/file.json'", &database.get_path_pretty());
    }
}
<commit_msg>Implement `From` for `ComponentEntry` macro<commit_after>//! Collect definitions for `Residue` and `SheetConf` objects
//! into a `DataBase` which can be read from or saved to disk.

use coord::{Coord, Translate};
use describe::{describe_list_short, describe_list, Describe};
use iterator::AtomIterItem;
use surface;
use system::{Component, Residue};
use volume;

use serde_json;
use std::ffi::OsStr;
use std::fmt::Write;
use std::convert::From;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::result;

#[derive(Copy, Clone, Debug)]
pub enum DataBaseError {
    BadPath,
}

#[macro_export]
/// Macro to wrap every object constructor into an enum with desired traits.
///
/// The traits are those important for the creation and display of system components.
/// The enum is used to hold created objects of different types in one container,
/// sharing one interface.
///
/// Implements `Describe`, `Component` and `Translate` for the enum. Also sets up
/// some getter functions directly to the object data.
///
/// # Requires
/// Wrapped objects have to implement the above traits and `Clone`, `Debug`,
/// `Deserialize` and `Serialize` (the last two from `serde`).
///
/// # Examples
/// Create two objects and let the macro create the wrapper and implement the traits for it.
///
/// ```
/// # #[macro_use] extern crate grafen;
/// # extern crate serde_json;
/// # #[macro_use] extern crate serde_derive;
/// # use grafen::coord::{Coord, Translate};
/// # use grafen::describe::Describe;
/// # use grafen::iterator::{AtomIterator, AtomIterItem};
/// # use grafen::system::{Component, Residue};
/// #
/// #[derive(Clone, Debug, Deserialize, Serialize)]
/// pub struct StructOne {
///     origin: Coord,
///     residue: Option<Residue>,
///     coords: Vec<Coord>
/// }
///
/// #[derive(Clone, Debug, Deserialize, Serialize)]
/// pub struct StructTwo {
///     origin: Coord,
///     residue: Option<Residue>,
///     coords: Vec<Coord>
/// }
///
/// // Not shown: implement required traits
/// # impl StructOne { fn calc_box_size(&self) -> Coord { Coord::default() } }
/// # impl StructTwo { fn calc_box_size(&self) -> Coord { Coord::default() } }
/// # impl Describe for StructOne {
/// #     fn describe(&self) -> String { "StructOne".to_string() }
/// #     fn describe_short(&self) -> String { self.describe() }
/// # }
/// # impl Describe for StructTwo {
/// #     fn describe(&self) -> String { "StructTwo".to_string() }
/// #     fn describe_short(&self) -> String { self.describe() }
/// # }
/// # impl_component![StructOne, StructTwo];
/// # impl_translate![StructOne, StructTwo];
///
/// // Construct the wrapping enum container
/// create_entry_wrapper![
///     Wrapper, // enum identifier
///     (StructOne => One), // Wrapper::One(StructOne)
///     (StructTwo => Two)  // Wrapper::Two(StructTwo)
/// ];
///
/// #
/// # fn main() {
/// let objects = vec![
///     Wrapper::One(StructOne {
///         origin: Coord::default(),
///         residue: None,
///         coords: vec![]
///     }),
///     Wrapper::Two(StructTwo {
///         origin: Coord::default(),
///         residue: None,
///         coords: vec![]
///     })
/// ];
///
/// assert_eq!("StructOne", &objects[0].describe());
/// assert_eq!(None, objects[0].iter_atoms().next());
///
/// assert_eq!("StructTwo", &objects[1].describe());
/// assert_eq!(None, objects[1].iter_atoms().next());
/// # }
/// ```
macro_rules! create_entry_wrapper {
    (
        $name:ident, // enum Identifier
        $( ($class:path => $entry:ident) ),+ // Identifier::Entry(Class)
    ) => {
        #[derive(Clone, Debug, Deserialize, Serialize)]
        /// Wrapper for accessing a shared interface from different components constructors.
        pub enum $name {
            $(
                $entry($class),
            )*
        }

        /// Getter function of linked data.
        impl<'a> $name {
            /// Get a reference to the coordinates of the component.
            pub fn get_coords(&'a self) -> &[Coord] {
                match *self {
                    $(
                        $name::$entry(ref object) => &object.coords,
                    )*
                }
            }

            /// Get a mutable reference to the coordinates of the component.
            pub fn get_coords_mut(&'a mut self) -> &mut Vec<Coord> {
                match *self {
                    $(
                        $name::$entry(ref mut object) => &mut object.coords,
                    )*
                }
            }

            /// Get a reference to the component's optional `Residue`.
            pub fn get_residue(&'a self) -> &'a Option<Residue> {
                match *self {
                    $(
                        $name::$entry(ref object) => &object.residue,
                    )*
                }
            }
        }

        impl Describe for $name {
            fn describe(&self) -> String {
                match *self {
                    $(
                        $name::$entry(ref object) => object.describe(),
                    )*
                }
            }

            fn describe_short(&self) -> String {
                match *self {
                    $(
                        $name::$entry(ref object) => object.describe_short(),
                    )*
                }
            }
        }

        impl<'a> Component<'a> for $name {
            fn box_size(&self) -> Coord {
                match *self {
                    $(
                        $name::$entry(ref object) => object.box_size(),
                    )*
                }
            }

            fn iter_atoms(&'a self) -> AtomIterItem {
                match *self {
                    $(
                        $name::$entry(ref object) => object.iter_atoms(),
                    )*
                }
            }

            fn num_atoms(&self) -> u64 {
                match *self {
                    $(
                        $name::$entry(ref object) => object.num_atoms(),
                    )*
                }
            }
        }

        impl Translate for $name {
            fn translate(self, coord: Coord) -> Self {
                match self {
                    $(
                        $name::$entry(object) => $name::$entry(object.translate(coord)),
                    )*
                }
            }

            fn translate_in_place(&mut self, coord: Coord) {
                match *self {
                    $(
                        $name::$entry(ref mut object)
                            => { object.translate_in_place(coord); }
                    )*
                }
            }
        }

        $(
            impl From<$class> for $name {
                fn from(object: $class) -> $name {
                    $name::$entry(object)
                }
            }
        )*
    }
}

// Our wrapper for object constructors is `ComponentEntry`. Use the macro to construct it.
create_entry_wrapper![
    ComponentEntry,
    (volume::Cuboid => VolumeCuboid),
    (volume::Cylinder => VolumeCylinder),
    (surface::Sheet => SurfaceSheet),
    (surface::Cylinder => SurfaceCylinder)
];

#[derive(Clone, Debug, Deserialize, Serialize)]
/// A collection of residues and substrate configurations
/// which can be saved to and read from disk.
pub struct DataBase {
    #[serde(skip)]
    /// A path to the `DataBase` location on the hard drive.
    pub path: Option<PathBuf>,

    #[serde(rename = "residue_definitions", default = "Vec::new")]
    /// Definitions of `Residue` objects.
    pub residue_defs: Vec<Residue>,

    #[serde(rename = "component_definitions", default = "Vec::new")]
    /// New component constructors.
    pub component_defs: Vec<ComponentEntry>,
}

impl DataBase {
    /// Construct an empty `DataBase`.
    pub fn new() -> DataBase {
        DataBase {
            path: None,
            residue_defs: vec![],
            component_defs: vec![],
        }
    }

    /// Get the database path enclosed in single quotes if it exists,
    /// otherwise the unenclosed string "None".
    pub fn get_path_pretty(&self) -> String {
        self.path.as_ref()
            .map(|path| path.to_string_lossy().to_owned())
            .map(|path| format!("'{}'", path))
            .unwrap_or("None".to_string())
    }

    /// Set a new path for the `DataBase`. The input path is asserted to
    /// be a file and the extension is set to 'json'.
    pub fn set_path<T>(&mut self, new_path: &T) -> Result<(), DataBaseError>
            where T: ?Sized + AsRef<OsStr> {
        let mut path = PathBuf::from(new_path);

        if path.file_stem().is_some() {
            path.set_extension("json");
            self.path = Some(path);
            Ok(())
        } else {
            Err(DataBaseError::BadPath)
        }
    }

    /// Parse a reader for a JSON formatted `DataBase`.
    ///
    /// This and the `to_writer` method are defined to enable a unit
    /// test which ensures that the behaviour for reading and writing
    /// a `DataBase` is consistent.
    fn from_reader<R: io::Read>(reader: R) -> Result<DataBase, io::Error> {
        serde_json::from_reader(reader).map_err(|e| io::Error::from(e))
    }

    /// Write a `DataBase` as a JSON formatted object to an input writer.
    fn to_writer<W: io::Write>(&self, writer: &mut W) -> result::Result<(), io::Error> {
        serde_json::to_writer_pretty(writer, self).map_err(|e| io::Error::from(e))
    }
}

impl Describe for DataBase {
    fn describe(&self) -> String {
        let mut description = String::new();
        const ERR: &'static str = "Could not construct a string";

        writeln!(description, "Database path: {}\n", self.get_path_pretty()).expect(ERR);
        writeln!(description, "{}", describe_list_short("Component definitions", &self.component_defs)).expect(ERR);
        writeln!(description, "{}", describe_list("Residue definitions", &self.residue_defs)).expect(ERR);

        description
    }

    fn describe_short(&self) -> String {
        self.describe()
    }
}

/// Read a `DataBase` from a JSON formatted file.
/// The owned path is set to the input path.
pub fn read_database(from_path: &str) -> Result<DataBase, io::Error> {
    let path = Path::new(from_path);
    let buffer = File::open(&path)?;

    let mut database = DataBase::from_reader(buffer)?;
    database.path = Some(PathBuf::from(&from_path));

    Ok(database)
}

/// Write a `DataBase` as a JSON formatted file.
/// The function writes to that owned by the object.
pub fn write_database(database: &DataBase) -> Result<(), io::Error> {
    if let Some(ref path) = database.path {
        let mut buffer = File::create(&path)?;
        database.to_writer(&mut buffer)?;

        return Ok(());
    }

    Err(io::Error::new(
        io::ErrorKind::Other,
        "No path was set when trying to write the database to disk")
    )
}

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

    #[test]
    fn serialize_and_deserialize_residue_entry() {
        let base = Residue {
            code: "RES".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(3.0, 4.0, 5.0) },
            ]
        };

        let serialized = serde_json::to_string(&base).unwrap();
        let deserialized: Residue = serde_json::from_str(&serialized).unwrap();

        assert_eq!(base, deserialized);
    }

    #[test]
    fn database_by_default_sets_empty_vectors_if_not_available() {
        let database: DataBase = serde_json::from_str("{}").unwrap();
        assert!(database.residue_defs.is_empty());
        assert!(database.component_defs.is_empty());
    }

    #[test]
    fn read_and_write_database() {
        let base = Residue {
            code: "RES".to_string(),
            atoms: vec![
                Atom { code: "A1".to_string(), position: Coord::new(0.0, 1.0, 2.0) },
                Atom { code: "A2".to_string(), position: Coord::new(3.0, 4.0, 5.0) },
            ]
        };

        let database = DataBase {
            path: Some(PathBuf::from("This/will/be/removed")),
            residue_defs: vec![base.clone()],
            component_defs: vec![],
        };

        let mut serialized: Vec<u8> = Vec::new();
        database.to_writer(&mut serialized).unwrap();
        let deserialized = DataBase::from_reader(serialized.as_slice()).unwrap();

        assert_eq!(None, deserialized.path);
        assert_eq!(database.residue_defs, deserialized.residue_defs);
    }

    #[test]
    fn set_database_path() {
        let mut database = DataBase::new();
        assert!(database.set_path("test").is_ok());
        assert_eq!("test.json", database.path.unwrap().to_str().unwrap());
    }

    #[test]
    fn set_database_to_empty_path_is_error() {
        let mut database = DataBase::new();
        database.path = Some(PathBuf::from("unchanged.json"));
        assert!(database.set_path("").is_err());
        assert_eq!("unchanged.json", database.path.unwrap().to_str().unwrap());
    }

    #[cfg(unix)]
    #[test]
    fn get_database_path() {
        let mut database = DataBase::new();
        assert_eq!("None", &database.get_path_pretty());

        database.set_path("/a/file.json").unwrap();
        assert_eq!("'/a/file.json'", &database.get_path_pretty());
    }

    #[test]
    fn create_entry_macro_adds_from_method() {
        let cuboid = Cuboid::default();
        let component = ComponentEntry::from(cuboid.clone());

        match component {
            ComponentEntry::VolumeCuboid(object) => {
                assert_eq!(object.name, cuboid.name);
                assert_eq!(object.residue, cuboid.residue);
                assert_eq!(object.size, cuboid.size);
                assert_eq!(object.origin, cuboid.origin);
                assert_eq!(object.coords, cuboid.coords);
            },
            _ => panic!["Incorrect object was created"],
        }
    }
}
<|endoftext|>


<commit_before>use ansi_term::Style;
use locale::Numeric as NumericLocale;

use fs::fields as f;
use output::cell::{TextCell, DisplayWidth};
use output::table::SizeFormat;

impl f::Size {
    pub fn render<C: Colours>(&self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
        use number_prefix::{binary_prefix, decimal_prefix};
        use number_prefix::{Prefixed, Standalone, PrefixNames};

        let size = match *self {
            f::Size::Some(s)             => s,
            f::Size::None                => return TextCell::blank(colours.no_size()),
            f::Size::DeviceIDs(ref ids)  => return ids.render(colours),
        };

        let result = match size_format {
            SizeFormat::DecimalBytes  => decimal_prefix(size as f64),
            SizeFormat::BinaryBytes   => binary_prefix(size as f64),
            SizeFormat::JustBytes     => {
                let string = numerics.format_int(size);
                return TextCell::paint(colours.size(size), string);
            },
        };

        let (prefix, n) = match result {
            Standalone(b)  => return TextCell::paint(colours.size(b as u64), b.to_string()),
            Prefixed(p, n) => (p, n)
        };

        let symbol = prefix.symbol();
        let number = if n < 10f64 { numerics.format_float(n, 1) }
                             else { numerics.format_int(n as isize) };

        // The numbers and symbols are guaranteed to be written in ASCII, so
        // we can skip the display width calculation.
        let width = DisplayWidth::from(number.len() + symbol.len());

        TextCell {
            width,
            contents: vec![
                colours.size(size).paint(number),
                colours.unit().paint(symbol),
            ].into(),
        }
    }
}

impl f::DeviceIDs {
    fn render<C: Colours>(&self, colours: &C) -> TextCell {
        let major = self.major.to_string();
        let minor = self.minor.to_string();

        TextCell {
            width: DisplayWidth::from(major.len() + 1 + minor.len()),
            contents: vec![
                colours.major().paint(major),
                colours.comma().paint(","),
                colours.minor().paint(minor),
            ].into(),
        }
    }
}

pub trait Colours {
    fn size(&self, size: u64) -> Style;
    fn unit(&self) -> Style;
    fn no_size(&self) -> Style;

    fn major(&self) -> Style;
    fn comma(&self) -> Style;
    fn minor(&self) -> Style;
}

#[cfg(test)]
pub mod test {
    use super::Colours;
    use output::cell::{TextCell, DisplayWidth};
    use output::table::SizeFormat;
    use fs::fields as f;

    use locale::Numeric as NumericLocale;
    use ansi_term::Colour::*;
    use ansi_term::Style;

    struct TestColours;

    impl Colours for TestColours {
        fn size(&self, _size: u64) -> Style { Fixed(66).normal() }
        fn unit(&self)             -> Style { Fixed(77).bold() }
        fn no_size(&self)          -> Style { Black.italic() }

        fn major(&self) -> Style { Blue.on(Red) }
        fn comma(&self) -> Style { Green.italic() }
        fn minor(&self) -> Style { Cyan.on(Yellow) }
    }

    #[test]
    fn directory() {
        let directory = f::Size::None;
        let expected = TextCell::blank(Black.italic());
        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_decimal() {
        let directory = f::Size::Some(2_100_000);
        let expected = TextCell {
            width: DisplayWidth::from(4),
            contents: vec![
                Fixed(66).paint("2.1"),
                Fixed(77).bold().paint("M"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_binary() {
        let directory = f::Size::Some(1_048_576);
        let expected = TextCell {
            width: DisplayWidth::from(5),
            contents: vec![
                Fixed(66).paint("1.0"),
                Fixed(77).bold().paint("Mi"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_bytes() {
        let directory = f::Size::Some(1048576);
        let expected = TextCell {
            width: DisplayWidth::from(9),
            contents: vec![
                Fixed(66).paint("1,048,576"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }

    #[test]
    fn device_ids() {
        let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
        let expected = TextCell {
            width: DisplayWidth::from(5),
            contents: vec![
                Blue.on(Red).paint("10"),
                Green.italic().paint(","),
                Cyan.on(Yellow).paint("80"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }
}
<commit_msg>Fix usages of number_prefix<commit_after>use ansi_term::Style;
use locale::Numeric as NumericLocale;

use fs::fields as f;
use output::cell::{TextCell, DisplayWidth};
use output::table::SizeFormat;

impl f::Size {
    pub fn render<C: Colours>(&self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
        use number_prefix::{Prefixed, Standalone, NumberPrefix, PrefixNames};

        let size = match *self {
            f::Size::Some(s)             => s,
            f::Size::None                => return TextCell::blank(colours.no_size()),
            f::Size::DeviceIDs(ref ids)  => return ids.render(colours),
        };

        let result = match size_format {
            SizeFormat::DecimalBytes  => NumberPrefix::decimal(size as f64),
            SizeFormat::BinaryBytes   => NumberPrefix::binary(size as f64),
            SizeFormat::JustBytes     => {
                let string = numerics.format_int(size);
                return TextCell::paint(colours.size(size), string);
            },
        };

        let (prefix, n) = match result {
            Standalone(b)  => return TextCell::paint(colours.size(b as u64), b.to_string()),
            Prefixed(p, n) => (p, n)
        };

        let symbol = prefix.symbol();
        let number = if n < 10f64 { numerics.format_float(n, 1) }
                             else { numerics.format_int(n as isize) };

        // The numbers and symbols are guaranteed to be written in ASCII, so
        // we can skip the display width calculation.
        let width = DisplayWidth::from(number.len() + symbol.len());

        TextCell {
            width,
            contents: vec![
                colours.size(size).paint(number),
                colours.unit().paint(symbol),
            ].into(),
        }
    }
}

impl f::DeviceIDs {
    fn render<C: Colours>(&self, colours: &C) -> TextCell {
        let major = self.major.to_string();
        let minor = self.minor.to_string();

        TextCell {
            width: DisplayWidth::from(major.len() + 1 + minor.len()),
            contents: vec![
                colours.major().paint(major),
                colours.comma().paint(","),
                colours.minor().paint(minor),
            ].into(),
        }
    }
}

pub trait Colours {
    fn size(&self, size: u64) -> Style;
    fn unit(&self) -> Style;
    fn no_size(&self) -> Style;

    fn major(&self) -> Style;
    fn comma(&self) -> Style;
    fn minor(&self) -> Style;
}

#[cfg(test)]
pub mod test {
    use super::Colours;
    use output::cell::{TextCell, DisplayWidth};
    use output::table::SizeFormat;
    use fs::fields as f;

    use locale::Numeric as NumericLocale;
    use ansi_term::Colour::*;
    use ansi_term::Style;

    struct TestColours;

    impl Colours for TestColours {
        fn size(&self, _size: u64) -> Style { Fixed(66).normal() }
        fn unit(&self)             -> Style { Fixed(77).bold() }
        fn no_size(&self)          -> Style { Black.italic() }

        fn major(&self) -> Style { Blue.on(Red) }
        fn comma(&self) -> Style { Green.italic() }
        fn minor(&self) -> Style { Cyan.on(Yellow) }
    }

    #[test]
    fn directory() {
        let directory = f::Size::None;
        let expected = TextCell::blank(Black.italic());
        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_decimal() {
        let directory = f::Size::Some(2_100_000);
        let expected = TextCell {
            width: DisplayWidth::from(4),
            contents: vec![
                Fixed(66).paint("2.1"),
                Fixed(77).bold().paint("M"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::DecimalBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_binary() {
        let directory = f::Size::Some(1_048_576);
        let expected = TextCell {
            width: DisplayWidth::from(5),
            contents: vec![
                Fixed(66).paint("1.0"),
                Fixed(77).bold().paint("Mi"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::BinaryBytes, &NumericLocale::english()))
    }

    #[test]
    fn file_bytes() {
        let directory = f::Size::Some(1048576);
        let expected = TextCell {
            width: DisplayWidth::from(9),
            contents: vec![
                Fixed(66).paint("1,048,576"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }

    #[test]
    fn device_ids() {
        let directory = f::Size::DeviceIDs(f::DeviceIDs { major: 10, minor: 80 });
        let expected = TextCell {
            width: DisplayWidth::from(5),
            contents: vec![
                Blue.on(Red).paint("10"),
                Green.italic().paint(","),
                Cyan.on(Yellow).paint("80"),
            ].into(),
        };

        assert_eq!(expected, directory.render(&TestColours, SizeFormat::JustBytes, &NumericLocale::english()))
    }
}
<|endoftext|>


<commit_before>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Committed, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEnd};

use std::marker::PhantomData;

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer<T> (PhantomData<T>);

impl<T> Consumer<T> for DiscardConsumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, _: At<'a,T>) {}
}

impl<T> DiscardConsumer<T> {
    fn new() -> DiscardConsumer<T> {
        DiscardConsumer(PhantomData)
    }
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided->  init
// init -Committed->  committed
// init -Matched(s)-> matched
// init -Failed(b)->  failed(b)
//
// committed -Committed->     committed
// committed -Matched(s)->    matched
// committed -Failed(false)-> failed(false)
//
// matched -Matched(s)-> matched
//
// failed(b) -Failed(b)-> failed(b)
//
// The Failed(b) action carries a boolean indicating if backtracking is allowed.
// Note that there is no transition . -Committed-> . -Failed(true)-> . so
// once a parser has committed, we can clean up space associated with backtracking.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided,
    Committed,
    Matched(T),
    Failed(bool),
}

pub trait Parser<S,T> where S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a> {
    // If push_to returns Undecided or Failed(true), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push_to(nil,d) is a no-op
    // push_to(a ++ b, d) is the same as push_to(a,d); push_to(b,d)
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool;
    // Helper methods
    fn push<'a>(&mut self, value: At<'a,S>) -> MatchResult<At<'a,S>> {
        self.push_to(value, &mut DiscardConsumer::new())
    }
    fn done(&mut self) -> bool {
        self.done_to(&mut DiscardConsumer::new())
    }
    fn and_then<R>(self, other: R) -> AndThenParser<Self,R> where Self: Sized, R: Parser<S,T> {
        AndThenParser{ lhs: self, rhs: CommittedParser{ parser: other }, in_lhs: true }
    }
}

pub trait BufferableMatcher<S,T> where S: for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

#[derive(Clone, Debug)]
pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push_to(value, downstream) {
            Undecided     => Committed,
            Committed     => Committed,
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(false),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done_to(downstream)
    }
}

// ----------- Sequencing ---------------

#[derive(Clone, Debug)]
pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push_to(value, downstream) {
                Undecided     => Undecided,
                Committed     => Committed,
                Matched(rest) => { self.in_lhs = false; self.rhs.push_to(rest, downstream) },
                Failed(b)     => Failed(b),
            }
        } else {
            self.rhs.push_to(value, downstream)
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.in_lhs = true;
        self.lhs.done_to(downstream) & self.rhs.done_to(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEnd(bool),
}

#[derive(Clone, Debug)]
pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEnd(true); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided },
            AtOffset(_)                                                    => { self.state = AtEnd(false); Failed(true) },
            AtEnd(true)                                                    => { Matched(string) },
            AtEnd(false)                                                   => { Failed(true) },
        }
    }
    fn done_to(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEnd(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

#[derive(Clone, Debug)]
pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string);
                match result {
                    Undecided     => self.state = Middle(String::from(string)),
                    Committed     => self.state = Middle(String::from(string)),
                    Failed(b)     => self.state = EndFail(b),
                    Matched(rest) => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string);
                match result {
                    Undecided     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Committed     => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(b)     => { self.state = EndFail(b); },
                    Matched(rest) => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(b) => Failed(b),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done();
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(true));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched("def"));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("a"), Undecided);
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided);
    assert_eq!(parser.push("cd"), Matched("d"));
    assert_eq!(parser.done(), true);
}

#[test]
fn test_and_then() {
    let mut parser = constant(String::from("abc")).and_then(constant(String::from("def")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(true));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided);
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Committed);
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcd"), Committed);
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcfred"), Failed(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdefghi"), Matched("ghi"));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("a"), Undecided);
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided);
    assert_eq!(parser.push("cd"), Committed);
    assert_eq!(parser.push("efg"), Matched("g"));
    assert_eq!(parser.done(), true);
}
<commit_msg>Redid parsers to enforce being LL(1).<commit_after>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEndMatched, AtEndFailed};

use std::marker::PhantomData;

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer<T> (PhantomData<T>);

impl<T> Consumer<T> for DiscardConsumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, _: At<'a,T>) {}
}

impl<T> DiscardConsumer<T> {
    fn new() -> DiscardConsumer<T> {
        DiscardConsumer(PhantomData)
    }
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided->  init
// init -Committed->  committed
// init -Matched(s)-> matched
// init -Failed(b)->  failed(b)
//
// committed -Committed->     committed
// committed -Matched(s)->    matched
// committed -Failed(false)-> failed(false)
//
// matched -Matched(s)-> matched
//
// failed(b) -Failed(b)-> failed(b)
//
// The Failed(b) action carries a boolean indicating if backtracking is allowed.
// Note that there is no transition . -Committed-> . -Failed(true)-> . so
// once a parser has committed, we can clean up space associated with backtracking.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided(bool),
    Matched(T),
    Failed(Option<T>),
}

pub trait Parser<S,T> where S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a> {
    // If push_to returns Undecided or Failed(true), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push_to(nil,d) is a no-op
    // push_to(a ++ b, d) is the same as push_to(a,d); push_to(b,d)
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool;
    // Helper methods
    fn push<'a>(&mut self, value: At<'a,S>) -> MatchResult<At<'a,S>> {
        self.push_to(value, &mut DiscardConsumer::new())
    }
    fn done(&mut self) -> bool {
        self.done_to(&mut DiscardConsumer::new())
    }
    fn and_then<R>(self, other: R) -> AndThenParser<Self,R> where Self: Sized, R: Parser<S,T> {
        AndThenParser{ lhs: self, rhs: CommittedParser{ parser: other }, in_lhs: true }
    }
    fn many0(self) -> Many0Parser<Self> where Self: Sized {
        Many0Parser{ parser: self, first_time: true }
    }
}

pub trait BufferableMatcher<S,T> where S: for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

#[derive(Clone, Debug)]
pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push_to(value, downstream) {
            Undecided(_)  => Undecided(false),
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done_to(downstream)
    }
}

// ----------- Sequencing ---------------

#[derive(Clone, Debug)]
pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push_to(value, downstream) {
                Undecided(b)  => Undecided(b),
                Matched(rest) => { self.in_lhs = false; self.lhs.done_to(downstream); self.rhs.push_to(rest, downstream) },
                Failed(rest)  => Failed(rest),
            }
        } else {
            self.rhs.push_to(value, downstream)
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        if self.in_lhs {
            self.lhs.done_to(downstream) && self.rhs.done_to(downstream)
        } else {
            self.in_lhs = true;
            self.rhs.done_to(downstream)
        }
    }
}

// ----------- Kleene star ---------------

#[derive(Clone, Debug)]
pub struct Many0Parser<P> {
    parser: P,
    first_time: bool,
}

impl<S,T,P> Parser<S,T> for Many0Parser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, mut value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        loop { match self.parser.push_to(value, downstream) {
            Undecided(b)        => return Undecided(b & self.first_time),
            Matched(rest)       => { self.first_time = false; value = rest; },
            Failed(Some(rest))  => return Matched(rest),
            Failed(None)        => return Failed(None),
        } }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.first_time = true;
        self.parser.done_to(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEndMatched(bool),
    AtEndFailed(bool),
}

#[derive(Clone, Debug)]
pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(0)     if string.is_empty()                           => { Undecided(true) },
            AtOffset(index) if string == &self.constant[index..]           => { downstream.accept(()); self.state = AtEndMatched(true); Matched("") },
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEndMatched(false); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided(false) },
            AtOffset(0)     if !string.starts_with(&self.constant[..1])    => { self.state = AtEndFailed(true); Failed(Some(string)) },
            AtOffset(_)                                                    => { self.state = AtEndFailed(false); Failed(None) },
            AtEndMatched(true)                                             => { self.state = AtEndMatched(string.is_empty()); Matched(string) },
            AtEndMatched(false)                                            => { Matched(string) },
            AtEndFailed(true)                                              => { Failed(Some(string)) },
            AtEndFailed(false)                                             => { Failed(None) },
        }
    }
    fn done_to(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEndMatched(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

#[derive(Clone, Debug)]
pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => self.state = Middle(String::from(string)),
                    Failed(Some(_)) => self.state = EndFail(true),
                    Failed(None)    => self.state = EndFail(false),
                    Matched(rest)   => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(Some(_)) => { self.state = EndFail(true) },
                    Failed(None)    => { self.state = EndFail(false) },
                    Matched(rest)   => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(true) => Failed(Some(string)),
            EndFail(false) => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done();
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched("def"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Matched("d"));
    assert_eq!(parser.done(), false);
}

#[test]
fn test_and_then() {
    let mut parser = constant(String::from("abc")).and_then(constant(String::from("def")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcd"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcfred"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("abcdefghi"), Matched("ghi"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("efg"), Matched("g"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("ef"), Matched(""));
    assert_eq!(parser.done(), true);
}
<|endoftext|>


<commit_before>fn d_1d(field: &Vec<Vec<f64>>) -> Vec<Vec<f64>> {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);

    let mut answer: Vec<Vec<f64>> = vec![vec![0.; size + 1]; size + 1];

    answer
}

fn d_2d_x(field: &Vec<Vec<f64>>) -> Vec<Vec<f64>> {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);

    let mut answer: Vec<Vec<f64>> = vec![vec![0.; size + 1]; size + 1];

    answer
}

fn d_2d_y(field: &Vec<Vec<f64>>) -> Vec<Vec<f64>> {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);

    let mut answer: Vec<Vec<f64>> = vec![vec![0.; size + 1]; size + 1];

    answer
}
<commit_msg>python and diff fix / re<commit_after>pub fn d_1d(field: &Vec<Vec<f64>>, answer: &Vec<Vec<f64>>) {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);
    assert!(field[0].capacity() == size + 1);
    assert!(answer.capacity() == size + 1);
    assert!(answer[0].capacity() == size + 1);

}

pub fn d_2d_x(field: &Vec<Vec<f64>>, answer: &Vec<Vec<f64>>) {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);
    assert!(field[0].capacity() == size + 1);
    assert!(answer.capacity() == size + 1);
    assert!(answer[0].capacity() == size + 1);
}

pub fn d_2d_y(field: &Vec<Vec<f64>>, answer: &Vec<Vec<f64>>) {

    let size: usize = field.capacity() - 1;
    assert!(field.capacity() == size + 1);
    assert!(field[0].capacity() == size + 1);
    assert!(answer.capacity() == size + 1);
    assert!(answer[0].capacity() == size + 1);
}
<|endoftext|>


<commit_before>use crate::platform::*;
use crate::types::*;
use crate::winrust::hstring::*;
use crate::winrust::*;
use std::fmt;
use std::{convert::TryFrom, io};

pub struct LanguageData {
    pub tag: String,
    pub name: String,
    pub english_name: String,
    pub localised_name: String,
    pub script_name: String,
}

impl fmt::Display for LanguageData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Tag:           {}", self.tag)?;
        writeln!(f, "Name:          {}", self.name)?;
        writeln!(f, "English Name:  {}", self.english_name)?;
        writeln!(f, "Native Name:   {}", self.localised_name)?;
        writeln!(f, "Script:        {}", self.script_name)?;

        Ok(())
    }
}

pub fn get_language_names(tag: &str) -> Option<LanguageData> {
    log::debug!("get_language_names({:?})", &tag);
    let mut a = [0u16; 256];
    let mut b = [0u16; 256];
    let mut c = [0u16; 256];
    let mut d = [0u16; 256];

    let ret = unsafe {
        sys::winlangdb::GetLanguageNames(
            to_wide_string(tag).as_ptr(),
            a.as_mut_ptr(),
            b.as_mut_ptr(),
            c.as_mut_ptr(),
            d.as_mut_ptr(),
        )
    };

    if ret != 0 {
        log::error!(
            "Error getting language names: {:?}",
            io::Error::last_os_error()
        );
        return None;
    }

    Some(LanguageData {
        tag: tag.to_owned(),
        name: from_wide_string(&a).unwrap(),
        english_name: from_wide_string(&b).unwrap(),
        localised_name: from_wide_string(&c).unwrap(),
        script_name: from_wide_string(&d).unwrap(),
    })
}

pub fn set_user_languages(tags: &[String]) -> Result<(), io::Error> {
    log::debug!("set_user_languages({:?})", tags);
    let joined = tags.join(";");
    log::trace!("Joined: {:?}", &joined);
    let handle = HString::from(joined);
    // let semi = ";".encode_utf16().collect::<Vec<_>>()[0];
    let ret = unsafe { sys::winlangdb::SetUserLanguages(';' as u16, *handle) };

    if ret != 0 {
        let err = io::Error::last_os_error();
        log::error!("Error setting user languages: {:?}", err);

        return Err(err);
    }

    Ok(())
}

pub fn transform_input_methods(methods: InputList, tag: &str) -> InputList {
    let hmethods = HString::from(String::from(methods));
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::TransformInputMethodsForLanguage(*hmethods, *htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}

pub fn default_input_method(tag: &str) -> InputList {
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::GetDefaultInputMethodForLanguage(*htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}
<commit_msg>This should make absolutely no difference<commit_after>use crate::platform::*;
use crate::types::*;
use crate::winrust::hstring::*;
use crate::winrust::*;
use std::fmt;
use std::{convert::TryFrom, io};

pub struct LanguageData {
    pub tag: String,
    pub name: String,
    pub english_name: String,
    pub localised_name: String,
    pub script_name: String,
}

impl fmt::Display for LanguageData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Tag:           {}", self.tag)?;
        writeln!(f, "Name:          {}", self.name)?;
        writeln!(f, "English Name:  {}", self.english_name)?;
        writeln!(f, "Native Name:   {}", self.localised_name)?;
        writeln!(f, "Script:        {}", self.script_name)?;

        Ok(())
    }
}

pub fn get_language_names(tag: &str) -> Option<LanguageData> {
    log::debug!("get_language_names({:?})", &tag);
    let mut a = [0u16; 256];
    let mut b = [0u16; 256];
    let mut c = [0u16; 256];
    let mut d = [0u16; 256];

    let ret = unsafe {
        sys::winlangdb::GetLanguageNames(
            to_wide_string(tag).as_ptr(),
            a.as_mut_ptr(),
            b.as_mut_ptr(),
            c.as_mut_ptr(),
            d.as_mut_ptr(),
        )
    };

    if ret != 0 {
        log::error!(
            "Error getting language names: {:?}",
            io::Error::last_os_error()
        );
        return None;
    }

    Some(LanguageData {
        tag: tag.to_owned(),
        name: from_wide_string(&a).unwrap(),
        english_name: from_wide_string(&b).unwrap(),
        localised_name: from_wide_string(&c).unwrap(),
        script_name: from_wide_string(&d).unwrap(),
    })
}

pub fn set_user_languages(tags: &[String]) -> Result<(), io::Error> {
    log::debug!("set_user_languages({:?})", tags);
    let joined = format!("{}", tags.join(":"));
    log::trace!("Joined: {:?}", &joined);
    let handle = HString::from(joined);
    // let semi = ";".encode_utf16().collect::<Vec<_>>()[0];
    let ret = unsafe { sys::winlangdb::SetUserLanguages(':' as u16, *handle) };

    if ret != 0 {
        let err = io::Error::last_os_error();
        log::error!("Error setting user languages: {:?}", err);

        return Err(err);
    }

    Ok(())
}

pub fn transform_input_methods(methods: InputList, tag: &str) -> InputList {
    let hmethods = HString::from(String::from(methods));
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::TransformInputMethodsForLanguage(*hmethods, *htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}

pub fn default_input_method(tag: &str) -> InputList {
    let htag = HString::from(tag);
    let out = unsafe {
        let mut out = HString::null();
        sys::winlangdb::GetDefaultInputMethodForLanguage(*htag, &mut *out);
        out
    };
    InputList::try_from(String::from(out)).unwrap()
}
<|endoftext|>


<commit_before>use std::cmp::min;

use Byte;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: Byte,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

#[cfg(test)]
mod test_chunk_length {
    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}<commit_msg>Change function definition<commit_after>use std::cmp::min;

use Byte;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

#[cfg(test)]
mod test_chunk_length {
    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}<|endoftext|>