<commit_before>use super::*;
use std::fmt;
use std::mem;
use std::sync::{Mutex, MutexGuard};

/// Common glyph layout logic.
pub trait GlyphCruncher<'font> {
    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn pixel_bounds_custom_layout<'a, S, L>(
        &mut self,
        section: S,
        custom_layout: &L,
    ) -> Option<Rect<i32>>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>;

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn pixel_bounds<'a, S>(&mut self, section: S) -> Option<Rect<i32>>
    where
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn glyphs_custom_layout<'a, 'b, S, L>(
        &'b mut self,
        section: S,
        custom_layout: &L,
    ) -> PositionedGlyphIter<'b, 'font>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>;

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn glyphs<'a, 'b, S>(&'b mut self, section: S) -> PositionedGlyphIter<'b, 'font>
    where
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }
}

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`GlyphCalculatorBuilder`](struct.GlyphCalculatorBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{GlyphCalculatorBuilder, GlyphCruncher, Section};
/// # fn main() {
///
/// let dejavu: &[u8] = include_bytes!("../examples/DejaVuSans.ttf");
/// let glyphs = GlyphCalculatorBuilder::using_font_bytes(dejavu).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// // create the scope, equivalent to a lock on the cache when
/// // dropped will clean unused cached calculations like a draw call
/// let mut scope = glyphs.cache_scope();
///
/// let bounds = scope.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphCalculatorGuard::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphCalculatorGuard::glyphs`](#method.glyphs) calculate the positioned glyphs for a
/// section. This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) there is no concept of actually drawing
/// the section to imply a section is no longer used. Instead a `GlyphCalculatorGuard`
/// is created, that provides the calculation functionality. Dropping indicates the 'cache frame'
/// is over, similar to when a `GlyphBrush` is draws. Any cached sections from previous 'frames'
/// are invalidated.
pub struct GlyphCalculator<'font> {
    fonts: FxHashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: Mutex<FxHashMap<u64, GlyphedSection<'font>>>,
}

impl<'font> fmt::Debug for GlyphCalculator<'font> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GlyphCalculator")
    }
}

impl<'font> GlyphCalculator<'font> {
    pub fn cache_scope<'a>(&'a self) -> GlyphCalculatorGuard<'a, 'font> {
        GlyphCalculatorGuard {
            fonts: &self.fonts,
            glyph_cache: self.calculate_glyph_cache.lock().unwrap(),
            cached: HashSet::default(),
        }
    }
}

/// [`GlyphCalculator`](struct.GlyphCalculator.html) scoped cache lock.
pub struct GlyphCalculatorGuard<'brush, 'font: 'brush> {
    fonts: &'brush FxHashMap<FontId, rusttype::Font<'font>>,
    glyph_cache: MutexGuard<'brush, FxHashMap<u64, GlyphedSection<'font>>>,
    cached: HashSet<u64>,
}

impl<'brush, 'font> GlyphCalculatorGuard<'brush, 'font> {
    /// Returns the calculate_glyph_cache key for this sections glyphs
    fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
    where
        L: GlyphPositioner,
    {
        let section_hash = xxhash(&(section, layout));

        if let Entry::Vacant(entry) = self.glyph_cache.entry(section_hash) {
            entry.insert(GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(self.fonts, section),
                z: section.z,
            });
        }

        section_hash
    }
}

impl<'brush, 'font> fmt::Debug for GlyphCalculatorGuard<'brush, 'font> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GlyphCalculatorGuard")
    }
}

impl<'brush, 'font> GlyphCruncher<'font> for GlyphCalculatorGuard<'brush, 'font> {
    fn pixel_bounds_custom_layout<'a, S, L>(
        &mut self,
        section: S,
        custom_layout: &L,
    ) -> Option<Rect<i32>>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.cached.insert(section_hash);
        for g in self.glyph_cache[&section_hash]
            .glyphs
            .iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect { min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 {
                    x.0 = min.x;
                }
                if no_match || min.y < y.0 {
                    y.0 = min.y;
                }
                if no_match || max.x > x.1 {
                    x.1 = max.x;
                }
                if no_match || max.y > y.1 {
                    y.1 = max.y;
                }

                no_match = false;
            }
        }

        if no_match {
            None
        }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    fn glyphs_custom_layout<'a, 'b, S, L>(
        &'b mut self,
        section: S,
        custom_layout: &L,
    ) -> PositionedGlyphIter<'b, 'font>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.cached.insert(section_hash);
        self.glyph_cache[&section_hash]
            .glyphs
            .iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }
}

impl<'a, 'b> Drop for GlyphCalculatorGuard<'a, 'b> {
    fn drop(&mut self) {
        let mut cached = HashSet::new();
        mem::swap(&mut cached, &mut self.cached);
        self.glyph_cache.retain(|key, _| cached.contains(key));
    }
}

/// Builder for a [`GlyphCalculator`](struct.GlyphCalculator.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::GlyphCalculatorBuilder;
/// # fn main() {
///
/// let dejavu: &[u8] = include_bytes!("../examples/DejaVuSans.ttf");
/// let mut glyphs = GlyphCalculatorBuilder::using_font_bytes(dejavu).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct GlyphCalculatorBuilder<'a> {
    font_data: Vec<Font<'a>>,
}

impl<'a> GlyphCalculatorBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(Font::from_bytes(font_0_data).unwrap())
    }

    pub fn using_fonts_bytes<B, V>(font_data: V) -> Self
    where
        B: Into<SharedBytes<'a>>,
        V: Into<Vec<B>>,
    {
        Self::using_fonts(
            font_data
                .into()
                .into_iter()
                .map(|data| Font::from_bytes(data).unwrap())
                .collect::<Vec<_>>(),
        )
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
        }
    }

    pub fn using_fonts<V: Into<Vec<Font<'a>>>>(fonts: V) -> Self {
        Self {
            font_data: fonts.into(),
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data
            .push(Font::from_bytes(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Builds a `GlyphCalculator`
    pub fn build(self) -> GlyphCalculator<'a> {
        let fonts = self
            .font_data
            .into_iter()
            .enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        GlyphCalculator {
            fonts,
            calculate_glyph_cache: Mutex::new(HashMap::default()),
        }
    }
}
<commit_msg>Clarify GlyphCalculator caching docs<commit_after>use super::*;
use std::fmt;
use std::mem;
use std::sync::{Mutex, MutexGuard};

/// Common glyph layout logic.
pub trait GlyphCruncher<'font> {
    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn pixel_bounds_custom_layout<'a, S, L>(
        &mut self,
        section: S,
        custom_layout: &L,
    ) -> Option<Rect<i32>>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>;

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn pixel_bounds<'a, S>(&mut self, section: S) -> Option<Rect<i32>>
    where
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn glyphs_custom_layout<'a, 'b, S, L>(
        &'b mut self,
        section: S,
        custom_layout: &L,
    ) -> PositionedGlyphIter<'b, 'font>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>;

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    fn glyphs<'a, 'b, S>(&'b mut self, section: S) -> PositionedGlyphIter<'b, 'font>
    where
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }
}

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`GlyphCalculatorBuilder`](struct.GlyphCalculatorBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{GlyphCalculatorBuilder, GlyphCruncher, Section};
/// # fn main() {
///
/// let dejavu: &[u8] = include_bytes!("../examples/DejaVuSans.ttf");
/// let glyphs = GlyphCalculatorBuilder::using_font_bytes(dejavu).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// // create the scope, equivalent to a lock on the cache when
/// // dropped will clean unused cached calculations like a draw call
/// let mut scope = glyphs.cache_scope();
///
/// let bounds = scope.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphCalculatorGuard::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphCalculatorGuard::glyphs`](#method.glyphs) calculate the positioned glyphs for a
/// section. This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) there is no concept of actually drawing
/// the section to imply when a section is used / no longer used. Instead a `GlyphCalculatorGuard`
/// is created, that provides the calculation functionality. Dropping indicates the 'cache frame'
/// is over, similar to when a `GlyphBrush` draws. Section calculations are cached for the next
/// 'cache frame', if not used then they will be dropped.
pub struct GlyphCalculator<'font> {
    fonts: FxHashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: Mutex<FxHashMap<u64, GlyphedSection<'font>>>,
}

impl<'font> fmt::Debug for GlyphCalculator<'font> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GlyphCalculator")
    }
}

impl<'font> GlyphCalculator<'font> {
    pub fn cache_scope<'a>(&'a self) -> GlyphCalculatorGuard<'a, 'font> {
        GlyphCalculatorGuard {
            fonts: &self.fonts,
            glyph_cache: self.calculate_glyph_cache.lock().unwrap(),
            cached: HashSet::default(),
        }
    }
}

/// [`GlyphCalculator`](struct.GlyphCalculator.html) scoped cache lock.
pub struct GlyphCalculatorGuard<'brush, 'font: 'brush> {
    fonts: &'brush FxHashMap<FontId, rusttype::Font<'font>>,
    glyph_cache: MutexGuard<'brush, FxHashMap<u64, GlyphedSection<'font>>>,
    cached: HashSet<u64>,
}

impl<'brush, 'font> GlyphCalculatorGuard<'brush, 'font> {
    /// Returns the calculate_glyph_cache key for this sections glyphs
    fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
    where
        L: GlyphPositioner,
    {
        let section_hash = xxhash(&(section, layout));

        if let Entry::Vacant(entry) = self.glyph_cache.entry(section_hash) {
            entry.insert(GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(self.fonts, section),
                z: section.z,
            });
        }

        section_hash
    }
}

impl<'brush, 'font> fmt::Debug for GlyphCalculatorGuard<'brush, 'font> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GlyphCalculatorGuard")
    }
}

impl<'brush, 'font> GlyphCruncher<'font> for GlyphCalculatorGuard<'brush, 'font> {
    fn pixel_bounds_custom_layout<'a, S, L>(
        &mut self,
        section: S,
        custom_layout: &L,
    ) -> Option<Rect<i32>>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.cached.insert(section_hash);
        for g in self.glyph_cache[&section_hash]
            .glyphs
            .iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect { min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 {
                    x.0 = min.x;
                }
                if no_match || min.y < y.0 {
                    y.0 = min.y;
                }
                if no_match || max.x > x.1 {
                    x.1 = max.x;
                }
                if no_match || max.y > y.1 {
                    y.1 = max.y;
                }

                no_match = false;
            }
        }

        if no_match {
            None
        }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    fn glyphs_custom_layout<'a, 'b, S, L>(
        &'b mut self,
        section: S,
        custom_layout: &L,
    ) -> PositionedGlyphIter<'b, 'font>
    where
        L: GlyphPositioner + Hash,
        S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.cached.insert(section_hash);
        self.glyph_cache[&section_hash]
            .glyphs
            .iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }
}

impl<'a, 'b> Drop for GlyphCalculatorGuard<'a, 'b> {
    fn drop(&mut self) {
        let mut cached = HashSet::new();
        mem::swap(&mut cached, &mut self.cached);
        self.glyph_cache.retain(|key, _| cached.contains(key));
    }
}

/// Builder for a [`GlyphCalculator`](struct.GlyphCalculator.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::GlyphCalculatorBuilder;
/// # fn main() {
///
/// let dejavu: &[u8] = include_bytes!("../examples/DejaVuSans.ttf");
/// let mut glyphs = GlyphCalculatorBuilder::using_font_bytes(dejavu).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct GlyphCalculatorBuilder<'a> {
    font_data: Vec<Font<'a>>,
}

impl<'a> GlyphCalculatorBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(Font::from_bytes(font_0_data).unwrap())
    }

    pub fn using_fonts_bytes<B, V>(font_data: V) -> Self
    where
        B: Into<SharedBytes<'a>>,
        V: Into<Vec<B>>,
    {
        Self::using_fonts(
            font_data
                .into()
                .into_iter()
                .map(|data| Font::from_bytes(data).unwrap())
                .collect::<Vec<_>>(),
        )
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
        }
    }

    pub fn using_fonts<V: Into<Vec<Font<'a>>>>(fonts: V) -> Self {
        Self {
            font_data: fonts.into(),
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data
            .push(Font::from_bytes(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Builds a `GlyphCalculator`
    pub fn build(self) -> GlyphCalculator<'a> {
        let fonts = self
            .font_data
            .into_iter()
            .enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        GlyphCalculator {
            fonts,
            calculate_glyph_cache: Mutex::new(HashMap::default()),
        }
    }
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
 */
#![allow(unused_variables)]

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use ::universe::Universe;
use ::potentials::*;

use super::yaml::{YamlLoader, Yaml};
use super::{Error, Result};

trait FromYaml where Self: Sized {
    fn from_yaml(node: &Yaml) -> Result<Self>;
}

// TODO: Add support for * in atoms sections.
// TODO: Add support for computation section

/// Read a interactions from a Yaml file at `path`, and add these interactions
/// to the `universe`.
///
/// The following format is accepted:
///
/// ```YAML
/// pairs:  # Non bonded atoms pairs
///   - atoms: [He, He]
///     type: LennardJones
///     sigma: 3.4 A
///     epsilon: 0.45 kJ/mol
///   - atoms: [He, Ar]
///     type: NullPotential
/// bond: # Bonded atoms pairs
///   - atoms: [C, C]
///     type: Harmonic
///     k: 67 kJ/mol/A^2
///     x0: 1.20 A
/// angles: # Molecular angles
///   - atoms: [O, C, C]
///     type: CosineHarmonic
///     k: 67 kJ/mol/deg^2
///     x0: 120 deg
///   - atoms: [C, C, C]
///     type: harmonic
///     k: 300 kJ/mol/deg^2
///     x0: 120 deg
/// dihedrals: # Molecular angles
///   - atoms: [O, C, C, O]
///     type: harmonic
///     k: 42 kJ/mol/deg^2
///     x0: 180 deg
/// ```
///
/// The main items are the `"pairs"`, `"bonds"`, `"angles"` and `"dihedrals"`;
/// which contains the data for pair potentials, bonds, angles and dihedral
/// angles potential. This data is orgnised as a vector of hash maps. Each maps
/// has at least a vector of `"atoms"` defining which particles will get this
/// interaction applied to, and a `"type"` parameter defining the type of the
/// potential. Others keys may be supplied depending on the potential type.
pub fn read_potentials<P: AsRef<Path>>(universe: &mut Universe, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buff = String::new();
    try!(file.read_to_string(&mut buff));

    let doc = &try!(YamlLoader::load_from_str(&buff))[0];
    if let Some(config) = doc["pairs"].as_vec() {
        try!(read_pairs(universe, config, true));
    }

    if let Some(config) = doc["bonds"].as_vec() {
        try!(read_pairs(universe, config, false));
    }

    if let Some(config) = doc["angles"].as_vec() {
        try!(read_angles(universe, config));
    }

    if let Some(config) = doc["dihedrals"].as_vec() {
        try!(read_dihedrals(universe, config));
    }

    Ok(())
}

/// Read the "pairs" or the "bonds" section in the file. If `pair_potentials`
/// is `true`, then the interactions are added to the pair interactions. Else,
/// the interaction are added to the bond interactions.
fn read_pairs(universe: &mut Universe, pairs: &Vec<Yaml>, pair_potentials: bool) -> Result<()> {
    for potential in pairs {
        let (a, b) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 2 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in pair potentials. Should be 2, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b)) = (vec[0].as_str(), vec[1].as_str()) {
                    (a, b)
                } else {
                    return Err(Error::from("The atoms names are not strings in pair potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in pair potential"));
            }
        };

        let potential = try!(read_pair_potential(potential));
        if pair_potentials {
            universe.add_pair_interaction(a, b, potential);
        } else {
            universe.add_bond_interaction(a, b, potential);
        }
    }
    Ok(())
}

fn read_pair_potential(node: &Yaml) -> Result<Box<PairPotential>> {
    match node["type"].as_str() {
        None => {
            return Err(Error::from("Missing 'type' section in pair potential"));
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "lennard-jones" | "lennardjones" => Ok(Box::new(try!(LennardJones::from_yaml(node)))),
                "null" | "nullpotential" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_angles(universe: &mut Universe, angles: &Vec<Yaml>) -> Result<()> {
    for potential in angles {
        let (a, b, c) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 3 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in angle potential. Should be 3, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str()) {
                    (a, b, c)
                } else {
                    return Err(Error::from("The atoms names are not strings in angle potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in angles potential"));
            }
        };

        let potential = try!(read_angle_potential(potential));
        universe.add_angle_interaction(a, b, c, potential);
    }
    Ok(())
}

fn read_angle_potential(node: &Yaml) -> Result<Box<AnglePotential>> {
    match node["type"].as_str() {
        None => {
            return Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ));
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_dihedrals(universe: &mut Universe, dihedrals: &Vec<Yaml>) -> Result<()> {
    for potential in dihedrals {
        let (a, b, c, d) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 4 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in dihedral potential. Should be 4, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c), Some(d)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str(), vec[3].as_str()) {
                    (a, b, c, d)
                } else {
                    return Err(Error::from("The atoms names are not strings in dihedral potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in dihedral potential"));
            }
        };

        let potential = try!(read_dihedral_potential(potential));
        universe.add_dihedral_interaction(a, b, c, d, potential);
    }
    Ok(())
}

fn read_dihedral_potential(node: &Yaml) -> Result<Box<DihedralPotential>> {
    match node["type"].as_str() {
        None => {
            return Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ));
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

impl FromYaml for NullPotential {
    fn from_yaml(node: &Yaml) -> Result<NullPotential> {
        Ok(NullPotential)
    }
}

impl FromYaml for Harmonic {
    fn from_yaml(node: &Yaml) -> Result<Harmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(Harmonic{k: k, x0: x0})
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in harmonic potential")
            )
        }
    }
}

impl FromYaml for LennardJones {
    fn from_yaml(node: &Yaml) -> Result<LennardJones> {
        if let (Some(sigma), Some(epsilon)) = (node["sigma"].as_str(), node["epsilon"].as_str()) {
            let sigma = try!(::units::from_str(sigma));
            let epsilon = try!(::units::from_str(epsilon));
            Ok(LennardJones{sigma: sigma, epsilon: epsilon})
        } else {
            Err(
                Error::from("Missing 'sigma' or 'espilon' in Lennard-Jones potential")
            )
        }
    }
}

impl FromYaml for CosineHarmonic {
    fn from_yaml(node: &Yaml) -> Result<CosineHarmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(CosineHarmonic::new(k, x0))
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in cosine harmonic potential")
            )
        }
    }
}
<commit_msg>Add computation support in input files<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
 */
#![allow(unused_variables)]

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use ::universe::Universe;
use ::potentials::*;

use super::yaml::{YamlLoader, Yaml};
use super::{Error, Result};

trait FromYaml where Self: Sized {
    fn from_yaml(node: &Yaml) -> Result<Self>;
}

// TODO: Add support for * in atoms sections.

/// Read a interactions from a Yaml file at `path`, and add these interactions
/// to the `universe`.
///
/// The following format is accepted:
///
/// ```YAML
/// pairs:  # Non bonded atoms pairs
///   - atoms: [He, He]
///     type: LennardJones
///     sigma: 3.4 A
///     epsilon: 0.45 kJ/mol
///     # computations specification is optional
///     computation:
///       type: table
///       numpoints: 5000
///       max: 20.0 A
///   - atoms: [He, Ar]
///     type: LennardJones
///     sigma: 3.8 A
///     epsilon: 0.67 kJ/mol
///     computation:
///       type: cutoff
///       cutoff: 10 A
///   - atoms: [He, Ar]
///     type: NullPotential
/// bond: # Bonded atoms pairs
///   - atoms: [C, C]
///     type: Harmonic
///     k: 67 kJ/mol/A^2
///     x0: 1.20 A
/// angles: # Molecular angles
///   - atoms: [O, C, C]
///     type: CosineHarmonic
///     k: 67 kJ/mol/deg^2
///     x0: 120 deg
///   - atoms: [C, C, C]
///     type: harmonic
///     k: 300 kJ/mol/deg^2
///     x0: 120 deg
/// dihedrals: # Molecular angles
///   - atoms: [O, C, C, O]
///     type: harmonic
///     k: 42 kJ/mol/deg^2
///     x0: 180 deg
/// ```
///
/// The main items are the `"pairs"`, `"bonds"`, `"angles"` and `"dihedrals"`;
/// which contains the data for pair potentials, bonds, angles and dihedral
/// angles potential. This data is orgnised as a vector of hash maps. Each maps
/// has at least a vector of `"atoms"` defining which particles will get this
/// interaction applied to, and a `"type"` parameter defining the type of the
/// potential. Others keys may be supplied depending on the potential type.
pub fn read_potentials<P: AsRef<Path>>(universe: &mut Universe, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buff = String::new();
    try!(file.read_to_string(&mut buff));

    let doc = &try!(YamlLoader::load_from_str(&buff))[0];
    if let Some(config) = doc["pairs"].as_vec() {
        try!(read_pairs(universe, config, true));
    }

    if let Some(config) = doc["bonds"].as_vec() {
        try!(read_pairs(universe, config, false));
    }

    if let Some(config) = doc["angles"].as_vec() {
        try!(read_angles(universe, config));
    }

    if let Some(config) = doc["dihedrals"].as_vec() {
        try!(read_dihedrals(universe, config));
    }

    Ok(())
}

/// Read the "pairs" or the "bonds" section in the file. If `pair_potentials`
/// is `true`, then the interactions are added to the pair interactions. Else,
/// the interaction are added to the bond interactions.
fn read_pairs(universe: &mut Universe, pairs: &Vec<Yaml>, pair_potentials: bool) -> Result<()> {
    for potential in pairs {
        let (a, b) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 2 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in pair potentials. Should be 2, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b)) = (vec[0].as_str(), vec[1].as_str()) {
                    (a, b)
                } else {
                    return Err(Error::from("The atoms names are not strings in pair potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in pair potential"));
            }
        };

        let potential = if potential["computation"].as_hash().is_some() {
            try!(read_pair_computation(potential))
        } else {
            try!(read_pair_potential(potential))
        };

        if pair_potentials {
            universe.add_pair_interaction(a, b, potential);
        } else {
            universe.add_bond_interaction(a, b, potential);
        }
    }
    Ok(())
}

fn read_pair_potential(node: &Yaml) -> Result<Box<PairPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from("Missing 'type' section in pair potential"))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "lennard-jones" | "lennardjones" => Ok(Box::new(try!(LennardJones::from_yaml(node)))),
                "null" | "nullpotential" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_angles(universe: &mut Universe, angles: &Vec<Yaml>) -> Result<()> {
    for potential in angles {
        let (a, b, c) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 3 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in angle potential. Should be 3, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str()) {
                    (a, b, c)
                } else {
                    return Err(Error::from("The atoms names are not strings in angle potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in angles potential"));
            }
        };

        let potential = try!(read_angle_potential(potential));
        universe.add_angle_interaction(a, b, c, potential);
    }
    Ok(())
}

fn read_angle_potential(node: &Yaml) -> Result<Box<AnglePotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_dihedrals(universe: &mut Universe, dihedrals: &Vec<Yaml>) -> Result<()> {
    for potential in dihedrals {
        let (a, b, c, d) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 4 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in dihedral potential. Should be 4, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c), Some(d)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str(), vec[3].as_str()) {
                    (a, b, c, d)
                } else {
                    return Err(Error::from("The atoms names are not strings in dihedral potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in dihedral potential"));
            }
        };

        let potential = try!(read_dihedral_potential(potential));
        universe.add_dihedral_interaction(a, b, c, d, potential);
    }
    Ok(())
}

fn read_dihedral_potential(node: &Yaml) -> Result<Box<DihedralPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

impl FromYaml for NullPotential {
    fn from_yaml(node: &Yaml) -> Result<NullPotential> {
        Ok(NullPotential)
    }
}

impl FromYaml for Harmonic {
    fn from_yaml(node: &Yaml) -> Result<Harmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(Harmonic{k: k, x0: x0})
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in harmonic potential")
            )
        }
    }
}

impl FromYaml for LennardJones {
    fn from_yaml(node: &Yaml) -> Result<LennardJones> {
        if let (Some(sigma), Some(epsilon)) = (node["sigma"].as_str(), node["epsilon"].as_str()) {
            let sigma = try!(::units::from_str(sigma));
            let epsilon = try!(::units::from_str(epsilon));
            Ok(LennardJones{sigma: sigma, epsilon: epsilon})
        } else {
            Err(
                Error::from("Missing 'sigma' or 'espilon' in Lennard-Jones potential")
            )
        }
    }
}

impl FromYaml for CosineHarmonic {
    fn from_yaml(node: &Yaml) -> Result<CosineHarmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(CosineHarmonic::new(k, x0))
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in cosine harmonic potential")
            )
        }
    }
}

/******************************************************************************/

fn read_pair_computation(node: &Yaml) -> Result<Box<PairPotential>> {
    let pot = try!(read_pair_potential(node));
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section for potential computation in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "cutoff" => Ok(Box::new(try!(CutoffComputation::from_yaml(node, pot)))),
                //"table" => Ok(Box::new(try!(TableComputation::from_yaml(node, pot)))),
                val => Err(
                    Error::from(format!("Unknown computation type '{}'", val))
                ),
            }
        }
    }
}

trait FromYamlWithPairPotential where Self: Sized {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<Self>;
}

impl FromYamlWithPairPotential for CutoffComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<CutoffComputation> {
        if let Some(cutoff) = node["cutoff"].as_str() {
            let cutoff = try!(::units::from_str(cutoff));
            Ok(CutoffComputation::new(potential, cutoff))
        } else {
            Err(
                Error::from("Missing 'cutoff' value in cutoff computation")
            )
        }
    }
}

impl FromYamlWithPairPotential for TableComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<TableComputation> {
        if let (Some(n), Some(max)) = (node["max"].as_i64(), node["max"].as_str()) {
            let max = try!(::units::from_str(max));
            Ok(TableComputation::new(potential, n as usize, max))
        } else {
            Err(
                Error::from("Missing 'cutoff' value in cutoff computation")
            )
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use uuid::Uuid;

pub struct JsType {
    uid: u64,
    t: Box<JsT>,
}

pub struct JsType {
    uid: Uuid,
    thing: Box<JsT>,
}

impl JsType {
    fn new(t: Box<JsT>) -> JsType {
        JsType {
            uid: Uuid::new_v4(),
            t: t,
        }
    }
}

impl PartialEq for JsType {
    fn eq(&self, other: &Self) -> bool {
        self.uid == other.uid
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsType{}

impl Hash for JsType {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.uid.hash(state);
    }

    fn hash_slice<H>(data: &[Self], state: &mut H) where H: Hasher {
        for ref d in data {
            d.uid.hash(state);
        }
    }
}

pub trait JsT {}
<commit_msg>Fix duplicate JsType definition:<commit_after>use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use uuid::Uuid;

pub struct JsType {
    uid: Uuid,
    t: Box<JsT>,
}

impl JsType {
    fn new(t: Box<JsT>) -> JsType {
        JsType {
            uid: Uuid::new_v4(),
            t: t,
        }
    }
}

impl PartialEq for JsType {
    fn eq(&self, other: &Self) -> bool {
        self.uid == other.uid
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsType{}

impl Hash for JsType {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.uid.hash(state);
    }

    fn hash_slice<H>(data: &[Self], state: &mut H) where H: Hasher {
        for ref d in data {
            d.uid.hash(state);
        }
    }
}

pub trait JsT {}
<|endoftext|>


<commit_before>//! Container types

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::{Geometry, Point, Size, ResizeEdge};

/// A handle to either a view or output
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

/// Types of containers
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A Container, houses views and other containers
    Container,
    /// A view (window)
    View
}

impl ContainerType {
    /// Whether this container can be used as the parent of another
    pub fn can_have_child(self, other: ContainerType) -> bool {
        use self::ContainerType::*;
        match self {
            Root => other == Output,
            Output => other == Workspace,
            Workspace => other == Container,
            Container => other == Container || other == View,
            View => false
        }
    }

    /// Whether this container can have a parent of type other
    #[allow(dead_code)]
    pub fn can_have_parent(self, other: ContainerType) -> bool {
        other.can_have_child(self)
    }
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Layout {
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Represents an item in the container tree.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Container {
    /// Root node of the container
    Root,
    /// Output
    Output {
        /// Handle to the wlc
        handle: WlcOutput,
        /// Whether the output is focused
        focused: bool
    },
    /// Workspace
    Workspace {
        /// Name of the workspace
        name: String,
        /// Whether the workspace is focused
        ///
        /// Multiple workspaces can be focused
        focused: bool,
        /// The size of the workspace on the screen.
        /// Might be different if there is e.g a bar present
        size: Size,
    },
    /// Container
    Container {
        /// How the container is layed out
        layout: Layout,
        /// If the container is focused
        focused: bool,
        /// If the container is floating
        floating: bool,
        /// The geometry of the container, relative to the parent container
        geometry: Geometry,
    },
    /// View or window
    View {
        /// The wlc handle to the view
        handle: WlcView,
        /// Whether this view is focused
        focused: bool,
        /// Whether this view is floating
        floating: bool,
    }
}

impl Container {
    /// Creates a new output container with the given output
    pub fn new_output(handle: WlcOutput) -> Container {
        Container::Output {
            handle: handle,
            focused: false
        }
    }

    /// Creates a new workspace container with the given name and size.
    /// Usually the size is the same as the output it resides on,
    /// unless there is a bar or something.
    pub fn new_workspace(name: String, size: Size) -> Container {
        Container::Workspace {
            name: name, focused: false, size: size
        }
    }

    /// Creates a new container
    pub fn new_container(geometry: Geometry) -> Container {
        Container::Container {
            layout: Layout::Horizontal,
            focused: false,
            floating: false,
            geometry: geometry
        }
    }

    /// Creates a new view container with the given handle
    pub fn new_view(handle: WlcView) -> Container {
        Container::View {
            handle: handle,
            focused: false,
            floating: false
        }
    }

    /// Sets the visibility of this container
    pub fn set_visibility(&mut self, visibility: bool) {
        let mask = if visibility { 1 } else { 0 };
        if let Some(handle) = self.get_handle() {
            match handle {
                Handle::View(view) => {
                    view.set_mask(mask)
                },
                _ => {},
            }
        }
    }

    /// Gets the type of this container
    pub fn get_type(&self) -> ContainerType {
        match *self {
            Container::Root => ContainerType::Root,
            Container::Output { .. } => ContainerType::Output,
            Container::Workspace { .. } => ContainerType::Workspace,
            Container::Container { .. } => ContainerType::Container,
            Container::View { .. } => ContainerType::View
        }
    }

    /// Gets the view handle of the view container, if this is a view container
    pub fn get_handle(&self) -> Option<Handle> {
        match *self {
            Container::View { ref handle, ..} => Some(Handle::View(handle.clone())),
            Container::Output { ref handle, .. } => Some(Handle::Output(handle.clone())),
            _ => None
        }
    }

    /// Gets the name of the workspace, if this container is a workspace.
    pub fn get_name(&self) -> Option<&str> {
        match *self {
            Container::Workspace { ref name, ..} => Some(name),
            _ => None
        }
    }

    /// Determines if the container is focused or not
    #[allow(dead_code)]
    pub fn is_focused(&self) -> bool {
        match *self {
            Container::Output { ref focused, .. } => focused.clone(),
            Container::Workspace { ref focused, .. } => focused.clone(),
            Container::View { ref focused, .. } => focused.clone(),
            _ => false
        }
    }

    /// Gets the geometry of the container, if the container has one.
    /// Root: Returns None
    /// Workspace/Output: Size is the size of the screen, origin is just 0,0
    /// Container/View: Size is the size of the container,
    /// origin is the coordinates relative to the parent container.
    pub fn get_geometry(&self) -> Option<Geometry> {
        match *self {
            Container::Root { .. } => None,
            Container::Output { ref handle, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0 },
                size: handle.get_resolution().clone(),
            }),
            Container::Workspace { ref size, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0},
                size: size.clone()
            }),
            Container::Container { ref geometry, .. } => Some(geometry.clone()),
            Container::View { ref handle, ..} => {
                match handle.get_geometry() {
                    Some(geometry) => Some(geometry.clone()),
                    _ => None
                }
            },
        }
    }

    /// Sets the geometry of the container, if it supports that operation.
    /// Only Views, Containers, and Workspaces support this operation,
    /// all others will return an Err with an appropriate error message.
    ///
    /// If setting a workspace, only the size of the geometry is set.
    #[allow(dead_code)]
    pub fn set_geometry(&mut self, new_geometry: Geometry) -> Result<(), String> {
        match *self {
            Container::Workspace { ref mut size, .. } => *size = new_geometry.size,
            Container::Container { ref mut geometry, .. } => *geometry = new_geometry,
            Container::View { ref handle, .. } =>
                handle.set_geometry(ResizeEdge::empty(), &new_geometry),
            _ => { return Err(format!("Could not set geometry on {:?}", self))}
        };
        return Ok(())
    }

    pub fn set_layout(&mut self, new_layout: Layout) -> Result<(), String>{
        match *self {
            Container::Container { ref mut layout, .. } => *layout = new_layout,
            ref other => return Err(
                format!("Can only set the layout of a container, not {:?}",
                        other))
        }
        Ok(())
    }
}

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

    #[test]
    fn can_have_child() {
        let root = ContainerType::Root;
        let output = ContainerType::Output;
        let workspace = ContainerType::Workspace;
        let container = ContainerType::Container;
        let view = ContainerType::View;

        assert!(root.can_have_child(output),         "Root      > output");
        assert!(output.can_have_child(workspace),    "Output    > workspace");
        assert!(workspace.can_have_child(container), "Workspace > container");
        assert!(container.can_have_child(container), "Container > container");
        assert!(container.can_have_child(view),      "Container > view");

        assert!(!root.can_have_child(root),      "! Root > root");
        assert!(!root.can_have_child(workspace), "! Root > workspace");
        assert!(!root.can_have_child(container), "! Root > container");
        assert!(!root.can_have_child(view),      "! Root > view");

        assert!(!output.can_have_child(root),      "! Output > root");
        assert!(!output.can_have_child(output),    "! Output > output");
        assert!(!output.can_have_child(container), "! Output > container");
        assert!(!output.can_have_child(view),      "! Output > view");

        assert!(!workspace.can_have_child(root),      "! Workspace > root");
        assert!(!workspace.can_have_child(output),    "! Workspace > output");
        assert!(!workspace.can_have_child(workspace), "! Workspace > worksp");
        assert!(!workspace.can_have_child(view),      "! Workspace > view");

        assert!(!container.can_have_child(root),      "! Container > root");
        assert!(!container.can_have_child(workspace), "! Container > worksp");
        assert!(!container.can_have_child(output),    "! Container > contanr");

        assert!(!view.can_have_child(root),      "! View > root");
        assert!(!view.can_have_child(output),    "! View > output");
        assert!(!view.can_have_child(workspace), "! View > workspace");
        assert!(!view.can_have_child(container), "! View > container");
        assert!(!view.can_have_child(view),      "! View > view");
    }

    #[test]
    /// Tests set and get geometry
    fn geometry_test() {
        use rustwlc::*;
        let test_geometry1 = Geometry {
            origin: Point { x: 800, y: 600 },
            size: Size { w: 500, h: 500}
        };
        let test_geometry2 = Geometry {
            origin: Point { x: 1024, y: 2048},
            size: Size { w: 500, h: 700}
        };
        let mut root = Container::Root;
        assert!(root.get_geometry().is_none());
        assert!(root.set_geometry(test_geometry1.clone()).is_err());

        let mut output = Container::new_output(WlcView::root().as_output());
        // NOTE Segfaults, because tries to get the geometry from dummy Wlc output
        //assert!(output.get_geometry().is_none());
        assert!(output.set_geometry(test_geometry1.clone()).is_err());

        let mut workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        assert_eq!(workspace.get_geometry(), Some(Geometry {
            size: Size { w: 500, h: 500},
            origin: Point { x: 0, y: 0}
        }));
        workspace.set_geometry(test_geometry1.clone())
            .expect("Can't set geometry on workspace");
        // Workspace only grabs the Size, so point will be 0 0.
        let workspace_geometry = Geometry {
            size: test_geometry1.size.clone(),
            origin: Point { x: 0, y: 0}
        };
        assert_eq!(workspace.get_geometry(), Some(workspace_geometry.clone()));

        let mut container = Container::new_container(test_geometry1.clone());
        assert_eq!(container.get_geometry(), Some(test_geometry1.clone()));
        container.set_geometry(test_geometry2.clone())
            .expect("Could not set geometry on container");
        assert_eq!(container.get_geometry(), Some(test_geometry2.clone()));

        // NOTE Can't test view, because that will just segfault as well
        //let mut view = Container::new_view(WlcView::root());
    }

    #[test]
    fn layout_change_test() {
        use rustwlc::*;
        let root = Container::Root;
        let output = Container::new_output(WlcView::root().as_output());
        let workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        let mut container = Container::new_container(Geometry {
            origin: Point { x: 0, y: 0},
            size: Size { w: 0, h:0}
        });
        let view = Container::new_view(WlcView::root());

        /* Container first, the only thing we can set the layout on */
        let layout = match container {
            Container::Container { ref layout, .. } => layout.clone(),
            _ => panic!()
        };
        assert_eq!(layout, Layout::Horizontal);
        let layouts = [Layout::Vertical, Layout::Horizontal,
                       Layout::Tabbed, Layout::Stacked];
        for new_layout in &layouts {
            container.set_layout(*new_layout).ok();
            let layout = match container {
                Container::Container { ref layout, .. } => layout.clone(),
                _ => panic!()
            };
            assert_eq!(layout, *new_layout);
        }

        for new_layout in &layouts {
            for container in &mut [root.clone(), output.clone(),
                                   workspace.clone(), view.clone()] {
                let result = container.set_layout(*new_layout);
                assert!(result.is_err());
            }
        }

    }
}
<commit_msg>is_focused test, fixed is_focus<commit_after>//! Container types

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::{Geometry, Point, Size, ResizeEdge};

/// A handle to either a view or output
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

/// Types of containers
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A Container, houses views and other containers
    Container,
    /// A view (window)
    View
}

impl ContainerType {
    /// Whether this container can be used as the parent of another
    pub fn can_have_child(self, other: ContainerType) -> bool {
        use self::ContainerType::*;
        match self {
            Root => other == Output,
            Output => other == Workspace,
            Workspace => other == Container,
            Container => other == Container || other == View,
            View => false
        }
    }

    /// Whether this container can have a parent of type other
    #[allow(dead_code)]
    pub fn can_have_parent(self, other: ContainerType) -> bool {
        other.can_have_child(self)
    }
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Layout {
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Represents an item in the container tree.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Container {
    /// Root node of the container
    Root,
    /// Output
    Output {
        /// Handle to the wlc
        handle: WlcOutput,
        /// Whether the output is focused
        focused: bool
    },
    /// Workspace
    Workspace {
        /// Name of the workspace
        name: String,
        /// Whether the workspace is focused
        ///
        /// Multiple workspaces can be focused
        focused: bool,
        /// The size of the workspace on the screen.
        /// Might be different if there is e.g a bar present
        size: Size,
    },
    /// Container
    Container {
        /// How the container is layed out
        layout: Layout,
        /// If the container is focused
        focused: bool,
        /// If the container is floating
        floating: bool,
        /// The geometry of the container, relative to the parent container
        geometry: Geometry,
    },
    /// View or window
    View {
        /// The wlc handle to the view
        handle: WlcView,
        /// Whether this view is focused
        focused: bool,
        /// Whether this view is floating
        floating: bool,
    }
}

impl Container {
    /// Creates a new output container with the given output
    pub fn new_output(handle: WlcOutput) -> Container {
        Container::Output {
            handle: handle,
            focused: false
        }
    }

    /// Creates a new workspace container with the given name and size.
    /// Usually the size is the same as the output it resides on,
    /// unless there is a bar or something.
    pub fn new_workspace(name: String, size: Size) -> Container {
        Container::Workspace {
            name: name, focused: false, size: size
        }
    }

    /// Creates a new container
    pub fn new_container(geometry: Geometry) -> Container {
        Container::Container {
            layout: Layout::Horizontal,
            focused: false,
            floating: false,
            geometry: geometry
        }
    }

    /// Creates a new view container with the given handle
    pub fn new_view(handle: WlcView) -> Container {
        Container::View {
            handle: handle,
            focused: false,
            floating: false
        }
    }

    /// Sets the visibility of this container
    pub fn set_visibility(&mut self, visibility: bool) {
        let mask = if visibility { 1 } else { 0 };
        if let Some(handle) = self.get_handle() {
            match handle {
                Handle::View(view) => {
                    view.set_mask(mask)
                },
                _ => {},
            }
        }
    }

    /// Gets the type of this container
    pub fn get_type(&self) -> ContainerType {
        match *self {
            Container::Root => ContainerType::Root,
            Container::Output { .. } => ContainerType::Output,
            Container::Workspace { .. } => ContainerType::Workspace,
            Container::Container { .. } => ContainerType::Container,
            Container::View { .. } => ContainerType::View
        }
    }

    /// Gets the view handle of the view container, if this is a view container
    pub fn get_handle(&self) -> Option<Handle> {
        match *self {
            Container::View { ref handle, ..} => Some(Handle::View(handle.clone())),
            Container::Output { ref handle, .. } => Some(Handle::Output(handle.clone())),
            _ => None
        }
    }

    /// Gets the name of the workspace, if this container is a workspace.
    pub fn get_name(&self) -> Option<&str> {
        match *self {
            Container::Workspace { ref name, ..} => Some(name),
            _ => None
        }
    }

    /// Determines if the container is focused or not
    #[allow(dead_code)]
    pub fn is_focused(&self) -> bool {
        match *self {
            Container::Root { .. } => false,
            Container::Output { ref focused, .. } => *focused,
            Container::Workspace { ref focused, .. } => *focused,
            Container::Container { ref focused, .. } => *focused,
            Container::View { ref focused, .. } =>*focused,
        }
    }

    /// Gets the geometry of the container, if the container has one.
    /// Root: Returns None
    /// Workspace/Output: Size is the size of the screen, origin is just 0,0
    /// Container/View: Size is the size of the container,
    /// origin is the coordinates relative to the parent container.
    pub fn get_geometry(&self) -> Option<Geometry> {
        match *self {
            Container::Root { .. } => None,
            Container::Output { ref handle, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0 },
                size: handle.get_resolution().clone(),
            }),
            Container::Workspace { ref size, .. } => Some(Geometry {
                origin: Point { x: 0, y: 0},
                size: size.clone()
            }),
            Container::Container { ref geometry, .. } => Some(geometry.clone()),
            Container::View { ref handle, ..} => {
                match handle.get_geometry() {
                    Some(geometry) => Some(geometry.clone()),
                    _ => None
                }
            },
        }
    }

    /// Sets the geometry of the container, if it supports that operation.
    /// Only Views, Containers, and Workspaces support this operation,
    /// all others will return an Err with an appropriate error message.
    ///
    /// If setting a workspace, only the size of the geometry is set.
    #[allow(dead_code)]
    pub fn set_geometry(&mut self, new_geometry: Geometry) -> Result<(), String> {
        match *self {
            Container::Workspace { ref mut size, .. } => *size = new_geometry.size,
            Container::Container { ref mut geometry, .. } => *geometry = new_geometry,
            Container::View { ref handle, .. } =>
                handle.set_geometry(ResizeEdge::empty(), &new_geometry),
            _ => { return Err(format!("Could not set geometry on {:?}", self))}
        };
        return Ok(())
    }

    pub fn set_layout(&mut self, new_layout: Layout) -> Result<(), String>{
        match *self {
            Container::Container { ref mut layout, .. } => *layout = new_layout,
            ref other => return Err(
                format!("Can only set the layout of a container, not {:?}",
                        other))
        }
        Ok(())
    }
}

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

    #[test]
    fn can_have_child() {
        let root = ContainerType::Root;
        let output = ContainerType::Output;
        let workspace = ContainerType::Workspace;
        let container = ContainerType::Container;
        let view = ContainerType::View;

        assert!(root.can_have_child(output),         "Root      > output");
        assert!(output.can_have_child(workspace),    "Output    > workspace");
        assert!(workspace.can_have_child(container), "Workspace > container");
        assert!(container.can_have_child(container), "Container > container");
        assert!(container.can_have_child(view),      "Container > view");

        assert!(!root.can_have_child(root),      "! Root > root");
        assert!(!root.can_have_child(workspace), "! Root > workspace");
        assert!(!root.can_have_child(container), "! Root > container");
        assert!(!root.can_have_child(view),      "! Root > view");

        assert!(!output.can_have_child(root),      "! Output > root");
        assert!(!output.can_have_child(output),    "! Output > output");
        assert!(!output.can_have_child(container), "! Output > container");
        assert!(!output.can_have_child(view),      "! Output > view");

        assert!(!workspace.can_have_child(root),      "! Workspace > root");
        assert!(!workspace.can_have_child(output),    "! Workspace > output");
        assert!(!workspace.can_have_child(workspace), "! Workspace > worksp");
        assert!(!workspace.can_have_child(view),      "! Workspace > view");

        assert!(!container.can_have_child(root),      "! Container > root");
        assert!(!container.can_have_child(workspace), "! Container > worksp");
        assert!(!container.can_have_child(output),    "! Container > contanr");

        assert!(!view.can_have_child(root),      "! View > root");
        assert!(!view.can_have_child(output),    "! View > output");
        assert!(!view.can_have_child(workspace), "! View > workspace");
        assert!(!view.can_have_child(container), "! View > container");
        assert!(!view.can_have_child(view),      "! View > view");
    }

    #[test]
    /// Tests set and get geometry
    fn geometry_test() {
        use rustwlc::*;
        let test_geometry1 = Geometry {
            origin: Point { x: 800, y: 600 },
            size: Size { w: 500, h: 500}
        };
        let test_geometry2 = Geometry {
            origin: Point { x: 1024, y: 2048},
            size: Size { w: 500, h: 700}
        };
        let mut root = Container::Root;
        assert!(root.get_geometry().is_none());
        assert!(root.set_geometry(test_geometry1.clone()).is_err());

        let mut output = Container::new_output(WlcView::root().as_output());
        // NOTE Segfaults, because tries to get the geometry from dummy Wlc output
        //assert!(output.get_geometry().is_none());
        assert!(output.set_geometry(test_geometry1.clone()).is_err());

        let mut workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        assert_eq!(workspace.get_geometry(), Some(Geometry {
            size: Size { w: 500, h: 500},
            origin: Point { x: 0, y: 0}
        }));
        workspace.set_geometry(test_geometry1.clone())
            .expect("Can't set geometry on workspace");
        // Workspace only grabs the Size, so point will be 0 0.
        let workspace_geometry = Geometry {
            size: test_geometry1.size.clone(),
            origin: Point { x: 0, y: 0}
        };
        assert_eq!(workspace.get_geometry(), Some(workspace_geometry.clone()));

        let mut container = Container::new_container(test_geometry1.clone());
        assert_eq!(container.get_geometry(), Some(test_geometry1.clone()));
        container.set_geometry(test_geometry2.clone())
            .expect("Could not set geometry on container");
        assert_eq!(container.get_geometry(), Some(test_geometry2.clone()));

        // NOTE Can't test view, because that will just segfault as well
        //let mut view = Container::new_view(WlcView::root());
    }

    #[test]
    fn layout_change_test() {
        let root = Container::Root;
        let output = Container::new_output(WlcView::root().as_output());
        let workspace = Container::new_workspace("1".to_string(),
                                                     Size { w: 500, h: 500 });
        let mut container = Container::new_container(Geometry {
            origin: Point { x: 0, y: 0},
            size: Size { w: 0, h:0}
        });
        let view = Container::new_view(WlcView::root());

        /* Container first, the only thing we can set the layout on */
        let layout = match container {
            Container::Container { ref layout, .. } => layout.clone(),
            _ => panic!()
        };
        assert_eq!(layout, Layout::Horizontal);
        let layouts = [Layout::Vertical, Layout::Horizontal,
                       Layout::Tabbed, Layout::Stacked];
        for new_layout in &layouts {
            container.set_layout(*new_layout).ok();
            let layout = match container {
                Container::Container { ref layout, .. } => layout.clone(),
                _ => panic!()
            };
            assert_eq!(layout, *new_layout);
        }

        for new_layout in &layouts {
            for container in &mut [root.clone(), output.clone(),
                                   workspace.clone(), view.clone()] {
                let result = container.set_layout(*new_layout);
                assert!(result.is_err());
            }
        }
    }

    #[test]
    fn is_focused_test() {
        let root = Container::Root;
        let output = Container::new_output(WlcView::root().as_output());
        let workspace = Container::new_workspace("1".to_string(),
                                                 Size { w: 500, h: 500 });
        let container = Container::new_container(Geometry {
            origin: Point { x: 0, y: 0},
            size: Size { w: 0, h:0}
        });
        let view = Container::new_view(WlcView::root());
        for container in &mut [root.clone(), output.clone(),
                               container.clone(),
                               workspace.clone(), view.clone()] {
            assert_eq!(container.is_focused(), false);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate mio;

use helper::Log;

use self::mio::tcp::TcpListener;
use self::mio::{Ready, PollOpt, Token};
use self::mio::channel::Sender;

use node::{Node, NET_TCP_SERVER_TOKEN};
use network::{CONNECTION_COUNT_PRE_ALLOC, TcpConnection
              , Connection, Networking
              , TcpHandlerCommand, TcpHandlerCMD};
use helper::NetHelper;

use std::net::SocketAddr;
use std::error::Error;
use std::process;
use std::str::FromStr;
use std::io::ErrorKind;
use std::sync::Arc;

/// TcpNetwork Trait for implementing TCP networking capabilities
/// On top of Node structure
pub trait TcpNetwork {
    /// Min function to attach TCP service functionality to existing POLL service
    fn register_tcp(&mut self);

    /// Make TCP server socket listener from given address
    fn make_tcp_server(address: &str) -> TcpListener;

    /// Handler for event loop ready event
    /// This is general event processing for TCP connections/servers
    /// If event token not in the TCP list it will return false
    /// To let other components to handle event
    fn tcp_ready(&mut self, token: Token, event_kind: Ready) -> bool;

    /// Function for accepting TCP connections as a pending connections
    fn tcp_acceptable(&mut self);

    /// Function for reading TCP data from pending connections
    fn tcp_readable(&mut self, token: Token);
    /// Function for writing TCP data from pending connections
    fn tcp_writable(&mut self, token: Token);
    /// closing TCP connection
    fn tcp_close(&mut self, token: Token);
    /// getting one of the TCP handler channels
    /// using Round Rubin algorithm
    fn tcp_get_handler(&mut self) -> Sender<TcpHandlerCommand>;
}

impl TcpNetwork for Node {
    fn register_tcp(&mut self) {
        match self.poll.register(&self.net_tcp_server, NET_TCP_SERVER_TOKEN, Ready::readable(), PollOpt::edge()) {
            Ok(_) => {}
            Err(e) => {
                Log::error("Unable to register TCP server to Node POLL service", e.description());
                process::exit(1);
            }
        }
    }

    fn make_tcp_server(address: &str) -> TcpListener {
        let addr = match SocketAddr::from_str(address) {
            Ok(a) => a,
            Err(e) => {
                Log::error("Unable to parse given TCP server address", e.description());
                process::exit(1);
            }
        };

        match TcpListener::bind(&addr) {
            Ok(s) => s,
            Err(e) => {
                Log::error("Unable to bind given TCP server address", e.description());
                process::exit(1);
            }
        }
    }

    #[inline(always)]
    fn tcp_ready(&mut self, token: Token, event_kind: Ready) -> bool {
        if token == NET_TCP_SERVER_TOKEN {
            if event_kind != Ready::readable() {
                Log::error("Unexpected TCP Server event kind", "Ignoring for now!");
                return false;
            }

            self.tcp_acceptable();
            return true;
        }

        if self.net_tcp_pending_connections.contains(token) {
            if event_kind == Ready::readable() {

                self.tcp_readable(token);

            } else if event_kind == Ready::writable() {

                self.tcp_writable(token);

            } else if event_kind == Ready::error()
                || event_kind == Ready::hup() {

                self.tcp_close(token);

            }

            return true;
        }

        false
    }

    #[inline(always)]
    fn tcp_acceptable(&mut self) {
        loop {
            let sock = match self.net_tcp_server.accept() {
                Ok((s, _)) => s,
                Err(e) => {
                    // if we got WouldBlock, then this is Non Blocking socket
                    // and data still not available for this, so it's not a connection error
                    if e.kind() != ErrorKind::WouldBlock {
                        Log::error("Unable to accept connection from TCP server socket", e.description());
                    }
                    return;
                }
            };

            // inserting connection to pending connections and registering to the loop
            if self.net_tcp_pending_connections.vacant_entry().is_none() {
                self.net_tcp_pending_connections.reserve_exact(CONNECTION_COUNT_PRE_ALLOC);
            }

            let entry = match self.net_tcp_pending_connections.vacant_entry() {
                Some(e) => e,
                None => {
                    Log::error("Unable to insert accepted connection to TcpNetwork pending connections"
                               , "Not enough place in Slab");
                    return;
                }
            };

            // creating connection and registering to current Node poll service
            let conn = TcpConnection::new(sock, entry.index(), true);
            conn.register(&self.poll);
            entry.insert(conn);
        };
    }

    #[inline(always)]
    fn tcp_readable(&mut self, token: Token) {
        // if we got here then we have connection with this token
        let mut close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            // if we don't have yet API version defined
            if !Connection::check_api_version(conn.api_version) {
                match conn.read_api_version() {
                    Some((done, version)) => {
                        // if we not done with reading API version
                        // Just returning and waiting until next readable cycle
                        if !done {
                            return;
                        }

                        // if we got wrong API version just closing connection
                        if !Connection::check_api_version(version) {
                            true
                        } else {
                            // if we got valid API version
                            // saving it as a connection version
                            conn.api_version = version;
                            false
                        }
                    }

                    // if we have connection error closing it
                    None => true
                }
            } else {
                false
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            // reading Connection Token and Value
            match conn.read_token_value() {
                Some((done, token_str, value)) => {
                    // if we not done with reading API version
                    // Just returning and waiting until next readable cycle
                    if !done {
                        return;
                    }

                    // checking if we got valid Prime Value or not
                    // if it's invalid just closing connection
                    if !NetHelper::validate_value(value) {
                        true
                    } else {
                        // if we done with token and value
                        // just setting them for connection
                        // and writing API handshake information
                        conn.conn_token = token_str;
                        conn.conn_value = value;

                        false
                    }
                }

                // if we have connection error closing it
                None => true
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        // if we got here then we have connection information
        // so now we need to send our handshake information
        // and after write will succeed, we will transfer connection
        // to one of the TCP handlers
        let info = Arc::new(self.handshake_info());
        self.net_tcp_pending_connections[token].write(info, &self.poll);
    }

    #[inline(always)]
    fn tcp_writable(&mut self, token: Token) {
        // if we got here then we have connection with this token
        let close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            match conn.flush() {
                Some(done) => {
                    // if Write queue is not empty, just returning
                    // and waiting for the next cycle
                    if !done {
                        return;
                    }

                    // letting know to keep connection
                    // so that we can make sure that queue is empty
                    false
                }

                // closing connection if we have write error
                None => true
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        // if we got here then write is done
        // so moving connection to one of the TCP handlers
        let mut command = TcpHandlerCommand::new();
        // removing connection from pending connections list
        let conn = self.net_tcp_pending_connections.remove(token).unwrap();
        // de-registering from current event loop
        let _ = self.poll.deregister(&conn.socket);

        command.cmd = TcpHandlerCMD::HandleConnection;
        command.conn.push(conn);
        match self.tcp_get_handler().send(command) {
            Ok(_) => {},
            Err(e) => {
                Log::error("Unable to send HandleConnection command to TCP handler", e.description());
                return;
            }
        }
    }

    #[inline(always)]
    fn tcp_close(&mut self, token: Token) {
        // just removing connection
        // it would be closed automatically when
        // connection object de-allocated from memory
        self.net_tcp_pending_connections.remove(token);
    }

    #[inline(always)]
    fn tcp_get_handler(&mut self) -> Sender<TcpHandlerCommand> {
        if self.net_tcp_handler_index >= self.net_tcp_handler_sender_chan.len() {
            self.net_tcp_handler_index = 0;
        }

        let i = self.net_tcp_handler_index;
        self.net_tcp_handler_index += 1;

        self.net_tcp_handler_sender_chan[i].clone()
    }
}

<commit_msg>adding TCP client connection functionality<commit_after>#![allow(dead_code)]
extern crate mio;

use helper::Log;

use self::mio::tcp::{TcpListener, TcpStream};
use self::mio::{Ready, PollOpt, Token};
use self::mio::channel::Sender;

use node::{Node, NET_TCP_SERVER_TOKEN};
use network::{CONNECTION_COUNT_PRE_ALLOC, TcpConnection
              , Connection, Networking
              , TcpHandlerCommand, TcpHandlerCMD};
use helper::NetHelper;

use std::net::SocketAddr;
use std::error::Error;
use std::process;
use std::str::FromStr;
use std::io::ErrorKind;
use std::sync::Arc;

/// TcpNetwork Trait for implementing TCP networking capabilities
/// On top of Node structure
pub trait TcpNetwork {
    /// Min function to attach TCP service functionality to existing POLL service
    fn register_tcp(&mut self);

    /// Make TCP server socket listener from given address
    fn make_tcp_server(address: &str) -> TcpListener;

    /// Handler for event loop ready event
    /// This is general event processing for TCP connections/servers
    /// If event token not in the TCP list it will return false
    /// To let other components to handle event
    fn tcp_ready(&mut self, token: Token, event_kind: Ready) -> bool;

    /// Function for accepting TCP connections as a pending connections
    fn tcp_acceptable(&mut self);

    /// Function for reading TCP data from pending connections
    fn tcp_readable(&mut self, token: Token);

    /// Function for writing TCP data from pending connections
    fn tcp_writable(&mut self, token: Token);

    /// closing TCP connection
    fn tcp_close(&mut self, token: Token);

    /// getting one of the TCP handler channels
    /// using Round Rubin algorithm
    fn tcp_get_handler(&mut self) -> Sender<TcpHandlerCommand>;

    /// making client connection to given address
    fn tcp_connect(&mut self, address: &str) -> bool;

    /// Inserting connection socket
    fn add_connection(&mut self, socket: TcpStream, from_server: bool);
}

impl TcpNetwork for Node {
    fn register_tcp(&mut self) {
        match self.poll.register(&self.net_tcp_server, NET_TCP_SERVER_TOKEN, Ready::readable(), PollOpt::edge()) {
            Ok(_) => {}
            Err(e) => {
                Log::error("Unable to register TCP server to Node POLL service", e.description());
                process::exit(1);
            }
        }
    }

    fn make_tcp_server(address: &str) -> TcpListener {
        let addr = match SocketAddr::from_str(address) {
            Ok(a) => a,
            Err(e) => {
                Log::error("Unable to parse given TCP server address", e.description());
                process::exit(1);
            }
        };

        match TcpListener::bind(&addr) {
            Ok(s) => s,
            Err(e) => {
                Log::error("Unable to bind given TCP server address", e.description());
                process::exit(1);
            }
        }
    }

    #[inline(always)]
    fn tcp_ready(&mut self, token: Token, event_kind: Ready) -> bool {
        if token == NET_TCP_SERVER_TOKEN {
            if event_kind != Ready::readable() {
                Log::error("Unexpected TCP Server event kind", "Ignoring for now!");
                return false;
            }

            self.tcp_acceptable();
            return true;
        }

        if self.net_tcp_pending_connections.contains(token) {
            if event_kind == Ready::readable() {

                self.tcp_readable(token);

            } else if event_kind == Ready::writable() {

                self.tcp_writable(token);

            } else if event_kind == Ready::error()
                || event_kind == Ready::hup() {

                self.tcp_close(token);

            }

            return true;
        }

        false
    }

    #[inline(always)]
    fn tcp_acceptable(&mut self) {
        loop {
            let sock = match self.net_tcp_server.accept() {
                Ok((s, _)) => s,
                Err(e) => {
                    // if we got WouldBlock, then this is Non Blocking socket
                    // and data still not available for this, so it's not a connection error
                    if e.kind() != ErrorKind::WouldBlock {
                        Log::error("Unable to accept connection from TCP server socket", e.description());
                    }
                    return;
                }
            };

            self.add_connection(sock, true);
        };
    }

    #[inline(always)]
    fn tcp_readable(&mut self, token: Token) {
        // if we got here then we have connection with this token
        let mut close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            // if we don't have yet API version defined
            if !Connection::check_api_version(conn.api_version) {
                match conn.read_api_version() {
                    Some((done, version)) => {
                        // if we not done with reading API version
                        // Just returning and waiting until next readable cycle
                        if !done {
                            return;
                        }

                        // if we got wrong API version just closing connection
                        if !Connection::check_api_version(version) {
                            true
                        } else {
                            // if we got valid API version
                            // saving it as a connection version
                            conn.api_version = version;
                            false
                        }
                    }

                    // if we have connection error closing it
                    None => true
                }
            } else {
                false
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            // reading Connection Token and Value
            match conn.read_token_value() {
                Some((done, token_str, value)) => {
                    // if we not done with reading API version
                    // Just returning and waiting until next readable cycle
                    if !done {
                        return;
                    }

                    // checking if we got valid Prime Value or not
                    // if it's invalid just closing connection
                    if !NetHelper::validate_value(value) {
                        true
                    } else {
                        // if we done with token and value
                        // just setting them for connection
                        // and writing API handshake information
                        conn.conn_token = token_str;
                        conn.conn_value = value;

                        false
                    }
                }

                // if we have connection error closing it
                None => true
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        // if we got here then we have connection information
        // so now we need to send our handshake information
        // and after write will succeed, we will transfer connection
        // to one of the TCP handlers
        let info = Arc::new(self.handshake_info());
        self.net_tcp_pending_connections[token].write(info, &self.poll);
    }

    #[inline(always)]
    fn tcp_writable(&mut self, token: Token) {
        // if we got here then we have connection with this token
        let close_conn = {
            let ref mut conn: TcpConnection = self.net_tcp_pending_connections[token];
            match conn.flush() {
                Some(done) => {
                    // if Write queue is not empty, just returning
                    // and waiting for the next cycle
                    if !done {
                        return;
                    }

                    // letting know to keep connection
                    // so that we can make sure that queue is empty
                    false
                }

                // closing connection if we have write error
                None => true
            }
        };

        if close_conn {
            self.tcp_close(token);
            return;
        }

        // if we got here then write is done
        // so moving connection to one of the TCP handlers
        let mut command = TcpHandlerCommand::new();
        // removing connection from pending connections list
        let conn = self.net_tcp_pending_connections.remove(token).unwrap();
        // de-registering from current event loop
        let _ = self.poll.deregister(&conn.socket);

        command.cmd = TcpHandlerCMD::HandleConnection;
        command.conn.push(conn);
        match self.tcp_get_handler().send(command) {
            Ok(_) => {},
            Err(e) => {
                Log::error("Unable to send HandleConnection command to TCP handler", e.description());
                return;
            }
        }
    }

    #[inline(always)]
    fn tcp_close(&mut self, token: Token) {
        // just removing connection
        // it would be closed automatically when
        // connection object de-allocated from memory
        self.net_tcp_pending_connections.remove(token);
    }

    #[inline(always)]
    fn tcp_get_handler(&mut self) -> Sender<TcpHandlerCommand> {
        if self.net_tcp_handler_index >= self.net_tcp_handler_sender_chan.len() {
            self.net_tcp_handler_index = 0;
        }

        let i = self.net_tcp_handler_index;
        self.net_tcp_handler_index += 1;

        self.net_tcp_handler_sender_chan[i].clone()
    }

    #[inline(always)]
    fn tcp_connect(&mut self, address: &str) -> bool {
        let sock_address = match SocketAddr::from_str(address) {
            Ok(a) => a,
            Err(e) => {
                Log::error(format!("Unable to parse address for making connection to TCP server {}", address).as_str(), e.description());
                return false;
            }
        };

        let sock = match TcpStream::connect(&sock_address) {
            Ok(s) => s,
            Err(e) => {
                Log::error(format!("Unable to connect with given tcp address {}", address).as_str(), e.description());
                return false;
            }
        };

        self.add_connection(sock, false);
        true
    }

    #[inline(always)]
    fn add_connection(&mut self, socket: TcpStream, from_server: bool) {
        // inserting connection to pending connections and registering to the loop
        if self.net_tcp_pending_connections.vacant_entry().is_none() {
            self.net_tcp_pending_connections.reserve_exact(CONNECTION_COUNT_PRE_ALLOC);
        }

        let data = Arc::new(self.handshake_info());

        let entry = match self.net_tcp_pending_connections.vacant_entry() {
            Some(e) => e,
            None => {
                Log::error("Unable to insert accepted connection to TcpNetwork pending connections"
                           , "Not enough place in Slab");
                return;
            }
        };

        // creating connection and registering to current Node poll service
        let mut conn = TcpConnection::new(socket, entry.index(), true);
        conn.register(&self.poll);
        if !from_server {
            conn.write(data, &self.poll);
        }
        entry.insert(conn);
    }
}

<|endoftext|>