<commit_before>// Copyright 2016 Google Inc.
//
// 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.

use byteorder::{LittleEndian, ByteOrder};
use math::Vector3f;
use Point;
use std::fs::File;
use std::io::{BufRead, BufReader, SeekFrom, Seek};
use std::ops::Index;
use std::path::Path;
use std::str;
use errors::*;

#[derive(Debug)]
struct Header {
    format: Format,
    elements: Vec<Element>,
}

#[derive(Debug,Copy,Clone,PartialEq)]
enum DataType {
    Int8,
    Uint8,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Float32,
    Float64,
}

impl DataType {
    fn from_str(input: &str) -> Result<Self> {
        match input {
            "float" | "float32" => Ok(DataType::Float32),
            "double" | "float64" => Ok(DataType::Float64),
            "char" | "int8" => Ok(DataType::Int8),
            "uchar" | "uint8" => Ok(DataType::Uint8),
            "short" | "int16" => Ok(DataType::Int16),
            "ushort" | "uint16" => Ok(DataType::Uint16),
            "int" | "int32" => Ok(DataType::Int32),
            "uint" | "uint32" => Ok(DataType::Uint32),
            _ => Err(ErrorKind::InvalidInput(format!("Invalid data type: {}", input)).into()),
        }
    }

    fn size_in_bytes(&self) -> usize {
        match *self {
            DataType::Int8 => 1,
            DataType::Uint8 => 1,
            DataType::Int16 => 2,
            DataType::Uint16 => 2,
            DataType::Int32 => 4,
            DataType::Uint32 => 4,
            DataType::Float32 => 4,
            DataType::Float64 => 8,
        }
    }

    fn read<B: ByteOrder>(&self, slice: &[u8]) -> f32 {
        match *self {
            DataType::Int8 => (slice[0] as i8) as f32,
            DataType::Uint8 => slice[0] as f32,
            DataType::Int16 => B::read_i16(slice) as f32,
            DataType::Uint16 => B::read_u16(slice) as f32,
            DataType::Int32 => B::read_i32(slice) as f32,
            DataType::Uint32 => B::read_u32(slice) as f32,
            DataType::Float32 => B::read_f32(slice) as f32,
            DataType::Float64 => B::read_f64(slice) as f32,
        }
    }
}

impl Header {
    fn has_element(&self, name: &str) -> bool {
        self.elements.iter().any(|e| e.name == name)
    }
}

impl<'a> Index<&'a str> for Header {
    type Output = Element;
    fn index(&self, name: &'a str) -> &Self::Output {
        for element in &self.elements {
            if element.name == name {
                return element;
            }
        }
        panic!("Element {} does not exist.", name);
    }
}

#[derive(Debug,PartialEq)]
enum Format {
    BinaryLittleEndianV1,
    BinaryBigEndianV1,
    AsciiV1,
}

// TODO(hrapp): Maybe support list properties too?
#[derive(Debug)]
struct ScalarProperty {
    name: String,
    data_type: DataType,
}

#[derive(Debug)]
struct Element {
    name: String,
    count: i64,
    properties: Vec<ScalarProperty>,
}

impl<'a> Index<&'a str> for Element {
    type Output = ScalarProperty;
    fn index(&self, name: &'a str) -> &Self::Output {
        for p in &self.properties {
            if p.name == name {
                return p;
            }
        }
        panic!("Property does not exist!")
    }
}

impl Element {
    fn has_property(&self, name: &str) -> bool {
        self.properties.iter().any(|p| p.name == name)
    }
}

fn parse_header<R: BufRead>(reader: &mut R) -> Result<(Header, usize)> {
    use errors::ErrorKind::InvalidInput;

    let mut header_len = 0;
    let mut line = String::new();
    header_len += reader.read_line(&mut line)?;
    if line.trim() != "ply" {
        return Err(InvalidInput("Not a PLY file".to_string()).into());
    }

    let mut format = None;
    let mut current_element = None;
    let mut elements = Vec::new();
    loop {
        line.clear();
        header_len += reader.read_line(&mut line)?;
        let entries: Vec<&str> = line.trim().split_whitespace().collect();
        match entries[0] {
            "format" if entries.len() == 3 => {
                if entries[2] != "1.0" {
                    return Err(InvalidInput(format!("Invalid version: {}", entries[2])).into());
                }
                format = Some(match entries[1] {
                    "ascii" => Format::AsciiV1,
                    "binary_little_endian" => Format::BinaryLittleEndianV1,
                    "binary_big_endian" => Format::BinaryBigEndianV1,
                    _ => return Err(InvalidInput(format!("Invalid format: {}", entries[1])).into()),
                });
            }
            "element" if entries.len() == 3 => {
                if let Some(element) = current_element.take() {
                    elements.push(element);
                }
                current_element = Some(Element {
                    name: entries[1].to_string(),
                    count: entries[2].parse::<i64>()
                        .chain_err(|| InvalidInput(format!("Invalid count: {}", entries[2])))?,
                    properties: Vec::new(),
                });
            }
            "property" => {
                if current_element.is_none() {
                    return Err(InvalidInput(format!("property outside of element: {}", line))
                        .into());
                };
                let property = match entries[1] {
                    "list" if entries.len() == 5 => {
                        // We do not support list properties.
                        continue;
                    }
                    data_type_str if entries.len() == 3 => {
                        let data_type = DataType::from_str(data_type_str)?;
                        ScalarProperty {
                            name: entries[2].to_string(),
                            data_type: data_type,
                        }
                    }
                    _ => return Err(InvalidInput(format!("Invalid line: {}", line)).into()),
                };
                current_element.as_mut().unwrap().properties.push(property);
            }
            "end_header" => break,
            "comment" => (),
            _ => return Err(InvalidInput(format!("Invalid line: {}", line)).into()),
        }
    }

    if let Some(element) = current_element {
        elements.push(element);
    }

    if format.is_none() {
        return Err(InvalidInput("No format specified".into()).into());
    }

    Ok((Header {
            elements: elements,
            format: format.unwrap(),
        },
        header_len))
}

#[derive(Debug)]
struct PointFormat {
    position_data_type: DataType,
    // None, if the file does not contain color.
    color_data_type: Option<DataType>,
}

/// Opens a PLY file and checks that it is the correct format we support. Seeks in the file to the
/// beginning of the binary data which must be (x, y, z, r, g, b) tuples.
fn open(ply_file: &Path) -> Result<(BufReader<File>, i64, PointFormat)> {
    let mut file = File::open(ply_file).chain_err(|| "Could not open input file.")?;
    let mut reader = BufReader::new(file);
    let (header, header_len) = parse_header(&mut reader)?;
    file = reader.into_inner();
    file.seek(SeekFrom::Start(header_len as u64))?;

    if !header.has_element("vertex") {
        panic!("Header does not have element 'vertex'");
    }

    if header.format != Format::BinaryLittleEndianV1 {
        panic!("Unsupported PLY format: {:?}", header.format);
    }

    let vertex = &header["vertex"];
    if !vertex.has_property("x") || !vertex.has_property("y") || !vertex.has_property("z") {
        panic!("PLY must contain properties 'x', 'y', 'z' for 'vertex'.");
    }

    let mut num_bytes_per_point = 0;
    let position_data_type = header["vertex"]["x"].data_type;
    num_bytes_per_point += position_data_type.size_in_bytes() * 3;

    // TODO(hrapp): We silently assume that data types of (y, z) is that of x and similar for
    // colors. Track this properly.
    let color_data_type = {
        if vertex.has_property("red") && vertex.has_property("green") &&
           vertex.has_property("blue") {
            Some(vertex["red"].data_type)
        } else if vertex.has_property("r") && vertex.has_property("g") && vertex.has_property("b") {
            Some(vertex["r"].data_type)
        } else {
            None
        }
    };
    if let Some(ref data_type) = color_data_type {
        num_bytes_per_point += data_type.size_in_bytes() * 3;
    }

    let point_format = PointFormat {
        position_data_type: position_data_type,
        color_data_type: color_data_type,
    };

    // We align the buffer of this 'BufReader' to points, so that we can index this buffer and know
    // that it will always contain full points to parse.
    Ok((BufReader::with_capacity(num_bytes_per_point * 1024, file),
        header["vertex"].count,
        point_format))
}

/// Abstraction to read binary points from ply files into points.
pub struct PlyIterator {
    reader: BufReader<File>,
    point_format: PointFormat,
    num_points_read: i64,
    pub num_total_points: i64,
}

impl PlyIterator {
    pub fn new(ply_file: &Path) -> Result<Self> {
        let (reader, num_total_points, point_format) = open(ply_file)?;
        Ok(PlyIterator {
            reader: reader,
            point_format: point_format,
            num_total_points: num_total_points,
            num_points_read: 0,
        })
    }
}

impl Iterator for PlyIterator {
    type Item = Point;

    fn next(&mut self) -> Option<Self::Item> {
        if self.num_points_read >= self.num_total_points {
            return None;
        }

        let mut nread = 0;
        let point = {
            // We made sure before that the internal buffer of 'reader' is aligned to the number of
            // bytes for a single point, therefore we can access it here and know that we can
            // always read into it and are sure that it contains at least a full point.
            let buf = self.reader.fill_buf().unwrap();

            let position = {
                let data_type = &self.point_format.position_data_type;
                let size_in_bytes = data_type.size_in_bytes();
                let x = data_type.read::<LittleEndian>(&buf[nread..]);
                nread += size_in_bytes;
                let y = data_type.read::<LittleEndian>(&buf[nread..]);
                nread += size_in_bytes;
                let z = data_type.read::<LittleEndian>(&buf[nread..]);
                nread += size_in_bytes;
                Vector3f::new(x, y, z)
            };

            let mut r = 255;
            let mut g = 255;
            let mut b = 255;
            if let Some(ref data_type) = self.point_format.color_data_type {
                let size_in_bytes = data_type.size_in_bytes();
                r = data_type.read::<LittleEndian>(&buf[nread..]) as u8;
                nread += size_in_bytes;
                g = data_type.read::<LittleEndian>(&buf[nread..]) as u8;
                nread += size_in_bytes;
                b = data_type.read::<LittleEndian>(&buf[nread..]) as u8;
                nread += size_in_bytes;
            };

            Point {
                position: position,
                r: r,
                g: g,
                b: b,
            }
        };
        self.num_points_read += 1;
        self.reader.consume(nread);
        Some(point)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.num_total_points as usize, Some(self.num_total_points as usize))
    }
}
<commit_msg>Make PLY reading more general. (#24)<commit_after>// Copyright 2016 Google Inc.
//
// 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.

use Point;
use byteorder::{LittleEndian, ByteOrder};
use errors::*;
use math::Vector3f;
use std::fs::File;
use std::io::{BufRead, BufReader, SeekFrom, Seek};
use std::ops::Index;
use std::path::Path;
use std::str;

#[derive(Debug)]
struct Header {
    format: Format,
    elements: Vec<Element>,
}

#[derive(Debug,Copy,Clone,PartialEq)]
enum DataType {
    Int8,
    Uint8,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Float32,
    Float64,
}

impl DataType {
    fn from_str(input: &str) -> Result<Self> {
        match input {
            "float" | "float32" => Ok(DataType::Float32),
            "double" | "float64" => Ok(DataType::Float64),
            "char" | "int8" => Ok(DataType::Int8),
            "uchar" | "uint8" => Ok(DataType::Uint8),
            "short" | "int16" => Ok(DataType::Int16),
            "ushort" | "uint16" => Ok(DataType::Uint16),
            "int" | "int32" => Ok(DataType::Int32),
            "uint" | "uint32" => Ok(DataType::Uint32),
            _ => Err(ErrorKind::InvalidInput(format!("Invalid data type: {}", input)).into()),
        }
    }
}

impl Header {
    fn has_element(&self, name: &str) -> bool {
        self.elements.iter().any(|e| e.name == name)
    }
}

impl<'a> Index<&'a str> for Header {
    type Output = Element;
    fn index(&self, name: &'a str) -> &Self::Output {
        for element in &self.elements {
            if element.name == name {
                return element;
            }
        }
        panic!("Element {} does not exist.", name);
    }
}

#[derive(Debug,PartialEq)]
enum Format {
    BinaryLittleEndianV1,
    BinaryBigEndianV1,
    AsciiV1,
}

// TODO(hrapp): Maybe support list properties too?
#[derive(Debug)]
struct ScalarProperty {
    name: String,
    data_type: DataType,
}

#[derive(Debug)]
struct Element {
    name: String,
    count: i64,
    properties: Vec<ScalarProperty>,
}

impl<'a> Index<&'a str> for Element {
    type Output = ScalarProperty;
    fn index(&self, name: &'a str) -> &Self::Output {
        for p in &self.properties {
            if p.name == name {
                return p;
            }
        }
        panic!("Property does not exist!")
    }
}

fn parse_header<R: BufRead>(reader: &mut R) -> Result<(Header, usize)> {
    use errors::ErrorKind::InvalidInput;

    let mut header_len = 0;
    let mut line = String::new();
    header_len += reader.read_line(&mut line)?;
    if line.trim() != "ply" {
        return Err(InvalidInput("Not a PLY file".to_string()).into());
    }

    let mut format = None;
    let mut current_element = None;
    let mut elements = Vec::new();
    loop {
        line.clear();
        header_len += reader.read_line(&mut line)?;
        let entries: Vec<&str> = line.trim().split_whitespace().collect();
        match entries[0] {
            "format" if entries.len() == 3 => {
                if entries[2] != "1.0" {
                    return Err(InvalidInput(format!("Invalid version: {}", entries[2])).into());
                }
                format = Some(match entries[1] {
                                  "ascii" => Format::AsciiV1,
                                  "binary_little_endian" => Format::BinaryLittleEndianV1,
                                  "binary_big_endian" => Format::BinaryBigEndianV1,
                                  _ => {
                                      return Err(InvalidInput(format!("Invalid format: {}",
                                                                      entries[1]))
                                                         .into())
                                  }
                              });
            }
            "element" if entries.len() == 3 => {
                if let Some(element) = current_element.take() {
                    elements.push(element);
                }
                current_element =
                    Some(Element {
                             name: entries[1].to_string(),
                             count: entries[2].parse::<i64>()
                                 .chain_err(|| {
                                                InvalidInput(format!("Invalid count: {}",
                                                                     entries[2]))
                                            })?,
                             properties: Vec::new(),
                         });
            }
            "property" => {
                if current_element.is_none() {
                    return Err(InvalidInput(format!("property outside of element: {}", line))
                                   .into());
                };
                let property = match entries[1] {
                    "list" if entries.len() == 5 => {
                        // We do not support list properties.
                        continue;
                    }
                    data_type_str if entries.len() == 3 => {
                        let data_type = DataType::from_str(data_type_str)?;
                        ScalarProperty {
                            name: entries[2].to_string(),
                            data_type: data_type,
                        }
                    }
                    _ => return Err(InvalidInput(format!("Invalid line: {}", line)).into()),
                };
                current_element.as_mut()
                    .unwrap()
                    .properties
                    .push(property);
            }
            "end_header" => break,
            "comment" => (),
            _ => return Err(InvalidInput(format!("Invalid line: {}", line)).into()),
        }
    }

    if let Some(element) = current_element {
        elements.push(element);
    }

    if format.is_none() {
        return Err(InvalidInput("No format specified".into()).into());
    }

    Ok((Header {
            elements: elements,
            format: format.unwrap(),
        },
        header_len))
}

type ReadingFn = fn(nread: &mut usize, buf: &[u8], val: &mut Point);

// The two macros create a 'ReadingFn' that reads a value of '$data_type' out of a reader, assigns
// it to '$property' (e.g. 'position.x') of 'point' while casting it to the correct type. I did not
// find a way of doing this purely using generic programming, so I resorted to this macro.
macro_rules! create_and_return_reading_fn {
    ($data_type:expr, $($property:ident).+, $size:ident, $num_bytes:expr, $reading_fn:expr) => (
        {
            $size += $num_bytes;
            fn _read_fn(nread: &mut usize, buf: &[u8], point: &mut Point) {
                point $( .$property )+ = $reading_fn(buf) as _;
                *nread += $num_bytes;
            }
            _read_fn
        }
    )
}

macro_rules! read_casted_property {
    ($data_type:expr, point. $($property:ident).+, &mut $size:ident) => (
        match $data_type {
            DataType::Uint8 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 1,
                    |buf: &[u8]| buf[0])
            },
            DataType::Int8 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 1,
                    |buf: &[u8]| buf[0])
            },
            DataType::Uint16 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 2,
                    LittleEndian::read_u16)
            },
            DataType::Int16 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 2,
                    LittleEndian::read_i16)
            },
            DataType::Uint32 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 4,
                    LittleEndian::read_u32)
            },
            DataType::Int32 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 4,
                    LittleEndian::read_i32)
            },
            DataType::Float32 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 4,
                    LittleEndian::read_f32)
            },
            DataType::Float64 => {
                create_and_return_reading_fn!($data_type, $($property).+, $size, 8,
                    LittleEndian::read_f64)
            },
        }
    )
}

/// Opens a PLY file and checks that it is the correct format we support. Seeks in the file to the
/// beginning of the binary data which must be (x, y, z, r, g, b) tuples.
fn open(ply_file: &Path) -> Result<(BufReader<File>, i64, Vec<ReadingFn>)> {
    let mut file = File::open(ply_file).chain_err(|| "Could not open input file.")?;
    let mut reader = BufReader::new(file);
    let (header, header_len) = parse_header(&mut reader)?;
    file = reader.into_inner();
    file.seek(SeekFrom::Start(header_len as u64))?;

    if !header.has_element("vertex") {
        panic!("Header does not have element 'vertex'");
    }

    if header.format != Format::BinaryLittleEndianV1 {
        panic!("Unsupported PLY format: {:?}", header.format);
    }

    let vertex = &header["vertex"];
    let mut seen_x = false;
    let mut seen_y = false;
    let mut seen_z = false;

    let mut readers: Vec<ReadingFn> = Vec::new();
    let mut num_bytes_per_point = 0;

    for prop in &vertex.properties {
        match &prop.name as &str {
            "x" => {
                readers.push(read_casted_property!(prop.data_type,
                                                   point.position.x,
                                                   &mut num_bytes_per_point));
                seen_x = true;
            }
            "y" => {
                readers.push(read_casted_property!(prop.data_type,
                                                   point.position.y,
                                                   &mut num_bytes_per_point));
                seen_y = true;
            }
            "z" => {
                readers.push(read_casted_property!(prop.data_type,
                                                   point.position.z,
                                                   &mut num_bytes_per_point));
                seen_z = true;
            }
            "r" | "red" => {
                readers.push(read_casted_property!(prop.data_type, point.r, &mut num_bytes_per_point));
            }
            "g" | "green" => {
                readers.push(read_casted_property!(prop.data_type, point.g, &mut num_bytes_per_point));
            }
            "b" | "blue" => {
                readers.push(read_casted_property!(prop.data_type, point.b, &mut num_bytes_per_point));
            }
            other => {
                // TODO(hrapp): Implement skipping of unknown properties.
                panic!("Unknown property '{}' on 'vertex'.", other)
            }
        }
    }

    if !seen_x || !seen_y || !seen_z {
        panic!("PLY must contain properties 'x', 'y', 'z' for 'vertex'.");
    }

    // We align the buffer of this 'BufReader' to points, so that we can index this buffer and know
    // that it will always contain full points to parse.
    Ok((BufReader::with_capacity(num_bytes_per_point * 1024, file),
        header["vertex"].count,
        readers))
}

/// Abstraction to read binary points from ply files into points.
pub struct PlyIterator {
    reader: BufReader<File>,
    readers: Vec<ReadingFn>,
    num_points_read: i64,
    pub num_total_points: i64,
}

impl PlyIterator {
    pub fn new(ply_file: &Path) -> Result<Self> {
        let (reader, num_total_points, readers) = open(ply_file)?;
        Ok(PlyIterator {
               reader: reader,
               readers: readers,
               num_total_points: num_total_points,
               num_points_read: 0,
           })
    }
}

impl Iterator for PlyIterator {
    type Item = Point;

    fn next(&mut self) -> Option<Self::Item> {
        if self.num_points_read >= self.num_total_points {
            return None;
        }

        let mut nread = 0;

        // We made sure before that the internal buffer of 'reader' is aligned to the number of
        // bytes for a single point, therefore we can access it here and know that we can
        // always read into it and are sure that it contains at least a full point.
        let mut point = Point {
            position: Vector3f::new(0., 0., 0.),
            r: 255,
            g: 255,
            b: 255,
        };
        {
            let buf = self.reader.fill_buf().unwrap();
            for r in &self.readers {
                let cnread = nread;
                r(&mut nread, &buf[cnread..], &mut point);
            }
        }

        self.num_points_read += 1;
        self.reader.consume(nread);
        Some(point)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.num_total_points as usize, Some(self.num_total_points as usize))
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! YAML Serialization
//!
//! This module provides YAML serialization with the type `Serializer`.

use std::{fmt, io};

use yaml_rust::{yaml, Yaml, YamlEmitter};

use serde::ser;

use super::error::{Error, Result};

pub struct Serializer;

impl ser::Serializer for Serializer {
    type Ok = Yaml;
    type Error = Error;

    type SerializeSeq = SerializeArray;
    type SerializeTuple = SerializeArray;
    type SerializeTupleStruct = SerializeArray;
    type SerializeTupleVariant = SerializeTupleVariant;
    type SerializeMap = SerializeMap;
    type SerializeStruct = SerializeStruct;
    type SerializeStructVariant = SerializeStructVariant;

    fn serialize_bool(self, v: bool) -> Result<Yaml> {
        Ok(Yaml::Boolean(v))
    }

    fn serialize_i8(self, v: i8) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(self, v: i64) -> Result<Yaml> {
        Ok(Yaml::Integer(v))
    }

    fn serialize_u8(self, v: u8) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(self, v: u16) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(self, v: u32) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(self, v: u64) -> Result<Yaml> {
        Ok(Yaml::Real(v.to_string()))
    }

    fn serialize_f32(self, v: f32) -> Result<Yaml> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, v: f64) -> Result<Yaml> {
        Ok(Yaml::Real(v.to_string()))
    }

    fn serialize_char(self, value: char) -> Result<Yaml> {
        Ok(Yaml::String(value.to_string()))
    }

    fn serialize_str(self, value: &str) -> Result<Yaml> {
        Ok(Yaml::String(value.to_owned()))
    }

    fn serialize_bytes(self, value: &[u8]) -> Result<Yaml> {
        let vec = value.iter().map(|&b| Yaml::Integer(b as i64)).collect();
        Ok(Yaml::Array(vec))
    }

    fn serialize_unit(self) -> Result<Yaml> {
        Ok(Yaml::Null)
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Yaml> {
        self.serialize_unit()
    }

    fn serialize_unit_variant(self,
                              _name: &str,
                              _variant_index: u32,
                              variant: &str)
                              -> Result<Yaml> {
        Ok(Yaml::String(variant.to_owned()))
    }

    fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<Yaml>
        where T: ser::Serialize
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            _name: &str,
                                            _variant_index: u32,
                                            variant: &str,
                                            value: &T)
                                            -> Result<Yaml>
        where T: ser::Serialize
    {
        Ok(singleton_hash(to_yaml(variant)?, to_yaml(value)?))
    }

    fn serialize_none(self) -> Result<Yaml> {
        self.serialize_unit()
    }

    fn serialize_some<V: ?Sized>(self, value: &V) -> Result<Yaml>
        where V: ser::Serialize
    {
        value.serialize(self)
    }

    fn serialize_seq(self, len: Option<usize>) -> Result<SerializeArray> {
        let array = match len {
            None => yaml::Array::new(),
            Some(len) => yaml::Array::with_capacity(len),
        };
        Ok(SerializeArray { array: array })
    }

    fn serialize_tuple(self, len: usize) -> Result<SerializeArray> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result<SerializeArray> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(self,
                               _enum: &'static str,
                               _idx: u32,
                               variant: &'static str,
                               len: usize)
                               -> Result<SerializeTupleVariant> {
        Ok(SerializeTupleVariant {
               name: variant,
               array: yaml::Array::with_capacity(len),
           })
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<SerializeMap> {
        Ok(SerializeMap {
               hash: yaml::Hash::new(),
               next_key: None,
           })
    }

    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<SerializeStruct> {
        Ok(SerializeStruct { hash: yaml::Hash::new() })
    }

    fn serialize_struct_variant(self,
                                _enum: &'static str,
                                _idx: u32,
                                variant: &'static str,
                                _len: usize)
                                -> Result<SerializeStructVariant> {
        Ok(SerializeStructVariant {
               name: variant,
               hash: yaml::Hash::new(),
           })
    }
}

#[doc(hidden)]
pub struct SerializeArray {
    array: yaml::Array,
}

#[doc(hidden)]
pub struct SerializeTupleVariant {
    name: &'static str,
    array: yaml::Array,
}

#[doc(hidden)]
pub struct SerializeMap {
    hash: yaml::Hash,
    next_key: Option<yaml::Yaml>,
}

#[doc(hidden)]
pub struct SerializeStruct {
    hash: yaml::Hash,
}

#[doc(hidden)]
pub struct SerializeStructVariant {
    name: &'static str,
    hash: yaml::Hash,
}

impl ser::SerializeSeq for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_element<T: ?Sized>(&mut self, elem: &T) -> Result<()>
        where T: ser::Serialize
    {
        self.array.push(to_yaml(elem)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Array(self.array))
    }
}

impl ser::SerializeTuple for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_element<T: ?Sized>(&mut self, elem: &T) -> Result<()>
        where T: ser::Serialize
    {
        ser::SerializeSeq::serialize_element(self, elem)
    }

    fn end(self) -> Result<Yaml> {
        ser::SerializeSeq::end(self)
    }
}

impl ser::SerializeTupleStruct for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, value: &V) -> Result<()>
        where V: ser::Serialize
    {
        ser::SerializeSeq::serialize_element(self, value)
    }

    fn end(self) -> Result<Yaml> {
        ser::SerializeSeq::end(self)
    }
}

impl ser::SerializeTupleVariant for SerializeTupleVariant {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, v: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.array.push(to_yaml(v)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(singleton_hash(to_yaml(self.name)?, Yaml::Array(self.array)))
    }
}

impl ser::SerializeMap for SerializeMap {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
        where T: ser::Serialize
    {
        self.next_key = Some(to_yaml(key)?);
        Ok(())
    }

    fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
        where T: ser::Serialize
    {
        match self.next_key.take() {
            Some(key) => self.hash.insert(key, to_yaml(value)?),
            None => panic!("serialize_value called before serialize_key"),
        };
        Ok(())
    }

    fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<()>
        where K: ser::Serialize,
              V: ser::Serialize
    {
        self.hash.insert(to_yaml(key)?, to_yaml(value)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Hash(self.hash))
    }
}

impl ser::SerializeStruct for SerializeStruct {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, key: &'static str, value: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.hash.insert(to_yaml(key)?, to_yaml(value)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Hash(self.hash))
    }
}

impl ser::SerializeStructVariant for SerializeStructVariant {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, field: &'static str, v: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.hash.insert(to_yaml(field)?, to_yaml(v)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(singleton_hash(to_yaml(self.name)?, Yaml::Hash(self.hash)))
    }
}

/// Serialize the given data structure as YAML into the IO stream.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_writer<W: ?Sized, T: ?Sized>(writer: &mut W, value: &T) -> Result<()>
    where W: io::Write,
          T: ser::Serialize
{
    let doc = to_yaml(value)?;
    let mut writer_adapter = FmtToIoWriter { writer: writer };
    YamlEmitter::new(&mut writer_adapter).dump(&doc).map_err(Error::emitter)?;
    Ok(())
}

/// Serialize the given data structure as a YAML byte vector.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>>
    where T: ser::Serialize
{
    let mut vec = Vec::with_capacity(128);
    to_writer(&mut vec, value)?;
    Ok(vec)
}

/// Serialize the given data structure as a String of YAML.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_string<T: ?Sized>(value: &T) -> Result<String>
    where T: ser::Serialize
{
    Ok(String::from_utf8(to_vec(value)?).map_err(Error::string_utf8)?)
}

/// The yaml-rust library uses `fmt::Write` intead of `io::Write` so this is a
/// simple adapter.
struct FmtToIoWriter<'a, W: ?Sized>
    where W: io::Write + 'a
{
    writer: &'a mut W,
}

impl<'a, W: ?Sized> fmt::Write for FmtToIoWriter<'a, W>
    where W: io::Write + 'a
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if self.writer.write(s.as_bytes()).is_err() {
            return Err(fmt::Error);
        }
        Ok(())
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
fn to_yaml<T>(elem: T) -> Result<Yaml>
    where T: ser::Serialize
{
    elem.serialize(Serializer)
}

fn singleton_hash(k: Yaml, v: Yaml) -> Yaml {
    let mut hash = yaml::Hash::new();
    hash.insert(k, v);
    Yaml::Hash(hash)
}
<commit_msg>Match serde_json's signature of to_writer<commit_after>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! YAML Serialization
//!
//! This module provides YAML serialization with the type `Serializer`.

use std::{fmt, io};

use yaml_rust::{yaml, Yaml, YamlEmitter};

use serde::ser;

use super::error::{Error, Result};

pub struct Serializer;

impl ser::Serializer for Serializer {
    type Ok = Yaml;
    type Error = Error;

    type SerializeSeq = SerializeArray;
    type SerializeTuple = SerializeArray;
    type SerializeTupleStruct = SerializeArray;
    type SerializeTupleVariant = SerializeTupleVariant;
    type SerializeMap = SerializeMap;
    type SerializeStruct = SerializeStruct;
    type SerializeStructVariant = SerializeStructVariant;

    fn serialize_bool(self, v: bool) -> Result<Yaml> {
        Ok(Yaml::Boolean(v))
    }

    fn serialize_i8(self, v: i8) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(self, v: i64) -> Result<Yaml> {
        Ok(Yaml::Integer(v))
    }

    fn serialize_u8(self, v: u8) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(self, v: u16) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(self, v: u32) -> Result<Yaml> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(self, v: u64) -> Result<Yaml> {
        Ok(Yaml::Real(v.to_string()))
    }

    fn serialize_f32(self, v: f32) -> Result<Yaml> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, v: f64) -> Result<Yaml> {
        Ok(Yaml::Real(v.to_string()))
    }

    fn serialize_char(self, value: char) -> Result<Yaml> {
        Ok(Yaml::String(value.to_string()))
    }

    fn serialize_str(self, value: &str) -> Result<Yaml> {
        Ok(Yaml::String(value.to_owned()))
    }

    fn serialize_bytes(self, value: &[u8]) -> Result<Yaml> {
        let vec = value.iter().map(|&b| Yaml::Integer(b as i64)).collect();
        Ok(Yaml::Array(vec))
    }

    fn serialize_unit(self) -> Result<Yaml> {
        Ok(Yaml::Null)
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Yaml> {
        self.serialize_unit()
    }

    fn serialize_unit_variant(self,
                              _name: &str,
                              _variant_index: u32,
                              variant: &str)
                              -> Result<Yaml> {
        Ok(Yaml::String(variant.to_owned()))
    }

    fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<Yaml>
        where T: ser::Serialize
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            _name: &str,
                                            _variant_index: u32,
                                            variant: &str,
                                            value: &T)
                                            -> Result<Yaml>
        where T: ser::Serialize
    {
        Ok(singleton_hash(to_yaml(variant)?, to_yaml(value)?))
    }

    fn serialize_none(self) -> Result<Yaml> {
        self.serialize_unit()
    }

    fn serialize_some<V: ?Sized>(self, value: &V) -> Result<Yaml>
        where V: ser::Serialize
    {
        value.serialize(self)
    }

    fn serialize_seq(self, len: Option<usize>) -> Result<SerializeArray> {
        let array = match len {
            None => yaml::Array::new(),
            Some(len) => yaml::Array::with_capacity(len),
        };
        Ok(SerializeArray { array: array })
    }

    fn serialize_tuple(self, len: usize) -> Result<SerializeArray> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result<SerializeArray> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(self,
                               _enum: &'static str,
                               _idx: u32,
                               variant: &'static str,
                               len: usize)
                               -> Result<SerializeTupleVariant> {
        Ok(SerializeTupleVariant {
               name: variant,
               array: yaml::Array::with_capacity(len),
           })
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<SerializeMap> {
        Ok(SerializeMap {
               hash: yaml::Hash::new(),
               next_key: None,
           })
    }

    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<SerializeStruct> {
        Ok(SerializeStruct { hash: yaml::Hash::new() })
    }

    fn serialize_struct_variant(self,
                                _enum: &'static str,
                                _idx: u32,
                                variant: &'static str,
                                _len: usize)
                                -> Result<SerializeStructVariant> {
        Ok(SerializeStructVariant {
               name: variant,
               hash: yaml::Hash::new(),
           })
    }
}

#[doc(hidden)]
pub struct SerializeArray {
    array: yaml::Array,
}

#[doc(hidden)]
pub struct SerializeTupleVariant {
    name: &'static str,
    array: yaml::Array,
}

#[doc(hidden)]
pub struct SerializeMap {
    hash: yaml::Hash,
    next_key: Option<yaml::Yaml>,
}

#[doc(hidden)]
pub struct SerializeStruct {
    hash: yaml::Hash,
}

#[doc(hidden)]
pub struct SerializeStructVariant {
    name: &'static str,
    hash: yaml::Hash,
}

impl ser::SerializeSeq for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_element<T: ?Sized>(&mut self, elem: &T) -> Result<()>
        where T: ser::Serialize
    {
        self.array.push(to_yaml(elem)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Array(self.array))
    }
}

impl ser::SerializeTuple for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_element<T: ?Sized>(&mut self, elem: &T) -> Result<()>
        where T: ser::Serialize
    {
        ser::SerializeSeq::serialize_element(self, elem)
    }

    fn end(self) -> Result<Yaml> {
        ser::SerializeSeq::end(self)
    }
}

impl ser::SerializeTupleStruct for SerializeArray {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, value: &V) -> Result<()>
        where V: ser::Serialize
    {
        ser::SerializeSeq::serialize_element(self, value)
    }

    fn end(self) -> Result<Yaml> {
        ser::SerializeSeq::end(self)
    }
}

impl ser::SerializeTupleVariant for SerializeTupleVariant {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, v: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.array.push(to_yaml(v)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(singleton_hash(to_yaml(self.name)?, Yaml::Array(self.array)))
    }
}

impl ser::SerializeMap for SerializeMap {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()>
        where T: ser::Serialize
    {
        self.next_key = Some(to_yaml(key)?);
        Ok(())
    }

    fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()>
        where T: ser::Serialize
    {
        match self.next_key.take() {
            Some(key) => self.hash.insert(key, to_yaml(value)?),
            None => panic!("serialize_value called before serialize_key"),
        };
        Ok(())
    }

    fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<()>
        where K: ser::Serialize,
              V: ser::Serialize
    {
        self.hash.insert(to_yaml(key)?, to_yaml(value)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Hash(self.hash))
    }
}

impl ser::SerializeStruct for SerializeStruct {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, key: &'static str, value: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.hash.insert(to_yaml(key)?, to_yaml(value)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(Yaml::Hash(self.hash))
    }
}

impl ser::SerializeStructVariant for SerializeStructVariant {
    type Ok = yaml::Yaml;
    type Error = Error;

    fn serialize_field<V: ?Sized>(&mut self, field: &'static str, v: &V) -> Result<()>
        where V: ser::Serialize
    {
        self.hash.insert(to_yaml(field)?, to_yaml(v)?);
        Ok(())
    }

    fn end(self) -> Result<Yaml> {
        Ok(singleton_hash(to_yaml(self.name)?, Yaml::Hash(self.hash)))
    }
}

/// Serialize the given data structure as YAML into the IO stream.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_writer<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
    where W: io::Write,
          T: ser::Serialize
{
    let doc = to_yaml(value)?;
    let mut writer_adapter = FmtToIoWriter { writer: writer };
    YamlEmitter::new(&mut writer_adapter).dump(&doc).map_err(Error::emitter)?;
    Ok(())
}

/// Serialize the given data structure as a YAML byte vector.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>>
    where T: ser::Serialize
{
    let mut vec = Vec::with_capacity(128);
    to_writer(&mut vec, value)?;
    Ok(vec)
}

/// Serialize the given data structure as a String of YAML.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// return an error.
pub fn to_string<T: ?Sized>(value: &T) -> Result<String>
    where T: ser::Serialize
{
    Ok(String::from_utf8(to_vec(value)?).map_err(Error::string_utf8)?)
}

/// The yaml-rust library uses `fmt::Write` intead of `io::Write` so this is a
/// simple adapter.
struct FmtToIoWriter<W> {
    writer: W,
}

impl<W> fmt::Write for FmtToIoWriter<W>
    where W: io::Write
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if self.writer.write(s.as_bytes()).is_err() {
            return Err(fmt::Error);
        }
        Ok(())
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
fn to_yaml<T>(elem: T) -> Result<Yaml>
    where T: ser::Serialize
{
    elem.serialize(Serializer)
}

fn singleton_hash(k: Yaml, v: Yaml) -> Yaml {
    let mut hash = yaml::Hash::new();
    hash.insert(k, v);
    Yaml::Hash(hash)
}
<|endoftext|>


<commit_before>use std::char;
use std::io::{Result, Error, ErrorKind, Seek, SeekFrom, BufReader};
use std::path::Path;
use std::fs::File;
use super::binary_reader::{ReadAll, BinaryRead, BinaryReader};

macro_rules! fail {
    ($expr:expr) => (return Err(Error::new(ErrorKind::Other, $expr)))
}

pub const RAM_LEN: usize = 0x10000;
pub const REG_LEN: usize = 128;
pub const IPL_ROM_LEN: usize = 64;

const HEADER_LEN: usize = 33;
const HEADER_BYTES: &'static [u8; HEADER_LEN] =
    b"SNES-SPC700 Sound File Data v0.30";

pub struct Spc {
    pub version_minor: u8,
    pub pc: u16,
    pub a: u8,
    pub x: u8,
    pub y: u8,
    pub psw: u8,
    pub sp: u8,
    pub id666_tag: Option<Id666Tag>,
    pub ram: [u8; RAM_LEN],
    pub regs: [u8; REG_LEN],
    pub ipl_rom: [u8; IPL_ROM_LEN]
}

impl Spc {
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Spc> {
        let file = try!(File::open(path));
        let mut r = BinaryReader::new(BufReader::new(file));

        let mut header = [0; HEADER_LEN];
        try!(r.read_all(&mut header));
        if header.iter().zip(HEADER_BYTES.iter()).any(|(x, y)| x != y) {
            fail!("Invalid header string");
        }

        if try!(r.read_le_u16()) != 0x1a1a {
            fail!("Invalid padding bytes");
        }

        let has_id666_tag = match try!(r.read_u8()) {
            0x1a => true,
            0x1b => false,
            _ => fail!("Unable to determine if file contains ID666 tag")
        };

        let version_minor = try!(r.read_u8());

        let pc = try!(r.read_le_u16());
        let a = try!(r.read_u8());
        let x = try!(r.read_u8());
        let y = try!(r.read_u8());
        let psw = try!(r.read_u8());
        let sp = try!(r.read_u8());

        let id666_tag = match has_id666_tag {
            true => {
                try!(r.seek(SeekFrom::Start(0x2e)));
                match Id666Tag::load(&mut r) {
                    Ok(x) => Some(x),
                    Err(e) => fail!(format!("Invalid ID666 tag: {}", e))
                }
            },
            false => None
        };

        try!(r.seek(SeekFrom::Start(0x100)));
        let mut ram = [0; RAM_LEN];
        try!(r.read_all(&mut ram));
        let mut regs = [0; REG_LEN];
        try!(r.read_all(&mut regs));
        try!(r.seek(SeekFrom::Start(0x101c0)));
        let mut ipl_rom = [0; IPL_ROM_LEN];
        try!(r.read_all(&mut ipl_rom));

        Ok(Spc {
            version_minor: version_minor,
            pc: pc,
            a: a,
            x: x,
            y: y,
            psw: psw,
            sp: sp,
            id666_tag: id666_tag,
            ram: ram,
            regs: regs,
            ipl_rom: ipl_rom
        })
    }
}

pub struct Id666Tag {
    pub song_title: String,
    pub game_title: String,
    pub dumper_name: String,
    pub comments: String,
    pub date_dumped: String,
    pub seconds_to_play_before_fading_out: i32,
    pub fade_out_length: i32,
    pub artist_name: String,
    pub default_channel_disables: u8,
    pub dumping_emulator: Emulator
}

pub enum Emulator {
    Unknown,
    ZSnes,
    Snes9x
}

impl Id666Tag {
    fn load<R: BinaryRead + Seek>(r: &mut R) -> Result<Id666Tag> {
        let song_title = try!(Id666Tag::read_string(r, 32));
        let game_title = try!(Id666Tag::read_string(r, 32));
        let dumper_name = try!(Id666Tag::read_string(r, 16));
        let comments = try!(Id666Tag::read_string(r, 32));

        // So, apparently, there's really no reliable way to detect whether or not
        //  an id666 tag is in text or binary format. I tried using the date field,
        //  but that's actually invalid in a lot of files anyways. I've read that
        //  the dumping emu can give clues (znes seems to dump binary files and
        //  snes9x seems to dump text), but these don't cover cases where the
        //  dumping emu is "unknown", so that sucks too. I've even seen some source
        //  where people try to differentiate based on the value of the psw register
        //  (lol). Ultimately, the most sensible solution I was able to dig up that
        //  seems to work on all of the .spc's I've tried is to just check if there
        //  appears to be textual data where the length and/or date fields should be.
        //  Still pretty icky, but it works pretty well.
        try!(r.seek(SeekFrom::Start(0x9e)));
        let is_text_format = match try!(Id666Tag::is_text_region(r, 11)) {
            true => {
                try!(r.seek(SeekFrom::Start(0xa9)));
                try!(Id666Tag::is_text_region(r, 3))
            },
            _ => false
        };

        try!(r.seek(SeekFrom::Start(0x9e)));

        let (date_dumped, seconds_to_play_before_fading_out, fade_out_length) =
            if is_text_format {
                let date_dumped = try!(Id666Tag::read_string(r, 11));
                let seconds_to_play_before_fading_out = try!(Id666Tag::read_number(r, 3));
                let fade_out_length = try!(Id666Tag::read_number(r, 5));

                (date_dumped, seconds_to_play_before_fading_out, fade_out_length)
            } else {
                // TODO: Find SPC's to test this with
                unimplemented!();

                /*let year = try!(r.read_le_u16());
                let month = try!(r.read_u8());
                let day = try!(r.read_u8());
                let date_dumped = format!("{}/{}/{}", month, day, year);

                try!(r.seek(SeekFrom::Start(0xa9)));
                let seconds_to_play_before_fading_out = try!(r.read_le_u16());
                try!(r.read_u8());
                let fade_out_length = try!(r.read_le_i32());

                (date_dumped, seconds_to_play_before_fading_out, fade_out_length)*/
            };

        let artist_name = try!(Id666Tag::read_string(r, 32));

        let default_channel_disables = try!(r.read_u8());

        let dumping_emulator = match Id666Tag::read_digit(r) {
            Ok(1) => Emulator::ZSnes,
            Ok(2) => Emulator::Snes9x,
            _ => Emulator::Unknown
        };

        Ok(Id666Tag {
            song_title: song_title,
            game_title: game_title,
            dumper_name: dumper_name,
            comments: comments,
            date_dumped: date_dumped,
            seconds_to_play_before_fading_out: seconds_to_play_before_fading_out,
            fade_out_length: fade_out_length,
            artist_name: artist_name,
            default_channel_disables: default_channel_disables,
            dumping_emulator: dumping_emulator
        })
    }

    fn read_string<R: BinaryRead>(r: &mut R, max_len: i32) -> Result<String> {
        // TODO: Reimplement as iterator or something similar
        let mut ret = "".to_string();
        let mut has_ended = false;
        for _ in 0..max_len {
            let b = try!(r.read_u8());
            if !has_ended {
                match char::from_u32(b as u32) {
                    Some(c) if b != 0 => ret.push(c),
                    _ => has_ended = true
                }
            }
        }
        Ok(ret)
    }

    fn is_text_region<R: BinaryRead>(r: &mut R, len: i32) -> Result<bool> {
        // TODO: This code is probably shit
        for _ in 0..len {
            let b = try!(r.read_u8());
            if b != 0 {
                if let Some(c) = char::from_u32(b as u32) {
                    if !c.is_digit(10) && c != '/' {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    }

    fn read_digit<R: BinaryRead>(r: &mut R) -> Result<i32> {
        let d = try!(r.read_u8());
        Id666Tag::digit(d)
    }

    fn digit(d: u8) -> Result<i32> {
        match char::from_u32(d as u32) {
            Some(c) if c.is_digit(10) => Ok(c.to_digit(10).unwrap() as i32),
            _ => fail!("Expected numeric value")
        }
    }

    fn read_number<R: BinaryRead>(r: &mut R, max_len: i32) -> Result<i32> {
        let mut ret = 0;
        for _ in 0..max_len {
        let d = try!(r.read_u8());
            if d == 0 {
                break;
            }
            ret *= 10;
            ret += try!(Id666Tag::digit(d));
        }
        Ok(ret)
    }
}
<commit_msg>Ability to open spc from something that impl's Read + Seek<commit_after>use std::char;
use std::io::{Read, Result, Error, ErrorKind, Seek, SeekFrom, BufReader};
use std::path::Path;
use std::fs::File;
use super::binary_reader::{ReadAll, BinaryRead, BinaryReader};

macro_rules! fail {
    ($expr:expr) => (return Err(Error::new(ErrorKind::Other, $expr)))
}

pub const RAM_LEN: usize = 0x10000;
pub const REG_LEN: usize = 128;
pub const IPL_ROM_LEN: usize = 64;

const HEADER_LEN: usize = 33;
const HEADER_BYTES: &'static [u8; HEADER_LEN] =
    b"SNES-SPC700 Sound File Data v0.30";

pub struct Spc {
    pub version_minor: u8,
    pub pc: u16,
    pub a: u8,
    pub x: u8,
    pub y: u8,
    pub psw: u8,
    pub sp: u8,
    pub id666_tag: Option<Id666Tag>,
    pub ram: [u8; RAM_LEN],
    pub regs: [u8; REG_LEN],
    pub ipl_rom: [u8; IPL_ROM_LEN]
}

impl Spc {
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Spc> {
        let file = try!(File::open(path));
        Spc::from_reader(BufReader::new(file))
    }
    pub fn from_reader<R: Read + Seek>(reader: R) -> Result<Spc> {
        let mut r = BinaryReader::new(reader);

        let mut header = [0; HEADER_LEN];
        try!(r.read_all(&mut header));
        if header.iter().zip(HEADER_BYTES.iter()).any(|(x, y)| x != y) {
            fail!("Invalid header string");
        }

        if try!(r.read_le_u16()) != 0x1a1a {
            fail!("Invalid padding bytes");
        }

        let has_id666_tag = match try!(r.read_u8()) {
            0x1a => true,
            0x1b => false,
            _ => fail!("Unable to determine if file contains ID666 tag")
        };

        let version_minor = try!(r.read_u8());

        let pc = try!(r.read_le_u16());
        let a = try!(r.read_u8());
        let x = try!(r.read_u8());
        let y = try!(r.read_u8());
        let psw = try!(r.read_u8());
        let sp = try!(r.read_u8());

        let id666_tag = match has_id666_tag {
            true => {
                try!(r.seek(SeekFrom::Start(0x2e)));
                match Id666Tag::load(&mut r) {
                    Ok(x) => Some(x),
                    Err(e) => fail!(format!("Invalid ID666 tag: {}", e))
                }
            },
            false => None
        };

        try!(r.seek(SeekFrom::Start(0x100)));
        let mut ram = [0; RAM_LEN];
        try!(r.read_all(&mut ram));
        let mut regs = [0; REG_LEN];
        try!(r.read_all(&mut regs));
        try!(r.seek(SeekFrom::Start(0x101c0)));
        let mut ipl_rom = [0; IPL_ROM_LEN];
        try!(r.read_all(&mut ipl_rom));

        Ok(Spc {
            version_minor: version_minor,
            pc: pc,
            a: a,
            x: x,
            y: y,
            psw: psw,
            sp: sp,
            id666_tag: id666_tag,
            ram: ram,
            regs: regs,
            ipl_rom: ipl_rom
        })
    }
}

pub struct Id666Tag {
    pub song_title: String,
    pub game_title: String,
    pub dumper_name: String,
    pub comments: String,
    pub date_dumped: String,
    pub seconds_to_play_before_fading_out: i32,
    pub fade_out_length: i32,
    pub artist_name: String,
    pub default_channel_disables: u8,
    pub dumping_emulator: Emulator
}

pub enum Emulator {
    Unknown,
    ZSnes,
    Snes9x
}

impl Id666Tag {
    fn load<R: BinaryRead + Seek>(r: &mut R) -> Result<Id666Tag> {
        let song_title = try!(Id666Tag::read_string(r, 32));
        let game_title = try!(Id666Tag::read_string(r, 32));
        let dumper_name = try!(Id666Tag::read_string(r, 16));
        let comments = try!(Id666Tag::read_string(r, 32));

        // So, apparently, there's really no reliable way to detect whether or not
        //  an id666 tag is in text or binary format. I tried using the date field,
        //  but that's actually invalid in a lot of files anyways. I've read that
        //  the dumping emu can give clues (znes seems to dump binary files and
        //  snes9x seems to dump text), but these don't cover cases where the
        //  dumping emu is "unknown", so that sucks too. I've even seen some source
        //  where people try to differentiate based on the value of the psw register
        //  (lol). Ultimately, the most sensible solution I was able to dig up that
        //  seems to work on all of the .spc's I've tried is to just check if there
        //  appears to be textual data where the length and/or date fields should be.
        //  Still pretty icky, but it works pretty well.
        try!(r.seek(SeekFrom::Start(0x9e)));
        let is_text_format = match try!(Id666Tag::is_text_region(r, 11)) {
            true => {
                try!(r.seek(SeekFrom::Start(0xa9)));
                try!(Id666Tag::is_text_region(r, 3))
            },
            _ => false
        };

        try!(r.seek(SeekFrom::Start(0x9e)));

        let (date_dumped, seconds_to_play_before_fading_out, fade_out_length) =
            if is_text_format {
                let date_dumped = try!(Id666Tag::read_string(r, 11));
                let seconds_to_play_before_fading_out = try!(Id666Tag::read_number(r, 3));
                let fade_out_length = try!(Id666Tag::read_number(r, 5));

                (date_dumped, seconds_to_play_before_fading_out, fade_out_length)
            } else {
                // TODO: Find SPC's to test this with
                unimplemented!();

                /*let year = try!(r.read_le_u16());
                let month = try!(r.read_u8());
                let day = try!(r.read_u8());
                let date_dumped = format!("{}/{}/{}", month, day, year);

                try!(r.seek(SeekFrom::Start(0xa9)));
                let seconds_to_play_before_fading_out = try!(r.read_le_u16());
                try!(r.read_u8());
                let fade_out_length = try!(r.read_le_i32());

                (date_dumped, seconds_to_play_before_fading_out, fade_out_length)*/
            };

        let artist_name = try!(Id666Tag::read_string(r, 32));

        let default_channel_disables = try!(r.read_u8());

        let dumping_emulator = match Id666Tag::read_digit(r) {
            Ok(1) => Emulator::ZSnes,
            Ok(2) => Emulator::Snes9x,
            _ => Emulator::Unknown
        };

        Ok(Id666Tag {
            song_title: song_title,
            game_title: game_title,
            dumper_name: dumper_name,
            comments: comments,
            date_dumped: date_dumped,
            seconds_to_play_before_fading_out: seconds_to_play_before_fading_out,
            fade_out_length: fade_out_length,
            artist_name: artist_name,
            default_channel_disables: default_channel_disables,
            dumping_emulator: dumping_emulator
        })
    }

    fn read_string<R: BinaryRead>(r: &mut R, max_len: i32) -> Result<String> {
        // TODO: Reimplement as iterator or something similar
        let mut ret = "".to_string();
        let mut has_ended = false;
        for _ in 0..max_len {
            let b = try!(r.read_u8());
            if !has_ended {
                match char::from_u32(b as u32) {
                    Some(c) if b != 0 => ret.push(c),
                    _ => has_ended = true
                }
            }
        }
        Ok(ret)
    }

    fn is_text_region<R: BinaryRead>(r: &mut R, len: i32) -> Result<bool> {
        // TODO: This code is probably shit
        for _ in 0..len {
            let b = try!(r.read_u8());
            if b != 0 {
                if let Some(c) = char::from_u32(b as u32) {
                    if !c.is_digit(10) && c != '/' {
                        return Ok(false);
                    }
                }
            }
        }
        Ok(true)
    }

    fn read_digit<R: BinaryRead>(r: &mut R) -> Result<i32> {
        let d = try!(r.read_u8());
        Id666Tag::digit(d)
    }

    fn digit(d: u8) -> Result<i32> {
        match char::from_u32(d as u32) {
            Some(c) if c.is_digit(10) => Ok(c.to_digit(10).unwrap() as i32),
            _ => fail!("Expected numeric value")
        }
    }

    fn read_number<R: BinaryRead>(r: &mut R, max_len: i32) -> Result<i32> {
        let mut ret = 0;
        for _ in 0..max_len {
        let d = try!(r.read_u8());
            if d == 0 {
                break;
            }
            ret *= 10;
            ret += try!(Id666Tag::digit(d));
        }
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use fake_tty::FakeIO;
use tty::IO;

struct Ansi<'a> {
    io: Box<(IO + 'a)>,
}

impl <'a> Ansi<'a> {
    pub fn escape(&mut self, message: &str) {
        self.io.write("\x1b[something");
    }
}

#[cfg(test)]

#[test]
fn it_escapes_a_str() {
    let mut ansi = Ansi { io: Box::new(FakeIO::new()) };
    ansi.escape("something");
    let inner_box = ansi.io;
    assert_eq!(inner_box.last(), "\x1b[something");
}
<commit_msg>It clears the screen<commit_after>use fake_tty::FakeIO;
use tty::IO;

struct Ansi<'a> {
    io: Box<(IO + 'a)>,
}

impl <'a> Ansi<'a> {
    pub fn escape(&mut self, message: &str) {
        let mut esc = "\x1b[".to_string();
        esc.push_str(message);
        self.io.write(esc.as_slice());
    }

    pub fn clear(&mut self) {
        self.escape("2J");
    }
}

#[cfg(test)]

#[test]
fn it_escapes_a_str() {
    let mut ansi = Ansi { io: Box::new(FakeIO::new()) };
    ansi.escape("something");
    let inner_box = ansi.io;
    assert_eq!(inner_box.last(), "\x1b[something");
}

#[test]
fn it_clears_the_screen() {
    let mut ansi = Ansi { io: Box::new(FakeIO::new()) };
    ansi.clear();
    let inner_box = ansi.io;
    assert_eq!(inner_box.last(), "\x1b[2J");
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::net;
use std::io;
use std::convert::From;

extern crate rustc_serialize;
use rustc_serialize::json;
use rustc_serialize::Encodable;

extern crate time;

pub struct Fluentd<'a, A: net::ToSocketAddrs> {
    pub address: A,
    pub tag: &'a str,
}

pub enum FluentError {
    DecodeError(json::EncoderError),
    IoError(io::Error),
}

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

impl From<json::EncoderError> for FluentError {
    fn from(err: json::EncoderError) -> FluentError {
        FluentError::DecodeError(err)
    }
}

impl <'a, A: net::ToSocketAddrs> Fluentd<'a, A> {
    pub fn write<B: Encodable> (&self, object: &B) -> Result<(), FluentError> {
        let tag = try!(json::encode(&self.tag));
        let now = time::now();
        let record = try!(json::encode(object));
        let message = format!("[{},{},{}]", tag, now.to_timespec().sec, record);

        let mut stream = try!(net::TcpStream::connect(&self.address));
        let _ = stream.write(&message.into_bytes());
        drop(stream);

        Ok(())
    }
}
<commit_msg>Implement Debug trait<commit_after>use std::io::prelude::*;
use std::net;
use std::io;
use std::convert::From;

extern crate rustc_serialize;
use rustc_serialize::json;
use rustc_serialize::Encodable;

extern crate time;

pub struct Fluentd<'a, A: net::ToSocketAddrs> {
    pub address: A,
    pub tag: &'a str,
}

#[derive(Debug)]
pub enum FluentError {
    DecodeError(json::EncoderError),
    IoError(io::Error),
}

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

impl From<json::EncoderError> for FluentError {
    fn from(err: json::EncoderError) -> FluentError {
        FluentError::DecodeError(err)
    }
}

impl <'a, A: net::ToSocketAddrs> Fluentd<'a, A> {
    pub fn write<B: Encodable> (&self, object: &B) -> Result<(), FluentError> {
        let tag = try!(json::encode(&self.tag));
        let now = time::now();
        let record = try!(json::encode(object));
        let message = format!("[{},{},{}]", tag, now.to_timespec().sec, record);

        let mut stream = try!(net::TcpStream::connect(&self.address));
        let _ = stream.write(&message.into_bytes());
        drop(stream);

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Static blog generation.

use std::fs::{self, File};
use std::path::Path;
use std::io;
use std::io::prelude::*;

use ammonia::Ammonia;
use chrono::{self, NaiveDateTime, NaiveDate, Datelike};
use rusqlite::{self, Connection};
use serde;
use yaml::YamlLoader;
use yaml::ScanError;

use markdown::{self, Html};
use persistence;

/// The length of a blog post preview.
const SUMMARY_LENGTH: usize = 200;

/// A struct representing a blog post.
#[derive(Debug, Clone, Serialize)]
pub struct Post {
    /// The title of the post.
    pub title: String,

    /// The time that the post was written.
    #[serde(serialize_with="Self::serialize_date")]
    pub date: NaiveDateTime,

    /// The post rendered as HTML.
    pub html: Html,
}

impl Post {
    /// The human-readable format that the date should appear as when rendering the post.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    // TODO: Remove the above attribute. For some reason rustfmt wants to remove the visibility.
    pub const DATE_FORMAT: &'static str = "%B %e, %Y";

    fn serialize_date<S>(date: &NaiveDateTime, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&date.format(Self::DATE_FORMAT).to_string())
    }
}

/// A brief summary of a blog post.
#[derive(Serialize, Debug)]
pub struct Summary {
    /// The title of the post.
    pub title: String,

    /// The date the post was written.
    #[serde(serialize_with="Self::serialize_date")]
    pub date: NaiveDateTime,

    /// A short preview of the post.
    pub summary: String,

    /// A URL to reach the full post.
    pub url: String,
}

impl Summary {
    fn serialize_date<S>(date: &NaiveDateTime, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&date.format(Post::DATE_FORMAT).to_string())
    }
}

#[derive(Debug)]
struct ParsedPost {
    title: String,
    date: NaiveDateTime,
    summary: String,
    html: Html,
    url: String,
}

quick_error! {
    /// Encapsulates errors that might occur while parsing a blog post.
    #[derive(Debug)]
    pub enum PostParseError {
        /// There was a problem reading the file.
        Io(err: io::Error) {
            from()
            description("io error")
            display("I/O error: {}", err)
            cause(err)
        }

        /// There was a syntax error in the metadata.
        MetadataSyntax(err: String) {
            from()
            from(err: ScanError) -> (err.to_string())
            from(err: chrono::ParseError) -> (err.to_string())
            description("yaml parsing error")
            display("Error parsing metadata: {}", err)
        }

        /// Something went wrong with the database.
        Database(err: rusqlite::Error) {
            from()
            description("problem with the database")
            display("Error with the database: {}", err)
            cause(err)
        }
    }
}

fn parse_post(post: &str) -> Result<ParsedPost, PostParseError> {
    // Read up to the first double newline to determine the end of metadata.
    //
    // TODO: This could probably be more robust. Investigate separating the metadata and
    // markdown as separate YAML documents.
    let contents = post.splitn(2, "\n\n").collect::<Vec<_>>();
    let metadata = contents[0];
    let metadata = try!(YamlLoader::load_from_str(metadata))[0].to_owned();

    let title = try!(metadata["title"]
            .as_str()
            .ok_or(PostParseError::MetadataSyntax("could not find key 'title'".to_owned())))
        .to_owned();

    let date_string = try!(metadata["date"]
        .as_str()
        .ok_or(PostParseError::MetadataSyntax("could not find 'key'".to_owned())));
    let date = try!(NaiveDateTime::parse_from_str(date_string, "%l:%M%P %m/%d/%y"));

    let content = contents[1];
    let html_content = markdown::render_html(&content);

    let escaped_title = title.to_lowercase().replace(" ", "-");
    let url = format!("/blog/{}/{}/{}/{}",
                      date.year(),
                      date.month(),
                      date.day(),
                      escaped_title);

    let mut ammonia = Ammonia::default();

    ammonia.url_relative = true;

    // Add a link at the end of the preview, then sanitize the HTML and close any unclosed
    // tags.
    let summary_link = format!(r#"... Continue→"#, url);
    let summary = html_content.chars()
        .take(SUMMARY_LENGTH)
        .chain(summary_link.chars())
        .collect::<String>();

    Ok(ParsedPost {
        title: title,
        date: date,
        html: html_content,
        summary: ammonia.clean(&summary),
        url: url,
    })
}

/// Retrieves blog post content and metadata by parsing all markdown files in a given directory,
/// then persists the posts into the database.
pub fn parse_posts
(directory: P, connection: &Connection) -> Result<(), PostParseError>
    where P: AsRef<Path>
{
    let posts = try!(fs::read_dir(&directory))
        .into_iter()
        .map(|entry| {
            let mut file = try!(File::open(try!(entry).path()));

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

            parse_post(&contents)
        })
        .collect::<Vec<_>>();

    info!("parsed {} blog posts in {:?}",
          posts.len(),
          directory.as_ref());

    for post in posts {
        let post = post.unwrap();
        connection.execute(r"INSERT INTO posts (title, date, html, summary, url)
                             VALUES ($1, $2, $3, $4, $5)",
                     &[&post.title,
                       &post.date,
                       &post.html.as_str(),
                       &post.summary,
                       &post.url.to_string()])
            .unwrap();
    }

    Ok(())
}

/// Retrieves a blog post from the database given the date it was posted and its title.
pub fn get_post(date: &NaiveDate, title: &str) -> Result<Post, rusqlite::Error> {
    let connection = persistence::get_db_connection();
    connection.query_row(r#"SELECT title, date, html
                            FROM posts
                            WHERE REPLACE(LOWER(title), " ", "-") = $1
                              AND DATE(date) = $2"#,
                         &[&title, date],
                         |row| {
        Post {
            title: row.get(0),
            date: row.get(1),
            html: Html(row.get(2)),
        }
    })
}

/// Retrieves blog post summaries from the database.
pub fn get_summaries(connection: &Connection) -> Result<Vec, rusqlite::Error> {
    let mut stmt = connection.prepare(r"SELECT title, date, summary, url
                                   FROM posts
                                   ORDER BY date DESC")
        .unwrap();

    let summaries = stmt.query_map(&[], |row| {
            Summary {
                title: row.get(0),
                date: row.get(1),
                summary: row.get(2),
                url: row.get(3),
            }
        })
        .unwrap();

    summaries.collect()
}
<commit_msg>refactor(blog): remove rustfmt workaround<commit_after>//! Static blog generation.

use std::fs::{self, File};
use std::path::Path;
use std::io;
use std::io::prelude::*;

use ammonia::Ammonia;
use chrono::{self, NaiveDateTime, NaiveDate, Datelike};
use rusqlite::{self, Connection};
use serde;
use yaml::YamlLoader;
use yaml::ScanError;

use markdown::{self, Html};
use persistence;

/// The length of a blog post preview.
const SUMMARY_LENGTH: usize = 200;

/// A struct representing a blog post.
#[derive(Debug, Clone, Serialize)]
pub struct Post {
    /// The title of the post.
    pub title: String,

    /// The time that the post was written.
    #[serde(serialize_with="Self::serialize_date")]
    pub date: NaiveDateTime,

    /// The post rendered as HTML.
    pub html: Html,
}

impl Post {
    /// The human-readable format that the date should appear as when rendering the post.
    pub const DATE_FORMAT: &'static str = "%B %e, %Y";

    fn serialize_date<S>(date: &NaiveDateTime, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&date.format(Self::DATE_FORMAT).to_string())
    }
}

/// A brief summary of a blog post.
#[derive(Serialize, Debug)]
pub struct Summary {
    /// The title of the post.
    pub title: String,

    /// The date the post was written.
    #[serde(serialize_with="Self::serialize_date")]
    pub date: NaiveDateTime,

    /// A short preview of the post.
    pub summary: String,

    /// A URL to reach the full post.
    pub url: String,
}

impl Summary {
    fn serialize_date<S>(date: &NaiveDateTime, serializer: &mut S) -> Result<(), S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&date.format(Post::DATE_FORMAT).to_string())
    }
}

#[derive(Debug)]
struct ParsedPost {
    title: String,
    date: NaiveDateTime,
    summary: String,
    html: Html,
    url: String,
}

quick_error! {
    /// Encapsulates errors that might occur while parsing a blog post.
    #[derive(Debug)]
    pub enum PostParseError {
        /// There was a problem reading the file.
        Io(err: io::Error) {
            from()
            description("io error")
            display("I/O error: {}", err)
            cause(err)
        }

        /// There was a syntax error in the metadata.
        MetadataSyntax(err: String) {
            from()
            from(err: ScanError) -> (err.to_string())
            from(err: chrono::ParseError) -> (err.to_string())
            description("yaml parsing error")
            display("Error parsing metadata: {}", err)
        }

        /// Something went wrong with the database.
        Database(err: rusqlite::Error) {
            from()
            description("problem with the database")
            display("Error with the database: {}", err)
            cause(err)
        }
    }
}

fn parse_post(post: &str) -> Result<ParsedPost, PostParseError> {
    // Read up to the first double newline to determine the end of metadata.
    //
    // TODO: This could probably be more robust. Investigate separating the metadata and
    // markdown as separate YAML documents.
    let contents = post.splitn(2, "\n\n").collect::<Vec<_>>();
    let metadata = contents[0];
    let metadata = try!(YamlLoader::load_from_str(metadata))[0].to_owned();

    let title = try!(metadata["title"]
            .as_str()
            .ok_or(PostParseError::MetadataSyntax("could not find key 'title'".to_owned())))
        .to_owned();

    let date_string = try!(metadata["date"]
        .as_str()
        .ok_or(PostParseError::MetadataSyntax("could not find 'key'".to_owned())));
    let date = try!(NaiveDateTime::parse_from_str(date_string, "%l:%M%P %m/%d/%y"));

    let content = contents[1];
    let html_content = markdown::render_html(&content);

    let escaped_title = title.to_lowercase().replace(" ", "-");
    let url = format!("/blog/{}/{}/{}/{}",
                      date.year(),
                      date.month(),
                      date.day(),
                      escaped_title);

    let mut ammonia = Ammonia::default();

    ammonia.url_relative = true;

    // Add a link at the end of the preview, then sanitize the HTML and close any unclosed
    // tags.
    let summary_link = format!(r#"... Continue→"#, url);
    let summary = html_content.chars()
        .take(SUMMARY_LENGTH)
        .chain(summary_link.chars())
        .collect::<String>();

    Ok(ParsedPost {
        title: title,
        date: date,
        html: html_content,
        summary: ammonia.clean(&summary),
        url: url,
    })
}

/// Retrieves blog post content and metadata by parsing all markdown files in a given directory,
/// then persists the posts into the database.
pub fn parse_posts
(directory: P, connection: &Connection) -> Result<(), PostParseError>
    where P: AsRef<Path>
{
    let posts = try!(fs::read_dir(&directory))
        .into_iter()
        .map(|entry| {
            let mut file = try!(File::open(try!(entry).path()));

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

            parse_post(&contents)
        })
        .collect::<Vec<_>>();

    info!("parsed {} blog posts in {:?}",
          posts.len(),
          directory.as_ref());

    for post in posts {
        let post = post.unwrap();
        connection.execute(r"INSERT INTO posts (title, date, html, summary, url)
                             VALUES ($1, $2, $3, $4, $5)",
                     &[&post.title,
                       &post.date,
                       &post.html.as_str(),
                       &post.summary,
                       &post.url.to_string()])
            .unwrap();
    }

    Ok(())
}

/// Retrieves a blog post from the database given the date it was posted and its title.
pub fn get_post(date: &NaiveDate, title: &str) -> Result<Post, rusqlite::Error> {
    let connection = persistence::get_db_connection();
    connection.query_row(r#"SELECT title, date, html
                            FROM posts
                            WHERE REPLACE(LOWER(title), " ", "-") = $1
                              AND DATE(date) = $2"#,
                         &[&title, date],
                         |row| {
        Post {
            title: row.get(0),
            date: row.get(1),
            html: Html(row.get(2)),
        }
    })
}

/// Retrieves blog post summaries from the database.
pub fn get_summaries(connection: &Connection) -> Result<Vec, rusqlite::Error> {
    let mut stmt = connection.prepare(r"SELECT title, date, summary, url
                                   FROM posts
                                   ORDER BY date DESC")
        .unwrap();

    let summaries = stmt.query_map(&[], |row| {
            Summary {
                title: row.get(0),
                date: row.get(1),
                summary: row.get(2),
                url: row.get(3),
            }
        })
        .unwrap();

    summaries.collect()
}
<|endoftext|>


<commit_before>extern crate hyper;

use std::sync::mpsc::{Receiver, channel};
use std::thread;
use args::Config;
use run_info::RunInfo;
use misc::split_number;
use tokio_core::reactor::Core;
use chrono::{Duration, Local};
use hyper::{Client, Url};
use std::str::FromStr;

use futures::{Future, stream};
use futures::future::{ok, loop_fn, Loop};
use futures::Stream;
use futures_utils::stopwatch;
use request_result::RequestResult;

/// Delegates and manages all the work.
pub struct Boss {
    /// Number of requests successfully completed
    pub requests_completed: usize,
    /// Number of active connections
    pub connections: usize,
    num_threads: usize,
}

impl Boss {
    pub fn new(num_threads: usize) -> Self {
        Boss {
            requests_completed: 0,
            connections: 0,
            num_threads: num_threads,
        }
    }

    pub fn start_workforce(&self, config: &Config) -> RunInfo {
        let (tx, rx) = channel();
        let desired_connections_per_worker_iter = split_number(config.num_connections,
                                                                     self.num_threads);
        // start num_threads workers
        for desired_connections_per_worker in desired_connections_per_worker_iter {
            let tx = tx.clone();
            let url = config.url.clone();
            let duration = config.duration;
            let timeout = config.timeout.to_std().unwrap();
            thread::spawn(move || {

                let mut core = Core::new().unwrap();
                let start_time = Local::now();
                let wanted_end_time = start_time + duration;
                let hyper_client = hyper::Client::configure()
                    .keep_alive_timeout(Some(timeout))
                    .build(&core.handle());
                let hyper_url = Url::from_str(&url).expect("Invalid URL");

                let iterator = (0..desired_connections_per_worker).map(|_| {

                    let runinfo = RunInfo::new(duration);

                    loop_fn((runinfo), |mut runinfo| {
                        send_request(hyper_url.clone(), &hyper_client)
                            .then(|res| -> Result<_, ()> { match res {
                                // on request success
                                Ok(request_res) => {
                                    // update histogram
                                    request_res.latency.num_nanoseconds()
                                        .map(|x| runinfo.histogram.increment(x as u64).ok());
                                    runinfo.requests_completed += 1;

                                    let state = runinfo;

                                    let now_time = Local::now();
                                    if now_time < wanted_end_time {
                                        Ok(Loop::Continue(state))
                                    } else {
                                        Ok(Loop::Break(state))
                                    }
                                }
                                // on request failure
                                Err(_) => {
                                    runinfo.num_failed_requests += 1;
                                    let state = runinfo;
                                    let now_time = Local::now();
                                    if now_time < wanted_end_time {
                                        Ok(Loop::Continue(state))
                                    } else {
                                        Ok(Loop::Break(state))
                                    }
                                }
                            }})
                    })
                });
                let future = stream::futures_unordered(iterator)
                    .fold(RunInfo::new(duration), |mut runinfo_acc, runinfo| {
                        runinfo_acc.merge(&runinfo);
                        ok(runinfo_acc)
                    });
                let res = core.run(future).unwrap();
                tx.send(res).unwrap();
            });
        }

        self.collect_workers(rx, config.duration)
    }

    /// Collects information from all workers
    fn collect_workers(&self, rx: Receiver<RunInfo>, run_duration: Duration) -> RunInfo {
        rx.iter()
                .take(self.num_threads)
                .fold(RunInfo::new(run_duration), |mut runinfo_acc, runinfo| {
                    runinfo_acc.merge(&runinfo);
                    runinfo_acc
                })
    }
}

fn send_request<C>(url: Url,
                   hyper_client: &Client<C>)
                   -> impl Future<Item = RequestResult, Error = hyper::Error>
    where C: hyper::client::Connect
{
    stopwatch(hyper_client.get(url)).and_then(|(_, latency)| {
        let request_result = RequestResult::new(latency);
        Ok(request_result)
    })
}<commit_msg>move loop future out of start_workforce<commit_after>extern crate hyper;

use std::sync::mpsc::{Receiver, channel};
use std::thread;
use args::Config;
use run_info::RunInfo;
use misc::split_number;
use tokio_core::reactor::Core;
use chrono::{Duration, Local, DateTime};
use hyper::{Client, Url};
use std::str::FromStr;
use hyper::client::HttpConnector;

use futures::{Future, stream};
use futures::future::{ok, loop_fn, Loop};
use futures::Stream;
use futures_utils::stopwatch;
use request_result::RequestResult;

/// Delegates and manages all the work.
pub struct Boss {
    /// Number of requests successfully completed
    pub requests_completed: usize,
    /// Number of active connections
    pub connections: usize,
    num_threads: usize,
}

impl Boss {
    pub fn new(num_threads: usize) -> Self {
        Boss {
            requests_completed: 0,
            connections: 0,
            num_threads: num_threads,
        }
    }

    pub fn start_workforce(&self, config: &Config) -> RunInfo {
        let (tx, rx) = channel();
        let desired_connections_per_worker_iter = split_number(config.num_connections,
                                                                     self.num_threads);
        // start num_threads workers
        for desired_connections_per_worker in desired_connections_per_worker_iter {
            let tx = tx.clone();
            let url = config.url.clone();
            let duration = config.duration;
            let timeout = config.timeout.to_std().unwrap();
            thread::spawn(move || {

                let mut core = Core::new().unwrap();
                let start_time = Local::now();
                let wanted_end_time = start_time + duration;
                let hyper_client = hyper::Client::configure()
                    .keep_alive_timeout(Some(timeout))
                    .build(&core.handle());
                let hyper_url = Url::from_str(&url).expect("Invalid URL");

                let iterator = (0..desired_connections_per_worker).map(|_| {
                    create_looping_worker(duration, hyper_url.clone(), &hyper_client, wanted_end_time)
                });
                let future = stream::futures_unordered(iterator)
                    .fold(RunInfo::new(duration), |mut runinfo_acc, runinfo| {
                        runinfo_acc.merge(&runinfo);
                        ok(runinfo_acc)
                    });
                let res = core.run(future).unwrap();
                tx.send(res).unwrap();
            });
        }

        self.collect_workers(rx, config.duration)
    }

    /// Collects information from all workers
    fn collect_workers(&self, rx: Receiver<RunInfo>, run_duration: Duration) -> RunInfo {
        rx.iter()
                .take(self.num_threads)
                .fold(RunInfo::new(run_duration), |mut runinfo_acc, runinfo| {
                    runinfo_acc.merge(&runinfo);
                    runinfo_acc
                })
    }
}

fn create_looping_worker<'a>(duration: Duration, url: Url, hyper_client: &'a Client<HttpConnector>, wanted_end_time: DateTime<Local>) -> impl Future<Item = RunInfo, Error = ()> + 'a {
    let runinfo = RunInfo::new(duration);
    loop_fn((runinfo), move|mut runinfo| {
        let url = url.clone();
        send_request(url, hyper_client)
            .then(move|res| -> Result<_, ()> { match res {
                // on request success
                Ok(request_res) => {
                    // update histogram
                    request_res.latency.num_nanoseconds()
                        .map(|x| runinfo.histogram.increment(x as u64).ok());
                    runinfo.requests_completed += 1;

                    let state = runinfo;

                    let now_time = Local::now();
                    if now_time < wanted_end_time {
                        Ok(Loop::Continue(state))
                    } else {
                        Ok(Loop::Break(state))
                    }
                }
                // on request failure
                Err(_) => {
                    runinfo.num_failed_requests += 1;
                    let state = runinfo;
                    let now_time = Local::now();
                    if now_time < wanted_end_time {
                        Ok(Loop::Continue(state))
                    } else {
                        Ok(Loop::Break(state))
                    }
                }
            }})
    })
}

fn send_request<C>(url: Url,
                   hyper_client: &Client<C>)
                   -> impl Future<Item = RequestResult, Error = hyper::Error>
    where C: hyper::client::Connect
{
    stopwatch(hyper_client.get(url)).and_then(|(_, latency)| {
        let request_result = RequestResult::new(latency);
        Ok(request_result)
    })
}<|endoftext|>


<commit_before>use num::{Float, FromPrimitive};

macro_rules! count {
    ($idc:tt) => (1);
    ($($element:tt),*) => {{$(count!($element) +)* 0}};
}

macro_rules! n_bezier {
    ($name:ident {
        $($field:ident: $weight:expr),+
    } derived {
        $($dleft:ident - $dright:ident: $dweight:expr),+
    }) => {
        #[derive(Debug, Clone)]
        pub struct $name<F> where F: Float + FromPrimitive {
            $($field: F),+
        }

        impl<F> $name<F> where F: Float + FromPrimitive {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }

            pub fn interp(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.interp_unbounded(t)
            }

            pub fn interp_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $field =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        self.$field *
                        F::from_i32($weight).unwrap();
                )+
                $($field +)+ F::from_f32(0.0).unwrap()
            }

            pub fn derivative(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.derivative_unbounded(t)
            }

            pub fn derivative_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 2;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $dleft =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        (self.$dleft - self.$dright) *
                        F::from_i32($dweight).unwrap();
                )+
                $($dleft +)+ F::from_f32(0.0).unwrap()
            }
        }
    }
}

n_bezier!{BezCubePoly {
    start: 1,
    ctrl0: 3,
    ctrl1: 3,
    end:   1
} derived {
    ctrl0 - start: 1,
    ctrl1 - ctrl0: 2,
    end   - ctrl1: 1
}}<commit_msg>Fixed incorrect macro derivative calculations<commit_after>use num::{Float, FromPrimitive};

macro_rules! count {
    ($idc:tt) => (1);
    ($($element:tt),*) => {{$(count!($element) +)* 0}};
}

macro_rules! n_bezier {
    ($name:ident {
        $($field:ident: $weight:expr),+
    } derived {
        $($dleft:ident - $dright:ident: $dweight:expr),+
    }) => {
        #[derive(Debug, Clone)]
        pub struct $name<F> where F: Float + FromPrimitive {
            $($field: F),+
        }

        impl<F> $name<F> where F: Float + FromPrimitive {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }

            pub fn interp(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.interp_unbounded(t)
            }

            pub fn interp_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $field =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        self.$field *
                        F::from_i32($weight).unwrap();
                )+
                $($field +)+ F::from_f32(0.0).unwrap()
            }

            pub fn derivative(&self, t: F) -> F {
                let zero = F::from_f32(0.0).unwrap();
                let one  = F::from_f32(1.0).unwrap();
                assert!(zero <= t && t <= one);
                self.derivative_unbounded(t)
            }

            pub fn derivative_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($dleft),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $dleft =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        (self.$dleft - self.$dright) *
                        F::from_i32($dweight * (COUNT + 1)).unwrap();
                )+
                $($dleft +)+ F::from_f32(0.0).unwrap()
            }
        }
    }
}

n_bezier!{BezCubePoly {
    start: 1,
    ctrl0: 3,
    ctrl1: 3,
    end:   1
} derived {
    ctrl0 - start: 1,
    ctrl1 - ctrl0: 2,
    end   - ctrl1: 1
}}<|endoftext|>