<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;
use std::cmp::min;

use freetype::{self, Library, Face};

pub mod fc;

use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    keys: HashMap<::std::path::PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let size_metrics = face.size_metrics()
            .ok_or(Error::MissingSizeMetrics)?;

        let width = (size_metrics.max_advance / 64) as f64;
        let height = (size_metrics.height / 64) as f64;
        let descent = (size_metrics.descender / 64) as f32;

        Ok(Metrics {
            average_advance: width,
            line_height: height,
            descent: descent,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = self.get_face(desc)?;
        let key = FontKey::next();
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key, false)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
            println!("got font path={:?}", path);
            Ok(self.library.new_face(path, index)?)
        }
        else {
            Err(Error::MissingFont(desc.to_owned()))
        }
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool)
                          -> Result<RasterizedGlyph, Error> {
        let faces = self.faces.clone();
        let face = faces
            .get(&glyph_key.font_key)
            .ok_or(Error::FontNotLoaded)?;

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
        let index = face.get_char_index(c as usize);

        if index == 0 && have_recursed == false {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            let new_glyph_key = GlyphKey {
                c: glyph_key.c,
                font_key: key,
                size: glyph_key.size
            };

            return self.get_rendered_glyph(&new_glyph_key, true);
        }

        face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let (pixel_width, buf) = Self::normalize_buffer(&glyph.bitmap())?;

        Ok(RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: pixel_width,
            height: glyph.bitmap().rows(),
            buf: buf,
        })
    }

    /// Given a FreeType `Bitmap`, returns packed buffer with 1 byte per LCD channel.
    ///
    /// The i32 value in the return type is the number of pixels per row.
    fn normalize_buffer(bitmap: &freetype::bitmap::Bitmap) -> freetype::FtResult<(i32, Vec<u8>)> {
        use freetype::bitmap::PixelMode;

        let buf = bitmap.buffer();
        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        let pitch = bitmap.pitch().abs() as usize;
        match bitmap.pixel_mode()? {
            PixelMode::Lcd => {
                for i in 0..bitmap.rows() {
                    let start = (i as usize) * pitch;
                    let stop = start + bitmap.width() as usize;
                    packed.extend_from_slice(&buf[start..stop]);
                }
                Ok((bitmap.width() / 3, packed))
            },
            // Mono data is stored in a packed format using 1 bit per pixel.
            PixelMode::Mono => {
                fn unpack_byte(res: &mut Vec<u8>, byte: u8, mut count: u8) {
                    // Mono stores MSBit at top of byte
                    let mut bit = 7;
                    while count != 0 {
                        let value = ((byte >> bit) & 1) * 255;
                        // Push value 3x since result buffer should be 1 byte
                        // per channel
                        res.push(value);
                        res.push(value);
                        res.push(value);
                        count -= 1;
                        bit -= 1;
                    }
                };

                for i in 0..(bitmap.rows() as usize) {
                    let mut columns = bitmap.width();
                    let mut byte = 0;
                    let offset = i * bitmap.pitch().abs() as usize;
                    while columns != 0 {
                        let bits = min(8, columns);
                        unpack_byte(&mut packed, buf[offset + byte], bits as u8);

                        columns -= bits;
                        byte += 1;
                    }
                }
                Ok((bitmap.width(), packed))
            },
            // Gray data is stored as a value between 0 and 255 using 1 byte per pixel.
            PixelMode::Gray => {
                for i in 0..bitmap.rows() {
                    let start = (i as usize) * pitch;
                    let stop = start + bitmap.width() as usize;
                    for byte in &buf[start..stop] {
                        packed.push(*byte);
                        packed.push(*byte);
                        packed.push(*byte);
                    }
                }
                Ok((bitmap.width(), packed))
            },
            mode @ _ => panic!("unhandled pixel mode: {:?}", mode)
        }
    }

    fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
                    match self.keys.get(&path) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let face = self.library.new_face(&path, index)?;
                            let key = FontKey::next();
                            self.faces.insert(key, face);
                            self.keys.insert(path, key);
                            Ok(key)
                        }
                    }
                }
                else {
                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))))
                }
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Tried to get size metrics from a Face that didn't have a size
    MissingSizeMetrics,

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
            Error::MissingSizeMetrics => "tried to get size metrics from a face without a size",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            },
            Error::MissingSizeMetrics => {
                f.write_str("Tried to get size metrics from a face without a size")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<commit_msg>Improve glyph rasterization performance<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;
use std::cmp::min;
use std::path::PathBuf;

use freetype::{self, Library};

pub mod fc;

use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};

struct Face {
    ft_face: freetype::Face<'static>,
    key: FontKey,
}

/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
    faces: HashMap<FontKey, Face>,
    library: Library,
    keys: HashMap<PathBuf, FontKey>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

impl ::Rasterize for FreeTypeRasterizer {
    type Err = Error;

    fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32, _: bool) -> Result<FreeTypeRasterizer, Error> {
        let library = Library::init()?;

        Ok(FreeTypeRasterizer {
            faces: HashMap::new(),
            keys: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        })
    }

    fn metrics(&self, key: FontKey) -> Result<Metrics, Error> {
        let face = self.faces
            .get(&key)
            .ok_or(Error::FontNotLoaded)?;

        let size_metrics = face.ft_face.size_metrics()
            .ok_or(Error::MissingSizeMetrics)?;

        let width = (size_metrics.max_advance / 64) as f64;
        let height = (size_metrics.height / 64) as f64;
        let descent = (size_metrics.descender / 64) as f32;

        Ok(Metrics {
            average_advance: width,
            line_height: height,
            descent: descent,
        })
    }

    fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
        let face = Face {
            ft_face: self.get_face(desc)?,
            key: FontKey::next(),
        };
        let key = face.key;
        self.faces.insert(key, face);
        Ok(key)
    }

    fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
        self.get_rendered_glyph(glyph_key)
    }

}

pub trait IntoFontconfigType {
    type FcType;
    fn into_fontconfig_type(&self) -> Self::FcType;
}

impl IntoFontconfigType for Slant {
    type FcType = fc::Slant;
    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Slant::Normal => fc::Slant::Roman,
            Slant::Italic => fc::Slant::Italic,
            Slant::Oblique => fc::Slant::Oblique,
        }
    }
}

impl IntoFontconfigType for Weight {
    type FcType = fc::Weight;

    fn into_fontconfig_type(&self) -> Self::FcType {
        match *self {
            Weight::Normal => fc::Weight::Regular,
            Weight::Bold => fc::Weight::Bold,
        }
    }
}

impl FreeTypeRasterizer {
    /// Load a font face accoring to `FontDesc`
    fn get_face(&mut self, desc: &FontDesc) -> Result<freetype::Face<'static>, Error> {
        match desc.style {
            Style::Description { slant, weight } => {
                // Match nearest font
                self.get_matching_face(&desc, slant, weight)
            }
            Style::Specific(ref style) => {
                // If a name was specified, try and load specifically that font.
                self.get_specific_face(&desc, &style)
            }
        }
    }

    fn get_matching_face(
        &mut self,
        desc: &FontDesc,
        slant: Slant,
        weight: Weight
    ) -> Result<freetype::Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.set_weight(weight.into_fontconfig_type());
        pattern.set_slant(slant.into_fontconfig_type());

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;

        if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
            return Ok(self.library.new_face(path, index)?);
        }

        Err(Error::MissingFont(desc.to_owned()))
    }

    fn get_specific_face(
        &mut self,
        desc: &FontDesc,
        style: &str
    ) -> Result<freetype::Face<'static>, Error> {
        let mut pattern = fc::Pattern::new();
        pattern.add_family(&desc.name);
        pattern.add_style(style);

        let font = fc::font_match(fc::Config::get_current(), &mut pattern)
            .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
        if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
            println!("got font path={:?}", path);
            Ok(self.library.new_face(path, index)?)
        }
        else {
            Err(Error::MissingFont(desc.to_owned()))
        }
    }

    fn face_for_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool) -> Result<FontKey, Error> {
        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        let use_initial_face = if self.faces.contains_key(&glyph_key.font_key) {
            // Get face and unwrap since we just checked for presence.
            let face = self.faces.get(&glyph_key.font_key).unwrap();

            face.ft_face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
            let index = face.ft_face.get_char_index(c as usize);

            if index != 0 || have_recursed {
                true
            } else {
                false
            }
        } else {
            false
        };

        if use_initial_face {
            Ok(glyph_key.font_key)
        } else {
            let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key);
            Ok(key)
        }
    }

    fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey)
                          -> Result<RasterizedGlyph, Error> {
        let font_key = self.face_for_glyph(glyph_key, false)?;
        let face = self.faces.get(&font_key).unwrap();
        let index = face.ft_face.get_char_index(glyph_key.c as usize);

        face.ft_face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?;
        let glyph = face.ft_face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?;

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(
                ft_lib,
                freetype::ffi::FT_LCD_FILTER_DEFAULT
            );
        }

        let (pixel_width, buf) = Self::normalize_buffer(&glyph.bitmap())?;

        Ok(RasterizedGlyph {
            c: glyph_key.c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: pixel_width,
            height: glyph.bitmap().rows(),
            buf: buf,
        })
    }

    /// Given a FreeType `Bitmap`, returns packed buffer with 1 byte per LCD channel.
    ///
    /// The i32 value in the return type is the number of pixels per row.
    fn normalize_buffer(bitmap: &freetype::bitmap::Bitmap) -> freetype::FtResult<(i32, Vec<u8>)> {
        use freetype::bitmap::PixelMode;

        let buf = bitmap.buffer();
        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        let pitch = bitmap.pitch().abs() as usize;
        match bitmap.pixel_mode()? {
            PixelMode::Lcd => {
                for i in 0..bitmap.rows() {
                    let start = (i as usize) * pitch;
                    let stop = start + bitmap.width() as usize;
                    packed.extend_from_slice(&buf[start..stop]);
                }
                Ok((bitmap.width() / 3, packed))
            },
            // Mono data is stored in a packed format using 1 bit per pixel.
            PixelMode::Mono => {
                fn unpack_byte(res: &mut Vec<u8>, byte: u8, mut count: u8) {
                    // Mono stores MSBit at top of byte
                    let mut bit = 7;
                    while count != 0 {
                        let value = ((byte >> bit) & 1) * 255;
                        // Push value 3x since result buffer should be 1 byte
                        // per channel
                        res.push(value);
                        res.push(value);
                        res.push(value);
                        count -= 1;
                        bit -= 1;
                    }
                };

                for i in 0..(bitmap.rows() as usize) {
                    let mut columns = bitmap.width();
                    let mut byte = 0;
                    let offset = i * bitmap.pitch().abs() as usize;
                    while columns != 0 {
                        let bits = min(8, columns);
                        unpack_byte(&mut packed, buf[offset + byte], bits as u8);

                        columns -= bits;
                        byte += 1;
                    }
                }
                Ok((bitmap.width(), packed))
            },
            // Gray data is stored as a value between 0 and 255 using 1 byte per pixel.
            PixelMode::Gray => {
                for i in 0..bitmap.rows() {
                    let start = (i as usize) * pitch;
                    let stop = start + bitmap.width() as usize;
                    for byte in &buf[start..stop] {
                        packed.push(*byte);
                        packed.push(*byte);
                        packed.push(*byte);
                    }
                }
                Ok((bitmap.width(), packed))
            },
            mode @ _ => panic!("unhandled pixel mode: {:?}", mode)
        }
    }

    fn load_face_with_glyph(
        &mut self,
        glyph: char,
    ) -> Result<FontKey, Error> {
        let mut charset = fc::CharSet::new();
        charset.add(glyph);
        let mut pattern = fc::Pattern::new();
        pattern.add_charset(&charset);

        let config = fc::Config::get_current();
        match fc::font_match(config, &mut pattern) {
            Some(font) => {
                if let (Some(path), Some(index)) = (font.file(0), font.index().nth(0)) {
                    match self.keys.get(&path) {
                        // We've previously loaded this font, so don't
                        // load it again.
                        Some(&key) => {
                            debug!("Hit for font {:?}", path);
                            Ok(key)
                        },

                        None => {
                            debug!("Miss for font {:?}", path);
                            let face = Face {
                                ft_face: self.library.new_face(&path, index)?,
                                key: FontKey::next(),
                            };
                            let key = face.key;
                            self.faces.insert(key, face);
                            self.keys.insert(path, key);
                            Ok(key)
                        }
                    }
                }
                else {
                Err(Error::MissingFont(
                    FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string()))))
                }
            },
            None => {
                Err(Error::MissingFont(
                    FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string()))
                ))
            }
        }
    }
}

/// Errors occurring when using the freetype rasterizer
#[derive(Debug)]
pub enum Error {
    /// Error occurred within the FreeType library
    FreeType(freetype::Error),

    /// Couldn't find font matching description
    MissingFont(FontDesc),

    /// Tried to get size metrics from a Face that didn't have a size
    MissingSizeMetrics,

    /// Requested an operation with a FontKey that isn't known to the rasterizer
    FontNotLoaded,
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::FreeType(ref err) => Some(err),
            _ => None,
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::FreeType(ref err) => err.description(),
            Error::MissingFont(ref _desc) => "couldn't find the requested font",
            Error::FontNotLoaded => "tried to operate on font that hasn't been loaded",
            Error::MissingSizeMetrics => "tried to get size metrics from a face without a size",
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::FreeType(ref err) => {
                err.fmt(f)
            },
            Error::MissingFont(ref desc) => {
                write!(f, "Couldn't find a font with {}\
                       \n\tPlease check the font config in your alacritty.yml.", desc)
            },
            Error::FontNotLoaded => {
                f.write_str("Tried to use a font that hasn't been loaded")
            },
            Error::MissingSizeMetrics => {
                f.write_str("Tried to get size metrics from a face without a size")
            }
        }
    }
}

impl From<freetype::Error> for Error {
    fn from(val: freetype::Error) -> Error {
        Error::FreeType(val)
    }
}

unsafe impl Send for FreeTypeRasterizer {}
<|endoftext|>


<commit_before>use yaml_rust::yaml::Yaml;
use yaml_rust::{YamlLoader, YamlEmitter};
use environment::{IEnvironment, Environment};
use ast::AST;
use evaluator::Evaluator;
use parser::Parser;
use helpers::is_keyword;
use lexer;

#[derive(Debug, PartialEq)]
pub enum YamlType {
    Value(Yaml),
    Return(Yaml),
}

// TODO: clean up super ugly code
fn apply_keyword(s: &str, k: &Yaml, v: &Yaml, env: &mut IEnvironment) -> YamlType {
    match s {
         "if" => {
            if let &Yaml::Array(ref arr) = v {
                let mut prop_str = String::new();
                for val in arr {
                    if let &Yaml::String(ref prop) = val {
                        let str_len = prop_str.len();
                        if str_len == 0 {
                            prop_str = format!("({})", prop.clone());
                        } else {
                            prop_str = format!("{} && ({})", prop_str, prop.clone());
                        }
                    } else if let &Yaml::Hash(ref h) = val {
                        for (key, val) in h {
                            if let &Yaml::String(ref keyword) = key {
                                let result = evaluate(&Yaml::String(prop_str.clone()), env);

                                match keyword.as_str() {
                                    "do" => {
                                        if let YamlType::Value(Yaml::Integer(i)) = result {
                                            if i > 0 {
                                                return evaluate(val, env);
                                            }
                                        }
                                    }
                                    "else" => {
                                        let result = evaluate(&Yaml::String(prop_str.clone()), env);
                                        if let YamlType::Value(Yaml::Integer(i)) = result {
                                            if i == 0 {
                                                return evaluate(val, env);
                                            }
                                        }
                                    }
                                    _ => {},
                                }
                            }
                        }
                    }
                }
            }
         }
        "return" => {
            let result = evaluate(&v, env);
            if let YamlType::Value(val) = result {
                return YamlType::Return(val);
            }
            return result;
        }
        _ => {}
    }

    YamlType::Value(v.clone())
}

pub fn evaluate(yaml: &Yaml, env: &mut IEnvironment) -> YamlType {
    match yaml {
        &Yaml::String(ref s) => {
            if s.as_str().contains("~>") {
                let split_vec = s.as_str().split("~>").collect::<Vec<_>>();
                let mut evaluator = Evaluator::new(env);
                let mut parser = Parser::new();

                let (mut var_deque, mut op_deque) = lexer::parse_string(split_vec[1]).unwrap();
                let ast = parser.parse_to_ast(&mut var_deque, &mut op_deque).unwrap_or(AST::None);
                let result = evaluator.evaluate(ast).unwrap_or(AST::None);

                YamlType::Value(match result {
                    AST::Decimal(d) => Yaml::Real(d.to_string()),
                    AST::Number(n) => Yaml::Integer(n as i64),
                    AST::String(s) => Yaml::String(s),
                    _ => Yaml::String(split_vec[1].to_string()),
                })
            } else {
                YamlType::Value(Yaml::String(s.clone()))
            }
        }
        &Yaml::Array(ref arr) => {
            let mut last_value: Option<Yaml> = None;
            for v in arr {
                let result = evaluate(v, env);
                if let YamlType::Return(val) = result {
                    return YamlType::Return(val);
                } else if let YamlType::Value(val) = result {
                    last_value = Some(val);
                }
            }

            if let Some(val) = last_value {
                YamlType::Value(val)
            } else {
                YamlType::Value(Yaml::Array(arr.clone()))
            }
        }
        &Yaml::Hash(ref h) => {
            for (k, v) in h {
                if let &Yaml::String(ref s) = k {
                    return apply_keyword(s.as_str(), k, v, env);
                }
            }
            YamlType::Value(Yaml::Hash(h.clone()))
        }
        &ref val @ _ => YamlType::Value(val.clone()),
    }
}

#[test]
fn test_yaml_eval() {
    // Test if evaluating "foo" returns 15

    let s = "
    foo:
      - '~> a := 2'
      - if:
        - '~> a == 2'
        - do:
          \
             - '~> a = 3'
      - return: '~> a * (2 + 3)'
    ";
    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(15)));
}

#[test]
fn test_yaml_else() {
    // Test if evaluating "foo" returns 20

    let s = "
    foo:
      - '~> a := 2'
      - if:
        - '~> a == 3'
        - do:
          \
             - '~> a = 3'
          else:
          \
             - '~> a = 4'
      - return: '~> a * (2 + 3)'
    ";
    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(20)));
}

#[test]
fn test_return() {
    // Test that return doesn't execute statements after it

    let s = "
    foo:
      - return: '~> 2 * (2 + 3)'
      - '~> a := 2'
      - if:
        \
             - '~> a == 2'
        - do:
          - '~> a = 3'
    ";
    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(10)));

    assert_eq!(env.get("a".to_string()), Some(&AST::Number(1)));
}

#[test]
fn test_return_last_val() {
    // Test that the last value is returned as value instead of return

    let s = "
    foo:
      - '~> a := 2'
      - if:
        \
             - '~> a == 2'
        - do:
          - '~> a = 3'
      - '~> 2 * (2 + 3)'
    ";
    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Value(Yaml::Integer(10)));
}
<commit_msg>Refactored if implementation<commit_after>use yaml_rust::yaml::Yaml;
use std::collections::BTreeMap;
use yaml_rust::{YamlLoader, YamlEmitter};
use environment::{IEnvironment, Environment};
use ast::AST;
use evaluator::Evaluator;
use parser::Parser;
use helpers::is_keyword;
use lexer;

#[derive(Debug, PartialEq)]
pub enum YamlType {
    Value(Yaml),
    Return(Yaml),
}

// same as apply_keywords but only works on nested keywords in if statements
// like do or else
fn apply_nested_if_keywords(h: &BTreeMap<Yaml, Yaml>, prop_str: &str, env: &mut IEnvironment) -> YamlType {
    for (key, val) in h {
        if let &Yaml::String(ref keyword) = key {
            let result = evaluate(&Yaml::String(prop_str.to_string()), env);

            match keyword.as_str() {
                "do" => {
                    if let YamlType::Value(Yaml::Integer(i)) = result {
                        if i > 0 {
                            return evaluate(val, env);
                        }
                    }
                }
                "else" => {
                    if let YamlType::Value(Yaml::Integer(i)) = result {
                        if i == 0 {
                            return evaluate(val, env);
                        }
                    }
                }
                _ => {}
            }
        }
    }
    YamlType::Value(Yaml::Hash(h.clone()))
}

// applies the effects of keywords in a YAML hash
fn apply_keyword(s: &str, k: &Yaml, v: &Yaml, env: &mut IEnvironment) -> YamlType {
    match s {
        "if" => {
            if let &Yaml::Array(ref arr) = v {
                let mut prop_str = String::new();
                for val in arr {
                    if let &Yaml::String(ref prop) = val {
                        let str_len = prop_str.len();
                        if str_len == 0 {
                            prop_str = format!("({})", prop.clone());
                        } else {
                            prop_str = format!("{} && ({})", prop_str, prop.clone());
                        }
                    } else if let &Yaml::Hash(ref h) = val {
                        return apply_nested_if_keywords(h, prop_str.clone().as_str(), env);
                    }
                }
            }
        }
        "return" => {
            let result = evaluate(&v, env);
            if let YamlType::Value(val) = result {
                return YamlType::Return(val);
            }
            return result;
        }
        _ => {}
    }

    YamlType::Value(v.clone())
}

// evaluates the result of a fragment of YAML
pub fn evaluate(yaml: &Yaml, env: &mut IEnvironment) -> YamlType {
    match yaml {
        &Yaml::String(ref s) => {
            if s.as_str().contains("~>") {
                let split_vec = s.as_str().split("~>").collect::<Vec<_>>();
                let mut evaluator = Evaluator::new(env);
                let mut parser = Parser::new();

                let (mut var_deque, mut op_deque) = lexer::parse_string(split_vec[1]).unwrap();
                let ast = parser.parse_to_ast(&mut var_deque, &mut op_deque).unwrap_or(AST::None);
                let result = evaluator.evaluate(ast).unwrap_or(AST::None);

                YamlType::Value(match result {
                    AST::Decimal(d) => Yaml::Real(d.to_string()),
                    AST::Number(n) => Yaml::Integer(n as i64),
                    AST::String(s) => Yaml::String(s),
                    _ => Yaml::String(split_vec[1].to_string()),
                })
            } else {
                YamlType::Value(Yaml::String(s.clone()))
            }
        }
        &Yaml::Array(ref arr) => {
            let mut last_value: Option<Yaml> = None;
            for v in arr {
                let result = evaluate(v, env);
                if let YamlType::Return(val) = result {
                    return YamlType::Return(val);
                } else if let YamlType::Value(val) = result {
                    last_value = Some(val);
                }
            }

            if let Some(val) = last_value {
                YamlType::Value(val)
            } else {
                YamlType::Value(Yaml::Array(arr.clone()))
            }
        }
        &Yaml::Hash(ref h) => {
            for (k, v) in h {
                if let &Yaml::String(ref s) = k {
                    return apply_keyword(s.as_str(), k, v, env);
                }
            }
            YamlType::Value(Yaml::Hash(h.clone()))
        }
        &ref val @ _ => YamlType::Value(val.clone()),
    }
}

#[test]
fn test_yaml_eval() {
    // Test if evaluating "foo" returns 15

    let s = "
    foo:
      - '~> a := 2'
      - if:
        - '~> a == 2'
        - do:
          \
             - '~> a = 3'
      - return: '~> a * (2 + 3)'
    ";

    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(15)));
}

#[test]
fn test_yaml_else() {
    // Test if evaluating "foo" returns 20

    let s = "
    foo:
      - '~> a := 2'
      - if:
        - '~> a == 3'
        - do:
            - '~> a = 3'
          else:
            - '~> a = 4'
      - return: '~> a * (2 + 3)'
    ";

    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(20)));
}

#[test]
fn test_return() {
    // Test that return doesn't execute statements after it

    let s = "
    foo:
      - return: '~> 2 * (2 + 3)'
      - '~> a := 2'
      - if:
        - '~> a == 2'
        - do:
          - '~> a = 3'
    ";

    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Return(Yaml::Integer(10)));

    assert_eq!(env.get("a".to_string()), Some(&AST::Number(1)));
}

#[test]
fn test_return_last_val() {
    // Test that the last value is returned as value instead of return

    let s = "
    foo:
      - '~> a := 2'
      - if:
        - '~> a == 2'
        - do:
          - '~> a = 3'
      - '~> 2 * (2 + 3)'
    ";

    let mut env = Environment::new();
    env.set("a".to_string(), AST::Number(1));
    env.set("b".to_string(), AST::Number(2));

    let docs = YamlLoader::load_from_str(s).unwrap();

    assert_eq!(evaluate(&docs[0]["foo"], &mut env),
               YamlType::Value(Yaml::Integer(10)));
}
<|endoftext|>


<commit_before>/*!

This crate provides a index (entity) based tree structure compatible to the [DCES](https://gitlab.redox-os.org/redox-os/dces-rust)
Entity Component System. The tree could be used as entity storage.

# Example

Basic usage of the tree:

```rust,no_run

use orbtk_tree::prelude::*;

let mut tree = Tree::new();
tree.register_node(0);
tree.register_node(1);
tree.append_child(0, 1);
```

 */

use std::{cell::Cell, collections::BTreeMap};

use dces::{entity::EntityStore, prelude::Entity};

pub mod prelude;

/// Used as return type if a requested entity is not found on the tree.
#[derive(Debug, PartialEq, Eq)]
pub enum NotFound {
    /// Parent could not be found.
    Parent(Entity),

    /// Child could not be found
    Child(Entity),
}

/// Base data structure to manage the entities of a window in a tree based structure.
#[derive(Clone, Default, Debug)]
pub struct Tree {
    pub root: Option<Entity>,
    pub overlay: Option<Entity>,
    pub children: BTreeMap<Entity, Vec<Entity>>,
    pub parent: BTreeMap<Entity, Option<Entity>>,
    iterator_start_node: Cell<Option<Entity>>,
}

impl Tree {
    /// Creates a new tree with default values.
    pub fn new() -> Self {
        Tree::default()
    }

    /// Returns the root of the tree.
    pub fn root(&self) -> Entity {
        if let Some(root) = self.root {
            return root;
        }

        if let Some(root) = self.parent.keys().next() {
            return *root;
        }

        0.into()
    }

    // /// Configure the tree iterator with a start node.
    pub fn start_node(&self, start_node: impl Into<Entity>) -> &Self {
        self.iterator_start_node.set(Some(start_node.into()));
        self
    }

    /// Registers a new entity `entity` as node.
    pub fn register_node(&mut self, entity: impl Into<Entity>) {
        let entity = entity.into();
        self.children.insert(entity, vec![]);
        self.parent.insert(entity, None);
    }

    /// Sets the root.
    pub fn set_root(&mut self, root: impl Into<Entity>) {
        let root = root.into();
        self.root = Some(root);

        if let Some(overlay) = self.overlay {
            if let Some(p) = self.children.get_mut(&root) {
                p.push(overlay);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay: impl Into<Entity>) {
        let overlay = overlay.into();
        self.overlay = Some(overlay);

        if let Some(root) = self.root {
            if let Some(p) = self.children.get_mut(&root) {
                p.push(overlay);
            }
        }
    }

    /// Appends a `child` entity to the given `parent` entity.
    /// Raised `NotFound` error if the parent is not part of the tree.
    pub fn append_child(
        &mut self,
        parent: impl Into<Entity>,
        child: impl Into<Entity>,
    ) -> Result<Entity, NotFound> {
        let parent = parent.into();
        let child = child.into();

        if self.root.is_some() && parent == self.root.unwrap() && self.overlay.is_some() {
            // insert child to root before overlay
            let len = self.children.len();
            if let Some(p) = self.children.get_mut(&parent) {
                p.insert(len - 2, child);
            } else {
                return Err(NotFound::Parent(parent));
            }
        } else {
            if let Some(p) = self.children.get_mut(&parent) {
                p.push(child);
            } else {
                return Err(NotFound::Parent(parent));
            }
            self.parent.insert(child, Some(parent));
        }

        Ok(child)
    }

    /// Returns the number of all entities in the tree.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Returns true if the tree has no entities.
    pub fn is_empty(&self) -> bool {
        self.children.is_empty()
    }
}

impl EntityStore for Tree {
    fn register_entity(&mut self, entity: impl Into<Entity>) {
        self.register_node(entity.into());
    }

    fn remove_entity(&mut self, entity: impl Into<Entity>) {
        let entity = entity.into();

        if let Some(parent_index) = self.parent[&entity] {
            if let Some(parent_children) = self.children.get_mut(&parent_index) {
                if let Some(index) = parent_children.iter().position(|&r| r == entity) {
                    parent_children.remove(index);
                }
            }
        }

        self.children.remove(&entity);
        self.parent.remove(&entity);
    }
}

impl<'a> IntoIterator for &'a Tree {
    type Item = Entity;
    type IntoIter = TreeIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        let start_node = {
            if let Some(start_node) = self.iterator_start_node.get() {
                start_node
            } else {
                if let Some(root) = self.root {
                    root
                } else {
                    0.into()
                }
            }
        };

        self.iterator_start_node.set(None);

        TreeIterator {
            tree: self,
            start_node,
            current_node: None,
        }
    }
}

/// Used to create an iterator for the tree.
pub struct TreeIterator<'a> {
    tree: &'a Tree,
    start_node: Entity,
    current_node: Option<Entity>,
}

impl<'a> Iterator for TreeIterator<'a> {
    type Item = Entity;

    fn next(&mut self) -> Option<Entity> {
        if let Some(node) = self.current_node {
            if !self.tree.children.contains_key(&node) {
                panic!("TreeIterator.next: Tree does not contains node {}", node.0);
            }
            if !self.tree.children[&node].is_empty() {
                self.current_node = Some(self.tree.children[&node][0]);
                return self.current_node;
            } else {
                if !self.tree.children.contains_key(&node) {
                    panic!("TreeIterator.next: Tree does not contains node {}", node.0);
                }
                let mut tree_node = node;
                while let Some(parent) = self.tree.parent[&tree_node] {
                    let siblings = &self.tree.children[&parent];

                    let sibling_index = siblings.iter().position(|&r| r == tree_node).unwrap() + 1;

                    if sibling_index < siblings.len() {
                        self.current_node = Some(siblings[sibling_index]);
                        return self.current_node;
                    } else {
                        tree_node = parent;
                    }
                }
                // root
                return None;
            }
        }

        self.current_node = Some(self.start_node);
        self.current_node
    }
}

#[cfg(test)]
mod tests {
    use dces::entity::EntityStore;
    use dces::prelude::*;

    use super::*;

    #[test]
    fn test_register_node() {
        let mut tree = Tree::new();
        tree.register_node(0);

        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());
    }

    #[test]
    fn test_append_child() {
        let parent = Entity(0);
        let child = Entity(1);

        let mut tree = Tree::new();
        tree.register_node(parent);
        tree.register_node(child);
        tree.append_child(parent, child).unwrap();

        assert_eq!(tree.children.len(), 2);
        assert_eq!(tree.parent.len(), 2);
        assert_eq!(tree.children.get(&parent).unwrap()[0], child);
        assert_eq!(tree.parent.get(&child).unwrap().unwrap(), parent);
    }

    #[test]
    fn test_len() {
        let mut tree = Tree::new();
        assert_eq!(tree.children.len(), 0);

        tree.register_node(0);
        assert_eq!(tree.children.len(), 1);

        tree.register_node(1);
        assert_eq!(tree.children.len(), 2);
    }

    #[test]
    fn test_is_empty() {
        let mut tree = Tree::new();
        assert!(tree.is_empty());

        tree.register_node(0);
        assert!(!tree.is_empty());
    }

    #[test]
    fn test_register_entity() {
        let mut tree = Tree::new();
        tree.register_entity(0);

        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());
    }

    #[test]
    fn test_remove_entity() {
        let mut tree = Tree::new();

        tree.register_entity(0);
        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());

        tree.remove_entity(0);
        assert_eq!(tree.children.len(), 0);
        assert_eq!(tree.parent.len(), 0);
        assert!(tree.children.get(&Entity(0)).is_none());
    }

    #[test]
    fn test_iterator_next() {
        let mut tree = Tree::new();
        tree.register_entity(0);
        tree.register_entity(1);
        tree.register_entity(2);
        tree.register_entity(3);
        tree.register_entity(4);
        tree.register_entity(5);
        tree.register_entity(6);

        tree.append_child(0, 1).unwrap();
        tree.append_child(0, 2).unwrap();

        tree.append_child(1, 3).unwrap();
        tree.append_child(1, 4).unwrap();

        tree.append_child(2, 5).unwrap();
        tree.append_child(2, 6).unwrap();

        let mut iterator = tree.into_iter();

        assert_eq!(Entity(0), iterator.next().unwrap());
        assert_eq!(Entity(1), iterator.next().unwrap());
        assert_eq!(Entity(3), iterator.next().unwrap());
        assert_eq!(Entity(4), iterator.next().unwrap());
        assert_eq!(Entity(2), iterator.next().unwrap());
        assert_eq!(Entity(5), iterator.next().unwrap());
        assert_eq!(Entity(6), iterator.next().unwrap());
    }
}
<commit_msg>clippy.<commit_after>/*!

This crate provides a index (entity) based tree structure compatible to the [DCES](https://gitlab.redox-os.org/redox-os/dces-rust)
Entity Component System. The tree could be used as entity storage.

# Example

Basic usage of the tree:

```rust,no_run

use orbtk_tree::prelude::*;

let mut tree = Tree::new();
tree.register_node(0);
tree.register_node(1);
tree.append_child(0, 1);
```

 */

use std::{cell::Cell, collections::BTreeMap};

use dces::{entity::EntityStore, prelude::Entity};

pub mod prelude;

/// Used as return type if a requested entity is not found on the tree.
#[derive(Debug, PartialEq, Eq)]
pub enum NotFound {
    /// Parent could not be found.
    Parent(Entity),

    /// Child could not be found
    Child(Entity),
}

/// Base data structure to manage the entities of a window in a tree based structure.
#[derive(Clone, Default, Debug)]
pub struct Tree {
    pub root: Option<Entity>,
    pub overlay: Option<Entity>,
    pub children: BTreeMap<Entity, Vec<Entity>>,
    pub parent: BTreeMap<Entity, Option<Entity>>,
    iterator_start_node: Cell<Option<Entity>>,
}

impl Tree {
    /// Creates a new tree with default values.
    pub fn new() -> Self {
        Tree::default()
    }

    /// Returns the root of the tree.
    pub fn root(&self) -> Entity {
        if let Some(root) = self.root {
            return root;
        }

        if let Some(root) = self.parent.keys().next() {
            return *root;
        }

        0.into()
    }

    // /// Configure the tree iterator with a start node.
    pub fn start_node(&self, start_node: impl Into<Entity>) -> &Self {
        self.iterator_start_node.set(Some(start_node.into()));
        self
    }

    /// Registers a new entity `entity` as node.
    pub fn register_node(&mut self, entity: impl Into<Entity>) {
        let entity = entity.into();
        self.children.insert(entity, vec![]);
        self.parent.insert(entity, None);
    }

    /// Sets the root.
    pub fn set_root(&mut self, root: impl Into<Entity>) {
        let root = root.into();
        self.root = Some(root);

        if let Some(overlay) = self.overlay {
            if let Some(p) = self.children.get_mut(&root) {
                p.push(overlay);
            }
        }
    }

    pub fn set_overlay(&mut self, overlay: impl Into<Entity>) {
        let overlay = overlay.into();
        self.overlay = Some(overlay);

        if let Some(root) = self.root {
            if let Some(p) = self.children.get_mut(&root) {
                p.push(overlay);
            }
        }
    }

    /// Appends a `child` entity to the given `parent` entity.
    /// Raised `NotFound` error if the parent is not part of the tree.
    pub fn append_child(
        &mut self,
        parent: impl Into<Entity>,
        child: impl Into<Entity>,
    ) -> Result<Entity, NotFound> {
        let parent = parent.into();
        let child = child.into();

        if self.root.is_some() && parent == self.root.unwrap() && self.overlay.is_some() {
            // insert child to root before overlay
            let len = self.children.len();
            if let Some(p) = self.children.get_mut(&parent) {
                p.insert(len - 2, child);
            } else {
                return Err(NotFound::Parent(parent));
            }
        } else {
            if let Some(p) = self.children.get_mut(&parent) {
                p.push(child);
            } else {
                return Err(NotFound::Parent(parent));
            }
            self.parent.insert(child, Some(parent));
        }

        Ok(child)
    }

    /// Returns the number of all entities in the tree.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Returns true if the tree has no entities.
    pub fn is_empty(&self) -> bool {
        self.children.is_empty()
    }
}

impl EntityStore for Tree {
    fn register_entity(&mut self, entity: impl Into<Entity>) {
        self.register_node(entity.into());
    }

    fn remove_entity(&mut self, entity: impl Into<Entity>) {
        let entity = entity.into();

        if let Some(parent_index) = self.parent[&entity] {
            if let Some(parent_children) = self.children.get_mut(&parent_index) {
                if let Some(index) = parent_children.iter().position(|&r| r == entity) {
                    parent_children.remove(index);
                }
            }
        }

        self.children.remove(&entity);
        self.parent.remove(&entity);
    }
}

impl<'a> IntoIterator for &'a Tree {
    type Item = Entity;
    type IntoIter = TreeIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        let start_node = {
            if let Some(start_node) = self.iterator_start_node.get() {
                start_node
            } else if let Some(root) = self.root {
                root
            } else {
                0.into()
            }
        };

        self.iterator_start_node.set(None);

        TreeIterator {
            tree: self,
            start_node,
            current_node: None,
        }
    }
}

/// Used to create an iterator for the tree.
pub struct TreeIterator<'a> {
    tree: &'a Tree,
    start_node: Entity,
    current_node: Option<Entity>,
}

impl<'a> Iterator for TreeIterator<'a> {
    type Item = Entity;

    fn next(&mut self) -> Option<Entity> {
        if let Some(node) = self.current_node {
            if !self.tree.children.contains_key(&node) {
                panic!("TreeIterator.next: Tree does not contains node {}", node.0);
            }
            if !self.tree.children[&node].is_empty() {
                self.current_node = Some(self.tree.children[&node][0]);
                return self.current_node;
            } else {
                if !self.tree.children.contains_key(&node) {
                    panic!("TreeIterator.next: Tree does not contains node {}", node.0);
                }
                let mut tree_node = node;
                while let Some(parent) = self.tree.parent[&tree_node] {
                    let siblings = &self.tree.children[&parent];

                    let sibling_index = siblings.iter().position(|&r| r == tree_node).unwrap() + 1;

                    if sibling_index < siblings.len() {
                        self.current_node = Some(siblings[sibling_index]);
                        return self.current_node;
                    } else {
                        tree_node = parent;
                    }
                }
                // root
                return None;
            }
        }

        self.current_node = Some(self.start_node);
        self.current_node
    }
}

#[cfg(test)]
mod tests {
    use dces::entity::EntityStore;
    use dces::prelude::*;

    use super::*;

    #[test]
    fn test_register_node() {
        let mut tree = Tree::new();
        tree.register_node(0);

        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());
    }

    #[test]
    fn test_append_child() {
        let parent = Entity(0);
        let child = Entity(1);

        let mut tree = Tree::new();
        tree.register_node(parent);
        tree.register_node(child);
        tree.append_child(parent, child).unwrap();

        assert_eq!(tree.children.len(), 2);
        assert_eq!(tree.parent.len(), 2);
        assert_eq!(tree.children.get(&parent).unwrap()[0], child);
        assert_eq!(tree.parent.get(&child).unwrap().unwrap(), parent);
    }

    #[test]
    fn test_len() {
        let mut tree = Tree::new();
        assert_eq!(tree.children.len(), 0);

        tree.register_node(0);
        assert_eq!(tree.children.len(), 1);

        tree.register_node(1);
        assert_eq!(tree.children.len(), 2);
    }

    #[test]
    fn test_is_empty() {
        let mut tree = Tree::new();
        assert!(tree.is_empty());

        tree.register_node(0);
        assert!(!tree.is_empty());
    }

    #[test]
    fn test_register_entity() {
        let mut tree = Tree::new();
        tree.register_entity(0);

        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());
    }

    #[test]
    fn test_remove_entity() {
        let mut tree = Tree::new();

        tree.register_entity(0);
        assert_eq!(tree.children.len(), 1);
        assert_eq!(tree.parent.len(), 1);
        assert!(tree.children.get(&Entity(0)).is_some());

        tree.remove_entity(0);
        assert_eq!(tree.children.len(), 0);
        assert_eq!(tree.parent.len(), 0);
        assert!(tree.children.get(&Entity(0)).is_none());
    }

    #[test]
    fn test_iterator_next() {
        let mut tree = Tree::new();
        tree.register_entity(0);
        tree.register_entity(1);
        tree.register_entity(2);
        tree.register_entity(3);
        tree.register_entity(4);
        tree.register_entity(5);
        tree.register_entity(6);

        tree.append_child(0, 1).unwrap();
        tree.append_child(0, 2).unwrap();

        tree.append_child(1, 3).unwrap();
        tree.append_child(1, 4).unwrap();

        tree.append_child(2, 5).unwrap();
        tree.append_child(2, 6).unwrap();

        let mut iterator = tree.into_iter();

        assert_eq!(Entity(0), iterator.next().unwrap());
        assert_eq!(Entity(1), iterator.next().unwrap());
        assert_eq!(Entity(3), iterator.next().unwrap());
        assert_eq!(Entity(4), iterator.next().unwrap());
        assert_eq!(Entity(2), iterator.next().unwrap());
        assert_eq!(Entity(5), iterator.next().unwrap());
        assert_eq!(Entity(6), iterator.next().unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate ilc_base;
extern crate ilc_ops;
extern crate ilc_format_weechat;
extern crate ilc_format_energymech;
extern crate chrono;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate glob;

use ilc_base::{Context, Decode, Encode};
use ilc_ops::*;
use ilc_format_weechat::Weechat;
use ilc_format_energymech::Energymech;

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

use chrono::{FixedOffset, NaiveDate};

use glob::glob;

use std::str::FromStr;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::{process, usize};
use std::error::Error;

mod chain;

pub fn main() {
    env_logger::init().unwrap();
    let args = App::new("ilc")
                   .version(crate_version!())
                   .setting(AppSettings::GlobalVersion)
                   .setting(AppSettings::VersionlessSubcommands)
                   .setting(AppSettings::ArgRequiredElseHelp)
                   .author("Till Höppner <till@hoeppner.ws>")
                   .about("A converter and statistics utility for IRC log files")
                   .arg(Arg::with_name("timezone")
                            .help("UTC offset in the direction of the western hemisphere")
                            .global(true)
                            .takes_value(true)
                            .long("timezone")
                            .short("t"))
                   .arg(Arg::with_name("date")
                            .help("Override the date for this log, ISO 8601, YYYY-MM-DD")
                            .global(true)
                            .takes_value(true)
                            .long("date")
                            .short("d"))
                   .arg(Arg::with_name("infer_date")
                            .help("Try to use the filename as date for the current log")
                            .global(true)
                            .long("infer-date"))
                   .arg(Arg::with_name("channel")
                            .help("Set a channel for the current log")
                            .global(true)
                            .takes_value(true)
                            .long("channel")
                            .short("c"))
                   .arg(Arg::with_name("format")
                            .help("Set the input and output format for the current log")
                            .global(true)
                            .takes_value(true)
                            .long("format")
                            .short("f"))
                   .arg(Arg::with_name("input_format")
                            .help("Set the input format for the current log")
                            .global(true)
                            .conflicts_with("format")
                            .takes_value(true)
                            .long("inf"))
                   .arg(Arg::with_name("output_format")
                            .help("Set the output format for the current log")
                            .global(true)
                            .conflicts_with("format")
                            .takes_value(true)
                            .long("outf"))
                   .arg(Arg::with_name("input_files")
                            .help("Specify an input file, instead of stdin")
                            .global(true)
                            .takes_value(true)
                            .multiple(true)
                            .long("input")
                            .short("i"))
                   .arg(Arg::with_name("output_file")
                            .help("Specify an output file, instead of stdout")
                            .global(true)
                            .takes_value(true)
                            .long("output")
                            .short("o"))
                   .subcommand(SubCommand::with_name("parse")
                                   .about("Parse the input, checking the format"))
                   .subcommand(SubCommand::with_name("convert")
                                   .about("Convert from a source to a target format"))
                   .subcommand(SubCommand::with_name("freq")
                                   .about("Analyse the activity of users by certain metrics")
                                   .arg(Arg::with_name("count")
                                            .help("The number of items to be displayed")
                                            .takes_value(true)
                                            .long("count")))
                   .subcommand(SubCommand::with_name("seen")
                                   .about("Print the last line a nick was active")
                                   .arg(Arg::with_name("nick")
                                            .help("The nick you're looking for")
                                            .takes_value(true)
                                            .required(true)
                                            .index(1)))
                   .subcommand(SubCommand::with_name("sort").about("Sorts a log by time"))
                   .subcommand(SubCommand::with_name("dedup")
                                   .about("Removes duplicate log entries in close proximity"))
                   .get_matches();

    let res = match args.subcommand() {
        ("parse", Some(args)) => {
            let e = Environment(&args);
            parse::parse(&e.context(), &mut e.input(), &mut *e.decoder())
        }
        ("convert", Some(args)) => {
            let e = Environment(&args);
            convert::convert(&e.context(),
                             &mut e.input(),
                             &mut *e.decoder(),
                             &mut *e.output(),
                             &*e.encoder())
        }
        ("freq", Some(args)) => {
            let e = Environment(&args);
            let count = value_t!(args, "count", usize).unwrap_or(usize::MAX);
            freq::freq(count,
                       &e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut e.output())
        }
        ("seen", Some(args)) => {
            let e = Environment(&args);
            let nick = args.value_of("nick").expect("Required argument <nick> not present");
            seen::seen(nick,
                       &e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut *e.output(),
                       &Weechat)
        }
        ("sort", Some(args)) => {
            let e = Environment(&args);
            sort::sort(&e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut *e.output(),
                       &*e.encoder())
        }
        ("dedup", Some(args)) => {
            let e = Environment(&args);
            dedup::dedup(&e.context(),
                         &mut e.input(),
                         &mut *e.decoder(),
                         &mut *e.output(),
                         &*e.encoder())
        }
        (sc, _) if !sc.is_empty() => panic!("Unimplemented subcommand `{}`, this is a bug", sc),
        _ => Ok(()),
    };

    match res {
        Ok(()) => (),
        Err(e) => error(Box::new(e)),
    }
}

pub fn error(e: Box<Error>) -> ! {
    let _ = writeln!(&mut io::stderr(), "Error: {}", e);
    let mut e = e.cause();
    while let Some(err) = e {
        let _ = writeln!(&mut io::stderr(), "\t{}", err);
        e = err.cause();
    }
    process::exit(1)
}

pub fn die(s: &str) -> ! {
    let _ = writeln!(&mut io::stderr(), "Aborting: {}", s);
    process::exit(1)
}

pub fn decoder(format: &str) -> Option<Box<Decode>> {
    match format {
        "energymech" | "em" => Some(Box::new(Energymech)),
        "weechat" | "w" => Some(Box::new(Weechat)),
        // "irssi" => Some(Box::new(irssi::Irssi)),
        // "binary" => Some(Box::new(Binary)),
        // "msgpack" => Some(Box::new(Msgpack)),
        _ => None,
    }
}

pub fn encoder(format: &str) -> Option<Box<Encode>> {
    match format {
        "energymech" | "em" => Some(Box::new(Energymech)),
        "weechat" | "w" => Some(Box::new(Weechat)),
        // "irssi" => Some(Box::new(irssi::Irssi)),
        // "binary" => Some(Box::new(Binary)),
        // "msgpack" => Some(Box::new(Msgpack)),
        _ => None,
    }
}

pub fn force_decoder(s: Option<&str>) -> Box<Decode> {
    let inf = match s {
        Some(s) => s,
        None => die("You didn't specify the input format"),
    };
    match decoder(&inf) {
        Some(d) => d,
        None => die(&format!("The format `{}` is unknown to me", inf)),
    }
}

pub fn force_encoder<'a>(s: Option<&str>) -> Box<Encode> {
    let outf = match s {
        Some(s) => s,
        None => die("You didn't specify the output format"),
    };
    match encoder(&outf) {
        Some(e) => e,
        None => die(&format!("The format `{}` is unknown to me", outf)),
    }
}

pub struct Environment<'a>(pub &'a ArgMatches<'a>);

impl<'a> Environment<'a> {
    pub fn context(&self) -> Context {
        build_context(self.0)
    }
    pub fn input(&self) -> Box<BufRead> {
        open_files(gather_input(self.0))
    }
    pub fn output(&self) -> Box<Write> {
        open_output(self.0)
    }
    pub fn decoder(&self) -> Box<Decode> {
        force_decoder(self.0.value_of("format").or(self.0.value_of("input_format")))
    }
    pub fn encoder(&self) -> Box<Encode> {
        force_encoder(self.0.value_of("format").or(self.0.value_of("output_format")))
    }
}

pub fn build_context(args: &ArgMatches) -> Context {
    let mut context = Context {
        timezone: FixedOffset::west(args.value_of("timezone")
                                        .and_then(|s| s.parse().ok())
                                        .unwrap_or(0)),
        override_date: args.value_of("date").and_then(|d| NaiveDate::from_str(&d).ok()),
        channel: args.value_of("channel").map(str::to_owned).clone(),
    };
    if args.is_present("infer_date") {
        let input_files = gather_input(args);
        match input_files.len() {
            0 => die("No input files given, can't infer date"),
            1 => {
                if let Some(date) = input_files.get(0)
                                               .map(PathBuf::as_path)
                                               .and_then(Path::file_stem)
                                               .and_then(OsStr::to_str)
                                               .and_then(|s: &str| NaiveDate::from_str(s).ok()) {
                    context.override_date = Some(date);
                }
            }
            _n => die("Too many input files, can't infer date"),
        }
    }
    context
}

pub fn gather_input(args: &ArgMatches) -> Vec<PathBuf> {
    if let Some(iter) = args.values_of("input_files") {
        iter.flat_map(|p| {
                match glob(p) {
                    Ok(paths) => paths,
                    Err(e) => die(&format!("{}", e.msg)),
                }
            })
            .filter_map(Result::ok)
            .collect()
    } else {
        Vec::new()
    }
}

pub fn open_files(files: Vec<PathBuf>) -> Box<BufRead> {
    if files.len() > 0 {
        Box::new(BufReader::new(chain::Chain::new(files.iter()
                                                       .map(|p| File::open(p).unwrap())
                                                       .collect())))
    } else {
        Box::new(BufReader::new(io::stdin()))
    }
}

pub fn open_output(args: &ArgMatches) -> Box<Write> {
    if let Some(out) = args.value_of("output_file") {
        match File::create(out) {
            Ok(f) => Box::new(BufWriter::new(f)),
            Err(e) => error(Box::new(e)),
        }
    } else {
        Box::new(BufWriter::new(io::stdout()))
    }
}
<commit_msg>Add "no command specified" special case message<commit_after>// Copyright 2015 Till Höppner
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate ilc_base;
extern crate ilc_ops;
extern crate ilc_format_weechat;
extern crate ilc_format_energymech;
extern crate chrono;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate glob;

use ilc_base::{Context, Decode, Encode};
use ilc_ops::*;
use ilc_format_weechat::Weechat;
use ilc_format_energymech::Energymech;

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

use chrono::{FixedOffset, NaiveDate};

use glob::glob;

use std::str::FromStr;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::{process, usize};
use std::error::Error;

mod chain;

pub fn main() {
    env_logger::init().unwrap();
    let args = App::new("ilc")
                   .version(crate_version!())
                   .setting(AppSettings::GlobalVersion)
                   .setting(AppSettings::VersionlessSubcommands)
                   .setting(AppSettings::ArgRequiredElseHelp)
                   .author("Till Höppner <till@hoeppner.ws>")
                   .about("A converter and statistics utility for IRC log files")
                   .arg(Arg::with_name("timezone")
                            .help("UTC offset in the direction of the western hemisphere")
                            .global(true)
                            .takes_value(true)
                            .long("timezone")
                            .short("t"))
                   .arg(Arg::with_name("date")
                            .help("Override the date for this log, ISO 8601, YYYY-MM-DD")
                            .global(true)
                            .takes_value(true)
                            .long("date")
                            .short("d"))
                   .arg(Arg::with_name("infer_date")
                            .help("Try to use the filename as date for the current log")
                            .global(true)
                            .long("infer-date"))
                   .arg(Arg::with_name("channel")
                            .help("Set a channel for the current log")
                            .global(true)
                            .takes_value(true)
                            .long("channel")
                            .short("c"))
                   .arg(Arg::with_name("format")
                            .help("Set the input and output format for the current log")
                            .global(true)
                            .takes_value(true)
                            .long("format")
                            .short("f"))
                   .arg(Arg::with_name("input_format")
                            .help("Set the input format for the current log")
                            .global(true)
                            .conflicts_with("format")
                            .takes_value(true)
                            .long("inf"))
                   .arg(Arg::with_name("output_format")
                            .help("Set the output format for the current log")
                            .global(true)
                            .conflicts_with("format")
                            .takes_value(true)
                            .long("outf"))
                   .arg(Arg::with_name("input_files")
                            .help("Specify an input file, instead of stdin")
                            .global(true)
                            .takes_value(true)
                            .multiple(true)
                            .long("input")
                            .short("i"))
                   .arg(Arg::with_name("output_file")
                            .help("Specify an output file, instead of stdout")
                            .global(true)
                            .takes_value(true)
                            .long("output")
                            .short("o"))
                   .subcommand(SubCommand::with_name("parse")
                                   .about("Parse the input, checking the format"))
                   .subcommand(SubCommand::with_name("convert")
                                   .about("Convert from a source to a target format"))
                   .subcommand(SubCommand::with_name("freq")
                                   .about("Analyse the activity of users by certain metrics")
                                   .arg(Arg::with_name("count")
                                            .help("The number of items to be displayed")
                                            .takes_value(true)
                                            .long("count")))
                   .subcommand(SubCommand::with_name("seen")
                                   .about("Print the last line a nick was active")
                                   .arg(Arg::with_name("nick")
                                            .help("The nick you're looking for")
                                            .takes_value(true)
                                            .required(true)
                                            .index(1)))
                   .subcommand(SubCommand::with_name("sort").about("Sorts a log by time"))
                   .subcommand(SubCommand::with_name("dedup")
                                   .about("Removes duplicate log entries in close proximity"))
                   .get_matches();

    let res = match args.subcommand() {
        ("parse", Some(args)) => {
            let e = Environment(&args);
            parse::parse(&e.context(), &mut e.input(), &mut *e.decoder())
        }
        ("convert", Some(args)) => {
            let e = Environment(&args);
            convert::convert(&e.context(),
                             &mut e.input(),
                             &mut *e.decoder(),
                             &mut *e.output(),
                             &*e.encoder())
        }
        ("freq", Some(args)) => {
            let e = Environment(&args);
            let count = value_t!(args, "count", usize).unwrap_or(usize::MAX);
            freq::freq(count,
                       &e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut e.output())
        }
        ("seen", Some(args)) => {
            let e = Environment(&args);
            let nick = args.value_of("nick").expect("Required argument <nick> not present");
            seen::seen(nick,
                       &e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut *e.output(),
                       &Weechat)
        }
        ("sort", Some(args)) => {
            let e = Environment(&args);
            sort::sort(&e.context(),
                       &mut e.input(),
                       &mut *e.decoder(),
                       &mut *e.output(),
                       &*e.encoder())
        }
        ("dedup", Some(args)) => {
            let e = Environment(&args);
            dedup::dedup(&e.context(),
                         &mut e.input(),
                         &mut *e.decoder(),
                         &mut *e.output(),
                         &*e.encoder())
        }
        (sc, _) if !sc.is_empty() => panic!("Unimplemented subcommand `{}`, this is a bug", sc),
        _ => die("No command specified"),
    };

    match res {
        Ok(()) => (),
        Err(e) => error(Box::new(e)),
    }
}

pub fn error(e: Box<Error>) -> ! {
    let _ = writeln!(&mut io::stderr(), "Error: {}", e);
    let mut e = e.cause();
    while let Some(err) = e {
        let _ = writeln!(&mut io::stderr(), "\t{}", err);
        e = err.cause();
    }
    process::exit(1)
}

pub fn die(s: &str) -> ! {
    let _ = writeln!(&mut io::stderr(), "Aborting: {}", s);
    process::exit(1)
}

pub fn decoder(format: &str) -> Option<Box<Decode>> {
    match format {
        "energymech" | "em" => Some(Box::new(Energymech)),
        "weechat" | "w" => Some(Box::new(Weechat)),
        // "irssi" => Some(Box::new(irssi::Irssi)),
        // "binary" => Some(Box::new(Binary)),
        // "msgpack" => Some(Box::new(Msgpack)),
        _ => None,
    }
}

pub fn encoder(format: &str) -> Option<Box<Encode>> {
    match format {
        "energymech" | "em" => Some(Box::new(Energymech)),
        "weechat" | "w" => Some(Box::new(Weechat)),
        // "irssi" => Some(Box::new(irssi::Irssi)),
        // "binary" => Some(Box::new(Binary)),
        // "msgpack" => Some(Box::new(Msgpack)),
        _ => None,
    }
}

pub fn force_decoder(s: Option<&str>) -> Box<Decode> {
    let inf = match s {
        Some(s) => s,
        None => die("You didn't specify the input format"),
    };
    match decoder(&inf) {
        Some(d) => d,
        None => die(&format!("The format `{}` is unknown to me", inf)),
    }
}

pub fn force_encoder<'a>(s: Option<&str>) -> Box<Encode> {
    let outf = match s {
        Some(s) => s,
        None => die("You didn't specify the output format"),
    };
    match encoder(&outf) {
        Some(e) => e,
        None => die(&format!("The format `{}` is unknown to me", outf)),
    }
}

pub struct Environment<'a>(pub &'a ArgMatches<'a>);

impl<'a> Environment<'a> {
    pub fn context(&self) -> Context {
        build_context(self.0)
    }
    pub fn input(&self) -> Box<BufRead> {
        open_files(gather_input(self.0))
    }
    pub fn output(&self) -> Box<Write> {
        open_output(self.0)
    }
    pub fn decoder(&self) -> Box<Decode> {
        force_decoder(self.0.value_of("format").or(self.0.value_of("input_format")))
    }
    pub fn encoder(&self) -> Box<Encode> {
        force_encoder(self.0.value_of("format").or(self.0.value_of("output_format")))
    }
}

pub fn build_context(args: &ArgMatches) -> Context {
    let mut context = Context {
        timezone: FixedOffset::west(args.value_of("timezone")
                                        .and_then(|s| s.parse().ok())
                                        .unwrap_or(0)),
        override_date: args.value_of("date").and_then(|d| NaiveDate::from_str(&d).ok()),
        channel: args.value_of("channel").map(str::to_owned).clone(),
    };
    if args.is_present("infer_date") {
        let input_files = gather_input(args);
        match input_files.len() {
            0 => die("No input files given, can't infer date"),
            1 => {
                if let Some(date) = input_files.get(0)
                                               .map(PathBuf::as_path)
                                               .and_then(Path::file_stem)
                                               .and_then(OsStr::to_str)
                                               .and_then(|s: &str| NaiveDate::from_str(s).ok()) {
                    context.override_date = Some(date);
                }
            }
            _n => die("Too many input files, can't infer date"),
        }
    }
    context
}

pub fn gather_input(args: &ArgMatches) -> Vec<PathBuf> {
    if let Some(iter) = args.values_of("input_files") {
        iter.flat_map(|p| {
                match glob(p) {
                    Ok(paths) => paths,
                    Err(e) => die(&format!("{}", e.msg)),
                }
            })
            .filter_map(Result::ok)
            .collect()
    } else {
        Vec::new()
    }
}

pub fn open_files(files: Vec<PathBuf>) -> Box<BufRead> {
    if files.len() > 0 {
        Box::new(BufReader::new(chain::Chain::new(files.iter()
                                                       .map(|p| File::open(p).unwrap())
                                                       .collect())))
    } else {
        Box::new(BufReader::new(io::stdin()))
    }
}

pub fn open_output(args: &ArgMatches) -> Box<Write> {
    if let Some(out) = args.value_of("output_file") {
        match File::create(out) {
            Ok(f) => Box::new(BufWriter::new(f)),
            Err(e) => error(Box::new(e)),
        }
    } else {
        Box::new(BufWriter::new(io::stdout()))
    }
}
<|endoftext|>


<commit_before> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::TcpStream;
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

pub struct Client {
  connection: BufStream<TcpStream>,
  space: String,
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
pub struct Datum {
  pub content: Vec<u8>
}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    Ok(Client { connection: BufStream::new(sock), space: space })
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Self::encode_truncate(&mut message, &self.space);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Self::encode_write(&mut message, &self.space, key, val);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Self::encode_read(&mut message, &self.space, key);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_datum_list(&message_reader)
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<commit_msg>Start factoring out a protocol layer: requests.<commit_after> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::TcpStream;
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

pub struct Client {
  connection: BufStream<TcpStream>,
  space: String,
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
pub struct Datum {
  pub content: Vec<u8>
}

pub struct Request {
  space: String,
  operation: Operation,
}
pub enum Operation {
  Truncate ,
  Read { key: Vec<u8> },
  Write { key: Vec<u8>, value: Vec<u8> },
}

impl Request {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    match &self.operation {
      &Operation::Truncate => Self::encode_truncate(message, &self.space),
      &Operation::Read { key: ref key } => Self::encode_read(message, &self.space, &key),
      &Operation::Write { key: ref key, value: ref val } => Self::encode_write(message, &self.space, &key, &val),
    }
  }

  fn truncate(space: &str) -> Request {
    Request { space: space.to_string(), operation: Operation::Truncate }
  }

  fn read(space: &str, key: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Read { key: key.to_vec() } }
  }

  fn write(space: &str, key: &[u8], value: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Write { key: key.to_owned(), value: value.to_owned() } }
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }

}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    Ok(Client { connection: BufStream::new(sock), space: space })
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Request::truncate(&self.space).encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Request::write(&self.space, key, val).encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let mut message = MallocMessageBuilder::new_default();
    Request::read(&self.space, key).encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_datum_list(&message_reader)
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<|endoftext|>