<commit_before>//! Writes an activity to GPX format.

use std::io::Write;

use chrono::prelude::Utc;
use chrono::DateTime;

use xml::writer::{EmitterConfig, EventWriter, XmlEvent};

use geo_types::Rect;

use errors::*;
use types::*;
use Gpx;
use GpxVersion;

/// Writes an activity to GPX format.
///
/// Takes any `std::io::Write` as its writer, and returns a
/// `std::io::Result<()>`.
///
/// ```
/// use gpx::write;
/// use gpx::Gpx;
/// use gpx::GpxVersion;
///
/// let mut data : Gpx = Default::default();
/// data.version = GpxVersion::Gpx11;
///
/// // You can give it anything that implements `std::io::Write`.
/// write(&data, std::io::stdout()).unwrap();
/// ```
pub fn write<W: Write>(gpx: &Gpx, writer: W) -> Result<()> {
    let mut writer = EmitterConfig::new()
        .perform_indent(true)
        .create_writer(writer);
    write_xml_event(
        XmlEvent::start_element("gpx")
            .attr("version", version_to_version_string(gpx.version)?)
            .attr("creator", "https://github.com/georust/gpx"),
        &mut writer,
    )?;
    write_metadata(gpx, &mut writer)?;
    for point in &gpx.waypoints {
        write_waypoint("wpt", point, &mut writer)?;
    }
    for track in &gpx.tracks {
        write_track(track, &mut writer)?;
    }
    write_xml_event(XmlEvent::end_element(), &mut writer)?;
    Ok(())
}

fn write_xml_event<'a, W, E>(event: E, writer: &mut EventWriter<W>) -> Result<()>
where
    W: Write,
    E: Into<XmlEvent<'a>>,
{
    writer
        .write(event)
        .chain_err(|| Error::from("error while writing gpx event"))
}

fn version_to_version_string(version: GpxVersion) -> Result<&'static str> {
    match version {
        GpxVersion::Gpx10 => Ok("1.0"),
        GpxVersion::Gpx11 => Ok("1.1"),
        version => Err(Error::from(format!("Unknown version {:?}", version))),
    }
}

fn write_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    match gpx.version {
        GpxVersion::Gpx10 => write_gpx10_metadata(gpx, writer),
        GpxVersion::Gpx11 => write_gpx11_metadata(gpx, writer),
        version => Err(Error::from(format!("Unknown version {:?}", version))),
    }
}

fn write_gpx10_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    if gpx.metadata.is_none() {
        return Ok(());
    }
    let metadata = gpx.metadata.as_ref().unwrap();
    write_string_if_exists("name", &metadata.name, writer)?;
    write_string_if_exists("description", &metadata.description, writer)?;
    if let Some(author) = metadata.author.as_ref() {
        write_string_if_exists("author", &author.name, writer)?;
        write_email_if_exists(&author.email, writer)?;
        if let Some(link) = author.link.as_ref() {
            write_string("url", &link.href, writer)?;
            write_string_if_exists("urlname", &link.text, writer)?;
        }
    }
    write_string_if_exists("keywords", &metadata.keywords, writer)?;
    write_time_if_exists(&metadata.time, writer)?;
    write_bounds_if_exists(&metadata.bounds, writer)?;
    Ok(())
}

fn write_gpx11_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    if gpx.metadata.is_none() {
        return Ok(());
    }
    let metadata = gpx.metadata.as_ref().unwrap();
    write_xml_event(XmlEvent::start_element("metadata"), writer)?;
    write_string_if_exists("name", &metadata.name, writer)?;
    write_string_if_exists("description", &metadata.description, writer)?;
    write_person_if_exists("author", &metadata.author, writer)?;
    write_string_if_exists("keywords", &metadata.keywords, writer)?;
    write_time_if_exists(&metadata.time, writer)?;
    for link in &metadata.links {
        write_link(&link, writer)?;
    }
    write_bounds_if_exists(&metadata.bounds, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_string<W: Write>(key: &str, value: &str, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(XmlEvent::start_element(key), writer)?;
    write_xml_event(XmlEvent::characters(value), writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_string_if_exists<W: Write>(
    key: &str,
    value: &Option<String>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_string(key, value, writer)?;
    }
    Ok(())
}

fn write_value_if_exists<W: Write, T: ToString>(
    key: &str,
    value: &Option<T>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_xml_event(XmlEvent::start_element(key), writer)?;
        let value = &value.to_string();
        write_xml_event(XmlEvent::characters(value), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_email_if_exists<W: Write>(
    email: &Option<String>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref email) = email {
        let mut parts = email.split("@");
        let id = parts.next().ok_or("Missing id part in email!")?;
        let domain = parts.next().ok_or("Missing domain part in email!")?;
        if parts.next().is_some() {
            bail!(ErrorKind::Msg(format!(
                "Email contains more than one @: {}",
                email
            )));
        }
        write_xml_event(
            XmlEvent::start_element("email")
                .attr("id", id)
                .attr("domain", domain),
            writer,
        )?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_link<W: Write>(link: &Link, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(
        XmlEvent::start_element("link").attr("href", &link.href),
        writer,
    )?;
    write_string_if_exists("text", &link.text, writer)?;
    write_string_if_exists("type", &link._type, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_link_if_exists<W: Write>(link: &Option<Link>, writer: &mut EventWriter<W>) -> Result<()> {
    if let Some(ref link) = link {
        write_link(link, writer)?;
    }
    Ok(())
}

fn write_person_if_exists<W: Write>(
    key: &str,
    value: &Option<Person>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_xml_event(XmlEvent::start_element(key), writer)?;
        write_string_if_exists("name", &value.name, writer)?;
        write_email_if_exists(&value.email, writer)?;
        write_link_if_exists(&value.link, writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_time_if_exists<W: Write>(
    time: &Option<DateTime<Utc>>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref time) = time {
        write_xml_event(XmlEvent::start_element("time"), writer)?;
        write_xml_event(XmlEvent::characters(&time.to_rfc3339()), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_bounds_if_exists<W: Write>(
    bounds: &Option<Rect<f64>>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref bounds) = bounds {
        write_xml_event(
            XmlEvent::start_element("bounds")
                .attr("minlat", &bounds.min.y.to_string())
                .attr("maxlat", &bounds.max.y.to_string())
                .attr("minlon", &bounds.min.x.to_string())
                .attr("maxlon", &bounds.max.x.to_string()),
            writer,
        )?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_fix_if_exists<W: Write>(fix: &Option<Fix>, writer: &mut EventWriter<W>) -> Result<()> {
    if let Some(ref fix) = fix {
        write_xml_event(XmlEvent::start_element("fix"), writer)?;
        let fix_str = match fix {
            Fix::None => "none",
            Fix::TwoDimensional => "2d",
            Fix::ThreeDimensional => "3d",
            Fix::DGPS => "dgps",
            Fix::PPS => "pps",
            Fix::Other(string) => string,
        };
        write_xml_event(XmlEvent::characters(fix_str), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_track<W: Write>(track: &Track, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(XmlEvent::start_element("trk"), writer)?;
    write_string_if_exists("name", &track.name, writer)?;
    write_string_if_exists("cmt", &track.comment, writer)?;
    write_string_if_exists("desc", &track.description, writer)?;
    write_string_if_exists("src", &track.source, writer)?;
    for link in &track.links {
        write_link(link, writer)?;
    }
    write_string_if_exists("type", &track._type, writer)?;
    for segment in &track.segments {
        write_track_segment(segment, writer)?;
    }
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_track_segment<W: Write>(
    segment: &TrackSegment,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    write_xml_event(XmlEvent::start_element("trkseg"), writer)?;
    for point in &segment.points {
        write_waypoint("trkpt", point, writer)?;
    }
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_waypoint<W: Write>(
    tagname: &str,
    waypoint: &Waypoint,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    write_xml_event(
        XmlEvent::start_element(tagname)
            .attr("lat", &waypoint.point().lat().to_string())
            .attr("lon", &waypoint.point().lng().to_string()),
        writer,
    )?;
    write_value_if_exists("ele", &waypoint.elevation, writer)?;
    // TODO: write speed if GPX version == 1.0
    write_time_if_exists(&waypoint.time, writer)?;
    write_value_if_exists("geoidheight", &waypoint.geoidheight, writer)?;
    write_string_if_exists("name", &waypoint.name, writer)?;
    write_string_if_exists("cmt", &waypoint.comment, writer)?;
    write_string_if_exists("desc", &waypoint.description, writer)?;
    write_string_if_exists("src", &waypoint.source, writer)?;
    for link in &waypoint.links {
        write_link(link, writer)?;
    }
    write_string_if_exists("sym", &waypoint.symbol, writer)?;
    write_string_if_exists("type", &waypoint._type, writer)?;
    write_fix_if_exists(&waypoint.fix, writer)?;
    write_value_if_exists("sat", &waypoint.sat, writer)?;
    write_value_if_exists("hdop", &waypoint.hdop, writer)?;
    write_value_if_exists("vdop", &waypoint.vdop, writer)?;
    write_value_if_exists("pdop", &waypoint.pdop, writer)?;
    write_value_if_exists("ageofdgpsdata", &waypoint.age, writer)?;
    write_value_if_exists("dgpsid", &waypoint.dgpsid, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}
<commit_msg>fix gpx_writer_write_test_with_accuracy<commit_after>//! Writes an activity to GPX format.

use std::io::Write;

use chrono::prelude::Utc;
use chrono::DateTime;

use xml::writer::{EmitterConfig, EventWriter, XmlEvent};

use geo_types::Rect;

use errors::*;
use types::*;
use Gpx;
use GpxVersion;

/// Writes an activity to GPX format.
///
/// Takes any `std::io::Write` as its writer, and returns a
/// `std::io::Result<()>`.
///
/// ```
/// use gpx::write;
/// use gpx::Gpx;
/// use gpx::GpxVersion;
///
/// let mut data : Gpx = Default::default();
/// data.version = GpxVersion::Gpx11;
///
/// // You can give it anything that implements `std::io::Write`.
/// write(&data, std::io::stdout()).unwrap();
/// ```
pub fn write<W: Write>(gpx: &Gpx, writer: W) -> Result<()> {
    let mut writer = EmitterConfig::new()
        .perform_indent(true)
        .create_writer(writer);
    write_xml_event(
        XmlEvent::start_element("gpx")
            .attr("version", version_to_version_string(gpx.version)?)
            .attr("creator", "https://github.com/georust/gpx"),
        &mut writer,
    )?;
    write_metadata(gpx, &mut writer)?;
    for point in &gpx.waypoints {
        write_waypoint("wpt", point, &mut writer)?;
    }
    for track in &gpx.tracks {
        write_track(track, &mut writer)?;
    }
    write_xml_event(XmlEvent::end_element(), &mut writer)?;
    Ok(())
}

fn write_xml_event<'a, W, E>(event: E, writer: &mut EventWriter<W>) -> Result<()>
where
    W: Write,
    E: Into<XmlEvent<'a>>,
{
    writer
        .write(event)
        .chain_err(|| Error::from("error while writing gpx event"))
}

fn version_to_version_string(version: GpxVersion) -> Result<&'static str> {
    match version {
        GpxVersion::Gpx10 => Ok("1.0"),
        GpxVersion::Gpx11 => Ok("1.1"),
        version => Err(Error::from(format!("Unknown version {:?}", version))),
    }
}

fn write_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    match gpx.version {
        GpxVersion::Gpx10 => write_gpx10_metadata(gpx, writer),
        GpxVersion::Gpx11 => write_gpx11_metadata(gpx, writer),
        version => Err(Error::from(format!("Unknown version {:?}", version))),
    }
}

fn write_gpx10_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    if gpx.metadata.is_none() {
        return Ok(());
    }
    let metadata = gpx.metadata.as_ref().unwrap();
    write_string_if_exists("name", &metadata.name, writer)?;
    write_string_if_exists("description", &metadata.description, writer)?;
    if let Some(author) = metadata.author.as_ref() {
        write_string_if_exists("author", &author.name, writer)?;
        write_email_if_exists(&author.email, writer)?;
        if let Some(link) = author.link.as_ref() {
            write_string("url", &link.href, writer)?;
            write_string_if_exists("urlname", &link.text, writer)?;
        }
    }
    write_string_if_exists("keywords", &metadata.keywords, writer)?;
    write_time_if_exists(&metadata.time, writer)?;
    write_bounds_if_exists(&metadata.bounds, writer)?;
    Ok(())
}

fn write_gpx11_metadata<W: Write>(gpx: &Gpx, writer: &mut EventWriter<W>) -> Result<()> {
    if gpx.metadata.is_none() {
        return Ok(());
    }
    let metadata = gpx.metadata.as_ref().unwrap();
    write_xml_event(XmlEvent::start_element("metadata"), writer)?;
    write_string_if_exists("name", &metadata.name, writer)?;
    write_string_if_exists("description", &metadata.description, writer)?;
    write_person_if_exists("author", &metadata.author, writer)?;
    write_string_if_exists("keywords", &metadata.keywords, writer)?;
    write_time_if_exists(&metadata.time, writer)?;
    for link in &metadata.links {
        write_link(&link, writer)?;
    }
    write_bounds_if_exists(&metadata.bounds, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_string<W: Write>(key: &str, value: &str, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(XmlEvent::start_element(key), writer)?;
    write_xml_event(XmlEvent::characters(value), writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_string_if_exists<W: Write>(
    key: &str,
    value: &Option<String>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_string(key, value, writer)?;
    }
    Ok(())
}

fn write_value_if_exists<W: Write, T: ToString>(
    key: &str,
    value: &Option<T>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_xml_event(XmlEvent::start_element(key), writer)?;
        let value = &value.to_string();
        write_xml_event(XmlEvent::characters(value), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_email_if_exists<W: Write>(
    email: &Option<String>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref email) = email {
        let mut parts = email.split("@");
        let id = parts.next().ok_or("Missing id part in email!")?;
        let domain = parts.next().ok_or("Missing domain part in email!")?;
        if parts.next().is_some() {
            bail!(ErrorKind::Msg(format!(
                "Email contains more than one @: {}",
                email
            )));
        }
        write_xml_event(
            XmlEvent::start_element("email")
                .attr("id", id)
                .attr("domain", domain),
            writer,
        )?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_link<W: Write>(link: &Link, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(
        XmlEvent::start_element("link").attr("href", &link.href),
        writer,
    )?;
    write_string_if_exists("text", &link.text, writer)?;
    write_string_if_exists("type", &link._type, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_link_if_exists<W: Write>(link: &Option<Link>, writer: &mut EventWriter<W>) -> Result<()> {
    if let Some(ref link) = link {
        write_link(link, writer)?;
    }
    Ok(())
}

fn write_person_if_exists<W: Write>(
    key: &str,
    value: &Option<Person>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref value) = value {
        write_xml_event(XmlEvent::start_element(key), writer)?;
        write_string_if_exists("name", &value.name, writer)?;
        write_email_if_exists(&value.email, writer)?;
        write_link_if_exists(&value.link, writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_time_if_exists<W: Write>(
    time: &Option<DateTime<Utc>>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref time) = time {
        write_xml_event(XmlEvent::start_element("time"), writer)?;
        write_xml_event(XmlEvent::characters(&time.to_rfc3339()), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_bounds_if_exists<W: Write>(
    bounds: &Option<Rect<f64>>,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    if let Some(ref bounds) = bounds {
        write_xml_event(
            XmlEvent::start_element("bounds")
                .attr("minlat", &bounds.min.y.to_string())
                .attr("maxlat", &bounds.max.y.to_string())
                .attr("minlon", &bounds.min.x.to_string())
                .attr("maxlon", &bounds.max.x.to_string()),
            writer,
        )?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_fix_if_exists<W: Write>(fix: &Option<Fix>, writer: &mut EventWriter<W>) -> Result<()> {
    if let Some(ref fix) = fix {
        write_xml_event(XmlEvent::start_element("fix"), writer)?;
        let fix_str = match fix {
            Fix::None => "none",
            Fix::TwoDimensional => "2d",
            Fix::ThreeDimensional => "3d",
            Fix::DGPS => "dgps",
            Fix::PPS => "pps",
            Fix::Other(string) => string,
        };
        write_xml_event(XmlEvent::characters(fix_str), writer)?;
        write_xml_event(XmlEvent::end_element(), writer)?;
    }
    Ok(())
}

fn write_track<W: Write>(track: &Track, writer: &mut EventWriter<W>) -> Result<()> {
    write_xml_event(XmlEvent::start_element("trk"), writer)?;
    write_string_if_exists("name", &track.name, writer)?;
    write_string_if_exists("cmt", &track.comment, writer)?;
    write_string_if_exists("desc", &track.description, writer)?;
    write_string_if_exists("src", &track.source, writer)?;
    for link in &track.links {
        write_link(link, writer)?;
    }
    write_string_if_exists("type", &track._type, writer)?;
    for segment in &track.segments {
        write_track_segment(segment, writer)?;
    }
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_track_segment<W: Write>(
    segment: &TrackSegment,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    write_xml_event(XmlEvent::start_element("trkseg"), writer)?;
    for point in &segment.points {
        write_waypoint("trkpt", point, writer)?;
    }
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}

fn write_waypoint<W: Write>(
    tagname: &str,
    waypoint: &Waypoint,
    writer: &mut EventWriter<W>,
) -> Result<()> {
    write_xml_event(
        XmlEvent::start_element(tagname)
            .attr("lat", &waypoint.point().lat().to_string())
            .attr("lon", &waypoint.point().lng().to_string()),
        writer,
    )?;
    write_value_if_exists("ele", &waypoint.elevation, writer)?;
    // TODO: write speed if GPX version == 1.0
    write_time_if_exists(&waypoint.time, writer)?;
    write_value_if_exists("geoidheight", &waypoint.geoidheight, writer)?;
    write_string_if_exists("name", &waypoint.name, writer)?;
    write_string_if_exists("cmt", &waypoint.comment, writer)?;
    write_string_if_exists("desc", &waypoint.description, writer)?;
    write_string_if_exists("src", &waypoint.source, writer)?;
    for link in &waypoint.links {
        write_link(link, writer)?;
    }
    write_string_if_exists("sym", &waypoint.symbol, writer)?;
    write_string_if_exists("type", &waypoint._type, writer)?;
    write_fix_if_exists(&waypoint.fix, writer)?;
    write_value_if_exists("sat", &waypoint.sat, writer)?;
    write_value_if_exists("hdop", &waypoint.hdop, writer)?;
    write_value_if_exists("vdop", &waypoint.vdop, writer)?;
    write_value_if_exists("pdop", &waypoint.pdop, writer)?;
    write_value_if_exists("ageofgpsdata", &waypoint.age, writer)?;
    write_value_if_exists("dgpsid", &waypoint.dgpsid, writer)?;
    write_xml_event(XmlEvent::end_element(), writer)?;
    Ok(())
}
<|endoftext|>


<commit_before>//
// writer.rs
// Copyright (C) 2015 Adrian Perez <aperez@igalia.com>
// Distributed under terms of the MIT license.
//

use std::io;
use std::fmt;
use std::collections::BTreeMap;
use super::value::Value;

trait Formatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write;
    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write;
    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write;
    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write;
}

pub struct CompactFormatter;

impl Formatter for CompactFormatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&[ch])
    }

    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&[ch])
    }

    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => Ok(()),
            _ => writer.write_all(b":"),
        }
    }

    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => Ok(()),
            _ => writer.write_all(b","),
        }
    }
}

pub struct PrettyFormatter {
    indent: usize,
}

impl PrettyFormatter {
    fn new() -> Self {
        PrettyFormatter { indent: 0 }
    }
}

#[inline]
fn indent<W>(writer: &mut W, indent: usize) -> io::Result<()>
    where W: io::Write
{
    for _ in 0..indent {
        try!(writer.write_all(b"  "));
    }
    Ok(())
}

impl Formatter for PrettyFormatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        self.indent += 1;
        try!(writer.write_all(&[ch, b'\n']));
        indent(writer, self.indent)
    }

    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        self.indent -= 1;
        try!(writer.write(b"\n"));
        try!(indent(writer, self.indent));
        writer.write_all(&[ch])
    }

    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => writer.write_all(b" "),
            _ => writer.write_all(b": "),
        }
    }

    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        try!(writer.write(b"\n"));
        indent(writer, self.indent)
    }
}

pub struct Writer<W, F=PrettyFormatter> {
    writer: W,
    format: F,
}

impl<W> Writer<W, CompactFormatter>
    where W: io::Write
{
    #[inline]
    pub fn compact(writer: W) -> Self {
        Writer::with_formatter(writer, CompactFormatter)
    }
}

impl<W> Writer<W>
    where W: io::Write
{
    #[inline]
    pub fn pretty(writer: W) -> Self {
        Writer::with_formatter(writer, PrettyFormatter::new())
    }
}

impl<W, F> Writer<W, F>
    where W: io::Write,
          F: Formatter,
{
    #[inline]
    fn with_formatter(writer: W, formatter: F) -> Self
        where W: io::Write,
              F: Formatter,
    {
        Writer {
            writer: writer,
            format: formatter,
        }
    }

    fn write_value(&mut self, value: &Value) -> io::Result<()> {
        match *value {
            Value::Bool(value) => self.write_bool(value),
            Value::Float(value) => self.write_float(value),
            Value::Integer(value) => self.write_integer(value),
            Value::String(ref value) => self.write_string(value),
            Value::List(ref value) => self.write_list(value),
            Value::Dict(ref value) => self.write_dict(value),
        }
    }

    fn write_bool(&mut self, value: bool) -> io::Result<()> {
        if value {
            self.writer.write_all(b"True")
        } else {
            self.writer.write_all(b"False")
        }
    }

    fn write_float(&mut self, value: f64) -> io::Result<()> {
        if value.is_nan() || value.is_infinite() {
            write!(self.writer, "{}", value)
        } else {
            let s = format!("{}", value);
            try!(self.writer.write_all(s.as_bytes()));
            if !s.contains(".") {
                try!(self.writer.write_all(b".0"));
            }
            Ok(())
        }
    }

    fn write_integer(&mut self, value: i64) -> io::Result<()> {
        write!(self.writer, "{}", value)
    }

    fn write_string(&mut self, value: &String) -> io::Result<()> {
        try!(self.writer.write_all(b"\""));
        for ch in value.bytes() {
            try!(match ch {
                0x09 => self.writer.write_all(b"\\t"),
                0x0A => self.writer.write_all(b"\\n"),
                0x0D => self.writer.write_all(b"\\r"),
                0x22 => self.writer.write_all(b"\\\""),
                0x5C => self.writer.write_all(b"\\\\"),
                ch if ch < 0xF => write!(self.writer, "\\0{:X}", ch),
                ch if ch < 0x20 => write!(self.writer, "\\{:X}", ch),
                ch => self.writer.write_all(&[ch]),
            });
        }
        self.writer.write_all(b"\"")
    }

    fn write_list(&mut self, value: &Vec<Value>) -> io::Result<()> {
        if value.is_empty() {
            return self.writer.write_all(b"[]");
        }

        let mut iter = value.iter().peekable();
        try!(self.format.start_compound(&mut self.writer, b'['));
        loop {
            match iter.next() {
                None => break,
                Some(value) => {
                    try!(self.write_value(value));
                    match iter.peek () {
                        Some(_) =>
                            try!(self.format.item_separator(&mut self.writer, value)),
                        None => (),
                    }
                },
            }
        }
        self.format.end_compound(&mut self.writer, b']')
    }

    fn write_dict(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
        if dict.is_empty() {
            return self.writer.write_all(b"{}");
        }

        try!(self.format.start_compound(&mut self.writer, b'{'));
        try!(self.write_keyval_items(dict));
        self.format.end_compound(&mut self.writer, b'}')
    }

    fn write_keyval_items(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
        let mut iter = dict.iter().peekable();
        loop {
            match iter.next() {
                None => break,
                Some((key, value)) => {
                    try!(self.writer.write_all(key.as_bytes()));
                    try!(self.format.key_separator(&mut self.writer, value));
                    try!(self.write_value(value));
                    match iter.peek () {
                        Some(&(_, ref value)) =>
                            try!(self.format.item_separator(&mut self.writer, value)),
                        None => (),
                    }
                },
            }
        }
        Ok(())
    }

    pub fn write_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
        self.write_keyval_items(value)
    }

    #[inline]
    pub fn write_framed_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
        self.write_dict(value)
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::value::Value;
    use std::io::{Cursor, Write};
    use std::collections::BTreeMap;
    use std::f64::{NAN, INFINITY};

    macro_rules! make_write_test {
        ($name:ident, $value:expr, $pretty:expr, $compact:expr) => {
            #[test]
            fn $name() {
                {
                    println!("Pretty");
                    let mut output = Cursor::new(Vec::new());
                    Writer::pretty(&mut output).write_value($value).ok();
                    assert_eq!($pretty, String::from_utf8(output.into_inner()).unwrap());
                }
                {
                    println!("Compact");
                    let mut output = Cursor::new(Vec::new());
                    Writer::compact(&mut output).write_value($value).ok();
                    assert_eq!($compact, String::from_utf8(output.into_inner()).unwrap());
                }
            }
        }
    }

    make_write_test!(bool_true,  &Value::Bool(true),  "True", "True");
    make_write_test!(bool_false, &Value::Bool(false), "False", "False");

    make_write_test!(list_empty, &Value::List(vec![]), "[]", "[]");
    make_write_test!(list_one,   &Value::List(vec![Value::Bool(true)]), "[\n  True\n]", "[True]");
    make_write_test!(list_two,   &Value::List(vec![Value::Bool(true), Value::Bool(false)]),
        "[\n  True\n  False\n]", "[True,False]");
    make_write_test!(list_nested,
                     &Value::List(vec![
                                  Value::Bool(true),
                                  Value::List(vec![Value::Bool(false)])]),
                     "[\n  True\n  [\n    False\n  ]\n]", "[True,[False]]");

    make_write_test!(dict_empty, &Value::Dict(BTreeMap::new()), "{}", "{}");
    make_write_test!(dict_one,   &Value::Dict((|| {
        let mut b = BTreeMap::new();
        b.insert("item".to_string(), Value::Bool(true));
        b
    })()), "{\n  item: True\n}", "{item:True}");
    make_write_test!(dict_two,   &Value::Dict((|| {
        let mut b = BTreeMap::new();
        b.insert("foo".to_string(), Value::Bool(true));
        b.insert("bar".to_string(), Value::Bool(false));
        b
    })()), "{\n  bar: False\n  foo: True\n}", "{bar:False,foo:True}");

    macro_rules! make_write_string_test {
        ($name:ident, $value:expr, $expected:expr) => {
            make_write_test!($name, &Value::String($value.to_string()), $expected, $expected);
        }
    }

    make_write_string_test!(string_empty, "", "\"\"");
    make_write_string_test!(string_non_empty, "foo bar", "\"foo bar\"");
    make_write_string_test!(string_unicode, "☺", "\"☺\"");
    make_write_string_test!(string_escapes, "\n\r\t\\\"", "\"\\n\\r\\t\\\\\\\"\"");
    make_write_string_test!(string_hexcode, "\0", "\"\\00\"");

    macro_rules! make_write_number_test {
        ($t:ident, $name:ident, $value:expr, $expected:expr) => {
            make_write_test!($name, &Value::$t($value), $expected, $expected);
        }
    }

    make_write_number_test!(Integer, integer_zero, 0, "0");
    make_write_number_test!(Integer, integer_negative, -34, "-34");

    make_write_number_test!(Float, float_zero, 0.0, "0.0");
    make_write_number_test!(Float, float_suffix, 1f64, "1.0");
    make_write_number_test!(Float, float_positive, 4.5, "4.5");
    make_write_number_test!(Float, float_negative, -3.2, "-3.2");
    make_write_number_test!(Float, float_nan, NAN, "NaN");
    make_write_number_test!(Float, float_infinite, INFINITY, "inf");
}
<commit_msg>writer: Mark small functions as #[inline]<commit_after>//
// writer.rs
// Copyright (C) 2015 Adrian Perez <aperez@igalia.com>
// Distributed under terms of the MIT license.
//

use std::io;
use std::fmt;
use std::collections::BTreeMap;
use super::value::Value;

trait Formatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write;
    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write;
    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write;
    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write;
}

pub struct CompactFormatter;

impl Formatter for CompactFormatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&[ch])
    }

    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&[ch])
    }

    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => Ok(()),
            _ => writer.write_all(b":"),
        }
    }

    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => Ok(()),
            _ => writer.write_all(b","),
        }
    }
}

pub struct PrettyFormatter {
    indent: usize,
}

impl PrettyFormatter {
    fn new() -> Self {
        PrettyFormatter { indent: 0 }
    }
}

#[inline]
fn indent<W>(writer: &mut W, indent: usize) -> io::Result<()>
    where W: io::Write
{
    for _ in 0..indent {
        try!(writer.write_all(b"  "));
    }
    Ok(())
}

impl Formatter for PrettyFormatter {
    fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        self.indent += 1;
        try!(writer.write_all(&[ch, b'\n']));
        indent(writer, self.indent)
    }

    fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
        where W: io::Write
    {
        self.indent -= 1;
        try!(writer.write(b"\n"));
        try!(indent(writer, self.indent));
        writer.write_all(&[ch])
    }

    fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        match *next {
            Value::Dict(_) | Value::List(_) => writer.write_all(b" "),
            _ => writer.write_all(b": "),
        }
    }

    fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
        where W: io::Write
    {
        try!(writer.write(b"\n"));
        indent(writer, self.indent)
    }
}

pub struct Writer<W, F=PrettyFormatter> {
    writer: W,
    format: F,
}

impl<W> Writer<W, CompactFormatter>
    where W: io::Write
{
    #[inline]
    pub fn compact(writer: W) -> Self {
        Writer::with_formatter(writer, CompactFormatter)
    }
}

impl<W> Writer<W>
    where W: io::Write
{
    #[inline]
    pub fn pretty(writer: W) -> Self {
        Writer::with_formatter(writer, PrettyFormatter::new())
    }
}

impl<W, F> Writer<W, F>
    where W: io::Write,
          F: Formatter,
{
    #[inline]
    fn with_formatter(writer: W, formatter: F) -> Self
        where W: io::Write,
              F: Formatter,
    {
        Writer {
            writer: writer,
            format: formatter,
        }
    }

    fn write_value(&mut self, value: &Value) -> io::Result<()> {
        match *value {
            Value::Bool(value) => self.write_bool(value),
            Value::Float(value) => self.write_float(value),
            Value::Integer(value) => self.write_integer(value),
            Value::String(ref value) => self.write_string(value),
            Value::List(ref value) => self.write_list(value),
            Value::Dict(ref value) => self.write_dict(value),
        }
    }

    #[inline]
    fn write_bool(&mut self, value: bool) -> io::Result<()> {
        if value {
            self.writer.write_all(b"True")
        } else {
            self.writer.write_all(b"False")
        }
    }

    #[inline]
    fn write_float(&mut self, value: f64) -> io::Result<()> {
        if value.is_nan() || value.is_infinite() {
            write!(self.writer, "{}", value)
        } else {
            let s = format!("{}", value);
            try!(self.writer.write_all(s.as_bytes()));
            if !s.contains(".") {
                try!(self.writer.write_all(b".0"));
            }
            Ok(())
        }
    }

    #[inline]
    fn write_integer(&mut self, value: i64) -> io::Result<()> {
        write!(self.writer, "{}", value)
    }

    #[inline]
    fn write_string(&mut self, value: &String) -> io::Result<()> {
        try!(self.writer.write_all(b"\""));
        for ch in value.bytes() {
            try!(match ch {
                0x09 => self.writer.write_all(b"\\t"),
                0x0A => self.writer.write_all(b"\\n"),
                0x0D => self.writer.write_all(b"\\r"),
                0x22 => self.writer.write_all(b"\\\""),
                0x5C => self.writer.write_all(b"\\\\"),
                ch if ch < 0xF => write!(self.writer, "\\0{:X}", ch),
                ch if ch < 0x20 => write!(self.writer, "\\{:X}", ch),
                ch => self.writer.write_all(&[ch]),
            });
        }
        self.writer.write_all(b"\"")
    }

    fn write_list(&mut self, value: &Vec<Value>) -> io::Result<()> {
        if value.is_empty() {
            return self.writer.write_all(b"[]");
        }

        let mut iter = value.iter().peekable();
        try!(self.format.start_compound(&mut self.writer, b'['));
        loop {
            match iter.next() {
                None => break,
                Some(value) => {
                    try!(self.write_value(value));
                    match iter.peek () {
                        Some(_) =>
                            try!(self.format.item_separator(&mut self.writer, value)),
                        None => (),
                    }
                },
            }
        }
        self.format.end_compound(&mut self.writer, b']')
    }

    #[inline]
    fn write_dict(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
        if dict.is_empty() {
            return self.writer.write_all(b"{}");
        }

        try!(self.format.start_compound(&mut self.writer, b'{'));
        try!(self.write_keyval_items(dict));
        self.format.end_compound(&mut self.writer, b'}')
    }

    fn write_keyval_items(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
        let mut iter = dict.iter().peekable();
        loop {
            match iter.next() {
                None => break,
                Some((key, value)) => {
                    try!(self.writer.write_all(key.as_bytes()));
                    try!(self.format.key_separator(&mut self.writer, value));
                    try!(self.write_value(value));
                    match iter.peek () {
                        Some(&(_, ref value)) =>
                            try!(self.format.item_separator(&mut self.writer, value)),
                        None => (),
                    }
                },
            }
        }
        Ok(())
    }

    #[inline]
    pub fn write_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
        self.write_keyval_items(value)
    }

    #[inline]
    pub fn write_framed_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
        self.write_dict(value)
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::value::Value;
    use std::io::{Cursor, Write};
    use std::collections::BTreeMap;
    use std::f64::{NAN, INFINITY};

    macro_rules! make_write_test {
        ($name:ident, $value:expr, $pretty:expr, $compact:expr) => {
            #[test]
            fn $name() {
                {
                    println!("Pretty");
                    let mut output = Cursor::new(Vec::new());
                    Writer::pretty(&mut output).write_value($value).ok();
                    assert_eq!($pretty, String::from_utf8(output.into_inner()).unwrap());
                }
                {
                    println!("Compact");
                    let mut output = Cursor::new(Vec::new());
                    Writer::compact(&mut output).write_value($value).ok();
                    assert_eq!($compact, String::from_utf8(output.into_inner()).unwrap());
                }
            }
        }
    }

    make_write_test!(bool_true,  &Value::Bool(true),  "True", "True");
    make_write_test!(bool_false, &Value::Bool(false), "False", "False");

    make_write_test!(list_empty, &Value::List(vec![]), "[]", "[]");
    make_write_test!(list_one,   &Value::List(vec![Value::Bool(true)]), "[\n  True\n]", "[True]");
    make_write_test!(list_two,   &Value::List(vec![Value::Bool(true), Value::Bool(false)]),
        "[\n  True\n  False\n]", "[True,False]");
    make_write_test!(list_nested,
                     &Value::List(vec![
                                  Value::Bool(true),
                                  Value::List(vec![Value::Bool(false)])]),
                     "[\n  True\n  [\n    False\n  ]\n]", "[True,[False]]");

    make_write_test!(dict_empty, &Value::Dict(BTreeMap::new()), "{}", "{}");
    make_write_test!(dict_one,   &Value::Dict((|| {
        let mut b = BTreeMap::new();
        b.insert("item".to_string(), Value::Bool(true));
        b
    })()), "{\n  item: True\n}", "{item:True}");
    make_write_test!(dict_two,   &Value::Dict((|| {
        let mut b = BTreeMap::new();
        b.insert("foo".to_string(), Value::Bool(true));
        b.insert("bar".to_string(), Value::Bool(false));
        b
    })()), "{\n  bar: False\n  foo: True\n}", "{bar:False,foo:True}");

    macro_rules! make_write_string_test {
        ($name:ident, $value:expr, $expected:expr) => {
            make_write_test!($name, &Value::String($value.to_string()), $expected, $expected);
        }
    }

    make_write_string_test!(string_empty, "", "\"\"");
    make_write_string_test!(string_non_empty, "foo bar", "\"foo bar\"");
    make_write_string_test!(string_unicode, "☺", "\"☺\"");
    make_write_string_test!(string_escapes, "\n\r\t\\\"", "\"\\n\\r\\t\\\\\\\"\"");
    make_write_string_test!(string_hexcode, "\0", "\"\\00\"");

    macro_rules! make_write_number_test {
        ($t:ident, $name:ident, $value:expr, $expected:expr) => {
            make_write_test!($name, &Value::$t($value), $expected, $expected);
        }
    }

    make_write_number_test!(Integer, integer_zero, 0, "0");
    make_write_number_test!(Integer, integer_negative, -34, "-34");

    make_write_number_test!(Float, float_zero, 0.0, "0.0");
    make_write_number_test!(Float, float_suffix, 1f64, "1.0");
    make_write_number_test!(Float, float_positive, 4.5, "4.5");
    make_write_number_test!(Float, float_negative, -3.2, "-3.2");
    make_write_number_test!(Float, float_nan, NAN, "NaN");
    make_write_number_test!(Float, float_infinite, INFINITY, "inf");
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Create_a_file

extern crate libc;

#[cfg(not(test))]
use std::io::{File, UserRead, UserWrite, UserExecute, fs};

#[cfg(not(test))]
fn main () {
    // Create a new file.
    // We get a Result object from File::create. We could check if there is an error
    // by using .is_error() or by using pattern matching. We choose here to ignore
    // the possibility of an error and just unwrap the value contained in the Result object.
    // This means that an error will cause the program to fail at runtime.
    let mut new_file = File::create(&Path::new("output.txt")).unwrap();

    // Write something trivial to the file.
    // Now we are handling a possible error by using pattern matching
    match writeln!(&mut new_file as &mut Writer, "Nothing here...") {
        Ok(()) => (),
        Err(e) => println!("Failed to write to file: {}", e),
    }

    // Create a directory
    // Here we handle a possible error by using the functions provided by result
    // The second argument sets the file permissions
    let result = fs::mkdir(&Path::new("docs"), UserRead|UserWrite|UserExecute);
    if result.is_err() {
        println!("Failed to create a directory: {}", result.err().unwrap());
    }
}
<commit_msg>add tests to create_file<commit_after>// Implements http://rosettacode.org/wiki/Create_a_file

extern crate libc;

use std::io;
use std::io::{File, fs};

#[cfg(not(test))]
fn main () {
    // Create a new file.  We get a Result object from
    // File::create. We could check if there is an error by using
    // .is_error() or by using pattern matching. We choose here to
    // ignore the possibility of an error and just unwrap the value
    // contained in the Result object.  This means that an error will
    // cause the program to fail at runtime.
    let mut new_file = File::create(&Path::new("build/output.txt")).unwrap();

    // Write something trivial to the file.
    // Now we are handling a possible error by using pattern matching
    match writeln!(&mut new_file as &mut Writer, "Nothing here...") {
        Ok(()) => (),
        Err(e) => println!("Failed to write to file: {}", e),
    }

    // Create a directory. Here we handle a possible error by using
    // the functions provided by result.  The second argument sets the
    // file permissions
    let result = fs::mkdir(&Path::new("build/docs"), io::UserRWX);
    if result.is_err() {
        println!("Failed to create a directory: {}", result.err().unwrap());
    }
}

#[test]
fn test_create_file() {
    let build_dir = Path::new("build-tests");
    if !(build_dir.exists() && build_dir.is_dir()) {
        let r = fs::mkdir(&build_dir, io::UserRWX);
        assert!(r.is_ok());
    }

    let file_path = Path::new("build-tests/create_file_test.txt");
    if file_path.exists() && file_path.is_file() {
        let r = fs::unlink(&file_path);
        assert!(r.is_ok());
    }
    match File::create(&file_path) {
        Ok(_) => assert!(true),
        Err(e) => fail!("failed to create_file at {}, error: {}",
                        file_path.display(),
                        e.desc)
    }
}
<|endoftext|>


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

extern crate cc;
extern crate glsl_to_cxx;
extern crate webrender_build;

use std::collections::HashSet;
use std::fmt::Write;
use webrender_build::shader::{ShaderFeatureFlags, get_shader_features};

// Shader key is in "name feature,feature" format.
// File name needs to be formatted as "name_feature_feature".
fn shader_file(shader_key: &str) -> String {
    shader_key.replace(' ', "_").replace(',', "_")
}

fn write_load_shader(shader_keys: &[String]) {
    let mut load_shader = String::new();
    for s in shader_keys {
        let _ = write!(load_shader, "#include \"{}.h\"\n", shader_file(s));
    }
    load_shader.push_str("ProgramLoader load_shader(const char* name) {\n");
    for s in shader_keys {
        let _ = write!(load_shader, "  if (!strcmp(name, \"{}\")) {{ return {}_program::loader; }}\n",
                       s, shader_file(s));
    }
    load_shader.push_str("  return nullptr;\n}\n");
    std::fs::write(std::env::var("OUT_DIR").unwrap() + "/load_shader.h", load_shader).unwrap();
}

fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String) {
    if !included.insert(shader.into()) {
        return;
    }
    println!("cargo:rerun-if-changed={}/{}.glsl", shader_dir, shader);
    let source = std::fs::read_to_string(format!("{}/{}.glsl", shader_dir, shader)).unwrap();
    for line in source.lines() {
        if line.starts_with("#include ") {
            let imports = line["#include ".len() ..].split(',');
            for import in imports {
                process_imports(shader_dir, import, included, output);
            }
        } else if line.starts_with("#version ") || line.starts_with("#extension ") {
            // ignore
        } else {
            output.push_str(line);
            output.push('\n');
        }
    }
}

fn translate_shader(shader_key: &str, shader_dir: &str) {
    let mut imported = String::from("#define SWGL 1\n#define __VERSION__ 150\n");
    let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
                   webrender_build::MAX_VERTEX_TEXTURE_WIDTH);

    let (basename, features) =
        shader_key.split_at(shader_key.find(' ').unwrap_or(shader_key.len()));
    if !features.is_empty() {
        for feature in features.trim().split(',') {
            let _ = write!(imported, "#define WR_FEATURE_{}\n", feature);
        }
    }

    process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported);

    let shader = shader_file(shader_key);

    let out_dir = std::env::var("OUT_DIR").unwrap();
    let imp_name = format!("{}/{}.c", out_dir, shader);
    std::fs::write(&imp_name, imported).unwrap();

    let mut build = cc::Build::new();
    if build.get_compiler().is_like_msvc() {
        build.flag("/EP").flag("/u");
    } else {
        build.flag("-xc").flag("-P").flag("-undef");
    }
    build.file(&imp_name);
    let vs = build.clone()
        .define("WR_VERTEX_SHADER", Some("1"))
        .expand();
    let fs = build.clone()
        .define("WR_FRAGMENT_SHADER", Some("1"))
        .expand();
    let vs_name = format!("{}/{}.vert", out_dir, shader);
    let fs_name = format!("{}/{}.frag", out_dir, shader);
    std::fs::write(&vs_name, vs).unwrap();
    std::fs::write(&fs_name, fs).unwrap();

    let args = vec![
        "glsl_to_cxx".to_string(),
        vs_name,
        fs_name,
    ];
    let result = glsl_to_cxx::translate(&mut args.into_iter());
    std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
}

fn main() {
    let shader_dir = match std::env::var("MOZ_SRC") {
        Ok(dir) => dir + "/gfx/wr/webrender/res",
        Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res",
    };

    let shader_flags =
        ShaderFeatureFlags::GL |
        ShaderFeatureFlags::DUAL_SOURCE_BLENDING |
        ShaderFeatureFlags::ADVANCED_BLEND_EQUATION |
        ShaderFeatureFlags::DEBUG;
    let mut shaders: Vec<String> = Vec::new();
    for (name, features) in get_shader_features(shader_flags) {
        shaders.extend(features.iter().map(|f| {
            if f.is_empty() { name.to_owned() } else { format!("{} {}", name, f) }
        }));
    }

    shaders.sort();

    for shader in &shaders {
        translate_shader(shader, &shader_dir);
    }

    write_load_shader(&shaders);

    println!("cargo:rerun-if-changed=src/blend.h");
    println!("cargo:rerun-if-changed=src/composite.h");
    println!("cargo:rerun-if-changed=src/gl_defs.h");
    println!("cargo:rerun-if-changed=src/glsl.h");
    println!("cargo:rerun-if-changed=src/program.h");
    println!("cargo:rerun-if-changed=src/rasterize.h");
    println!("cargo:rerun-if-changed=src/swgl_ext.h");
    println!("cargo:rerun-if-changed=src/texture.h");
    println!("cargo:rerun-if-changed=src/vector_type.h");
    println!("cargo:rerun-if-changed=src/gl.cc");
    let mut build = cc::Build::new();
    build.cpp(true);

    // SWGL relies heavily on inlining for performance so override -Oz with -O2
    if build.get_compiler().args().contains(&std::ffi::OsString::from("-Oz")) {
        build.flag("-O2");
    }

    build.file("src/gl.cc")
        .flag("-std=c++17")
        .flag("-UMOZILLA_CONFIG_H")
        .flag("-fno-exceptions")
        .flag("-fno-rtti")
        .flag("-fno-math-errno")
        .define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
        .include(shader_dir)
        .include("src")
        .include(std::env::var("OUT_DIR").unwrap())
        .compile("gl_cc");
}
<commit_msg>Bug 1698156 - Disable default flags for SWGL preprocessor. r=jrmuizel<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate glsl_to_cxx;
extern crate webrender_build;

use std::collections::HashSet;
use std::fmt::Write;
use webrender_build::shader::{ShaderFeatureFlags, get_shader_features};

// Shader key is in "name feature,feature" format.
// File name needs to be formatted as "name_feature_feature".
fn shader_file(shader_key: &str) -> String {
    shader_key.replace(' ', "_").replace(',', "_")
}

fn write_load_shader(shader_keys: &[String]) {
    let mut load_shader = String::new();
    for s in shader_keys {
        let _ = write!(load_shader, "#include \"{}.h\"\n", shader_file(s));
    }
    load_shader.push_str("ProgramLoader load_shader(const char* name) {\n");
    for s in shader_keys {
        let _ = write!(load_shader, "  if (!strcmp(name, \"{}\")) {{ return {}_program::loader; }}\n",
                       s, shader_file(s));
    }
    load_shader.push_str("  return nullptr;\n}\n");
    std::fs::write(std::env::var("OUT_DIR").unwrap() + "/load_shader.h", load_shader).unwrap();
}

fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String) {
    if !included.insert(shader.into()) {
        return;
    }
    println!("cargo:rerun-if-changed={}/{}.glsl", shader_dir, shader);
    let source = std::fs::read_to_string(format!("{}/{}.glsl", shader_dir, shader)).unwrap();
    for line in source.lines() {
        if line.starts_with("#include ") {
            let imports = line["#include ".len() ..].split(',');
            for import in imports {
                process_imports(shader_dir, import, included, output);
            }
        } else if line.starts_with("#version ") || line.starts_with("#extension ") {
            // ignore
        } else {
            output.push_str(line);
            output.push('\n');
        }
    }
}

fn translate_shader(shader_key: &str, shader_dir: &str) {
    let mut imported = String::from("#define SWGL 1\n#define __VERSION__ 150\n");
    let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
                   webrender_build::MAX_VERTEX_TEXTURE_WIDTH);

    let (basename, features) =
        shader_key.split_at(shader_key.find(' ').unwrap_or(shader_key.len()));
    if !features.is_empty() {
        for feature in features.trim().split(',') {
            let _ = write!(imported, "#define WR_FEATURE_{}\n", feature);
        }
    }

    process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported);

    let shader = shader_file(shader_key);

    let out_dir = std::env::var("OUT_DIR").unwrap();
    let imp_name = format!("{}/{}.c", out_dir, shader);
    std::fs::write(&imp_name, imported).unwrap();

    let mut build = cc::Build::new();
    build.no_default_flags(true);
    if build.get_compiler().is_like_msvc() {
        build.flag("/EP").flag("/u");
    } else {
        build.flag("-xc").flag("-P").flag("-undef");
    }
    build.file(&imp_name);
    let vs = build.clone()
        .define("WR_VERTEX_SHADER", Some("1"))
        .expand();
    let fs = build.clone()
        .define("WR_FRAGMENT_SHADER", Some("1"))
        .expand();
    let vs_name = format!("{}/{}.vert", out_dir, shader);
    let fs_name = format!("{}/{}.frag", out_dir, shader);
    std::fs::write(&vs_name, vs).unwrap();
    std::fs::write(&fs_name, fs).unwrap();

    let args = vec![
        "glsl_to_cxx".to_string(),
        vs_name,
        fs_name,
    ];
    let result = glsl_to_cxx::translate(&mut args.into_iter());
    std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
}

fn main() {
    let shader_dir = match std::env::var("MOZ_SRC") {
        Ok(dir) => dir + "/gfx/wr/webrender/res",
        Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res",
    };

    let shader_flags =
        ShaderFeatureFlags::GL |
        ShaderFeatureFlags::DUAL_SOURCE_BLENDING |
        ShaderFeatureFlags::ADVANCED_BLEND_EQUATION |
        ShaderFeatureFlags::DEBUG;
    let mut shaders: Vec<String> = Vec::new();
    for (name, features) in get_shader_features(shader_flags) {
        shaders.extend(features.iter().map(|f| {
            if f.is_empty() { name.to_owned() } else { format!("{} {}", name, f) }
        }));
    }

    shaders.sort();

    for shader in &shaders {
        translate_shader(shader, &shader_dir);
    }

    write_load_shader(&shaders);

    println!("cargo:rerun-if-changed=src/blend.h");
    println!("cargo:rerun-if-changed=src/composite.h");
    println!("cargo:rerun-if-changed=src/gl_defs.h");
    println!("cargo:rerun-if-changed=src/glsl.h");
    println!("cargo:rerun-if-changed=src/program.h");
    println!("cargo:rerun-if-changed=src/rasterize.h");
    println!("cargo:rerun-if-changed=src/swgl_ext.h");
    println!("cargo:rerun-if-changed=src/texture.h");
    println!("cargo:rerun-if-changed=src/vector_type.h");
    println!("cargo:rerun-if-changed=src/gl.cc");
    let mut build = cc::Build::new();
    build.cpp(true);

    // SWGL relies heavily on inlining for performance so override -Oz with -O2
    if build.get_compiler().args().contains(&std::ffi::OsString::from("-Oz")) {
        build.flag("-O2");
    }

    build.file("src/gl.cc")
        .flag("-std=c++17")
        .flag("-UMOZILLA_CONFIG_H")
        .flag("-fno-exceptions")
        .flag("-fno-rtti")
        .flag("-fno-math-errno")
        .define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
        .include(shader_dir)
        .include("src")
        .include(std::env::var("OUT_DIR").unwrap())
        .compile("gl_cc");
}
<|endoftext|>


<commit_before>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> &mut Room {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        self.room_from_matrix(&room_id.unwrap())
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg).unwrap();
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        let mut events: Vec<matrix::events::Event> = vec![];
        self.matrix.sync().and_then(|events| {
            for e in events {
                self.handle_matrix(e);
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and(self.start_matrix(events.channel()))
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                let room = self.room_from_irc(&message.args[0]);
                                matrix::events::EventData::Room(
                                    room.id.clone(),
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: drop usage of anony.oob and use user homeservers<commit_after>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@{}", user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@{}", user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@{}", user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@{}", user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> &mut Room {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        self.room_from_matrix(&room_id.unwrap())
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg).unwrap();
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        let mut events: Vec<matrix::events::Event> = vec![];
        self.matrix.sync().and_then(|events| {
            for e in events {
                self.handle_matrix(e);
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and(self.start_matrix(events.channel()))
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                let room = self.room_from_irc(&message.args[0]);
                                matrix::events::EventData::Room(
                                    room.id.clone(),
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>pub struct Broker<T: Subscriber> {
    subscriptions: Subscriptions<T>,
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker{ subscriptions: Subscriptions::<T>::new()}
    }

    pub fn publish(&mut self, topic: &str, payload: &[u8]) {
        self.subscriptions.publish(topic, payload);
    }

    pub fn subscribe(&mut self, subscriber: T, topics: &[&str]) {
        self.subscriptions.subscribers.push(subscriber);
    }
}

pub struct Subscriptions<T: Subscriber> {
    subscribers: Vec<T>,
}

impl<T: Subscriber> Subscriptions<T> {
    fn new() -> Self {
        return Subscriptions { subscribers: vec![], }
    }

    fn publish(&mut self, topic: &str, payload: &[u8]) {
        for s in &mut self.subscribers {
            if topic == "topics/foo" {
                s.new_message(&[0, 1, 3]);
            }
        }
    }
}

pub trait Subscriber {
    fn new() -> Self;
    fn new_message(&mut self, bytes: &[u8]);
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}
#[cfg(test)]
impl TestSubscriber {
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new() -> Self {
        return TestSubscriber{msgs: vec![]}
    }

    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn no_subscriptions() {
    let mut broker = Broker::<TestSubscriber>::new();
    let subscriber = TestSubscriber::new();
    broker.publish("topics/foo", &[0, 1, 3]);
    assert_eq!(subscriber.msgs.len(), 0);

    broker.subscribe(subscriber, &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 3]);
    broker.publish("topics/bar", &[2, 4, 6]);
    let subscriber = &broker.subscriptions.subscribers[0];
    assert_eq!(subscriber.msgs.len(), 1);
    assert_eq!(subscriber.msgs[0], &[0, 1, 3]);

    // broker.subscribe(&subscriber, &["topics/bar"]);
    // broker.publish("topics/foo", &[1, 3, 5, 7]);
    // broker.publish("topics/bar", &[2, 4]);
    // assert_eq!(subscriber.msgs.len(), 3);
    // assert_eq!(subscriber.msgs[0], &[0, 1, 3]);
    // assert_eq!(subscriber.msgs[1], &[1, 3, 5, 7]);
    // assert_eq!(subscriber.msgs[1], &[2, 4]);
}
<commit_msg>Ugly impl, but UT for publishing passes for broker<commit_after>use std::rc::{Rc};
use std::cell::{RefCell};

pub struct Broker<T: Subscriber> {
    subscriptions: Subscriptions<T>,
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker{ subscriptions: Subscriptions::<T>::new()}
    }

    pub fn publish(&mut self, topic: &str, payload: &[u8]) {
        self.subscriptions.publish(topic, payload);
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        for sub in &self.subscriptions.subscribers {
            let sub1 = sub.clone();
            let sub2 = subscriber.clone();
            if sub1.borrow().id() == sub2.borrow().id() {
                sub2.borrow_mut().append_topics(topics);
                return;
            }
        }
        self.subscriptions.subscribers.push(subscriber);
        let lesub = self.subscriptions.subscribers[self.subscriptions.subscribers.len() - 1].clone();
        lesub.borrow_mut().append_topics(topics);
    }
}

pub struct Subscriptions<T: Subscriber> {
    subscribers: Vec<Rc<RefCell<T>>>,
}

impl<T: Subscriber> Subscriptions<T> {
    fn new() -> Self {
        return Subscriptions { subscribers: vec![], }
    }

    fn publish(&mut self, topic: &str, payload: &[u8]) {
        for s in &mut self.subscribers {
            let sub_clone = s.clone();
            let mut s = sub_clone.borrow_mut();

            for t in s.topics() {
                if t == topic {
                    s.new_message(payload);
                }
            }
        }
    }
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
    fn id(&self) -> i64;
    fn append_topics(&mut self, topics: &[&str]);
    fn topics(&self) -> Vec<String>;
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
    id: i64,
    topics: Vec<String>,
}
#[cfg(test)]
impl TestSubscriber {
    fn new(id: i64) -> Self {
        return TestSubscriber{msgs: vec![], id: id, topics: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {

    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }

    fn id(&self) -> i64 {
        return self.id;
    }

    fn append_topics(&mut self, topics: &[&str]) {
        let mut new_topics = topics.to_vec().into_iter().map(|t| t.to_string()).collect();
        self.topics.append(&mut new_topics);
        println!("after append, len is {}", self.topics.len());
    }

    fn topics(&self) -> Vec<String> {
        println!("self topics len: {}", self.topics.len());
        self.topics.clone()
    }
}

#[test]
fn no_subscriptions() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_ref = Rc::new(RefCell::new(TestSubscriber::new(42)));
    let subscriber = sub_ref.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4, 6]);
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), &["topics/bar"]);
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}
<|endoftext|>


<commit_before>use bits;
use data;
use voice;

pub trait Storage {
    type Input: Copy;
    type Buf;

    fn size(&self) -> usize;
    fn buf(&mut self) -> &mut Self::Buf;
    fn add(&mut self, item: Self::Input, pos: usize);
    fn reset(&mut self) {}
}

macro_rules! storage_type {
    ($name: ident, [$input: ty; $size: expr]) => {
        pub struct $name([$input; $size]);

        impl $name {
            pub fn new() -> Self { $name([Default::default(); $size]) }
        }

        impl Storage for $name {
            type Input = $input;
            type Buf = [$input; $size];

            fn size(&self) -> usize { $size }
            fn buf(&mut self) -> &mut Self::Buf { &mut self.0 }
            fn add(&mut self, item: Self::Input, pos: usize) { self.0[pos] = item; }
        }
    };
}

storage_type!(VoiceHeaderStorage, [bits::Hexbit; 36]);
storage_type!(VoiceFrameStorage, [bits::Dibit; voice::consts::FRAME_DIBITS]);
storage_type!(VoiceExtraStorage, [bits::Hexbit; 24]);
storage_type!(DataPayloadStorage, [bits::Dibit; data::consts::CODING_DIBITS]);

pub struct DibitStorage {
    buf: u64,
    size: usize,
}

impl DibitStorage {
    pub fn new(size: usize) -> DibitStorage {
        assert!(size <= 32);

        DibitStorage {
            buf: 0,
            size: size,
        }
    }
}

impl Storage for DibitStorage {
    type Input = bits::Dibit;
    type Buf = u64;

    fn size(&self) -> usize { self.size }
    fn buf(&mut self) -> &mut u64 { &mut self.buf }

    fn add(&mut self, item: Self::Input, _: usize) {
        self.buf <<= 2;
        self.buf |= item.bits() as u64;
    }

    fn reset(&mut self) { self.buf = 0; }
}

pub struct Buffer<S: Storage> {
    storage: S,
    pos: usize,
}

impl<S: Storage> Buffer<S> {
    pub fn new(storage: S) -> Buffer<S> {
        Buffer {
            storage: storage,
            pos: 0,
        }
    }

    pub fn reset(&mut self) { self.pos = 0; }

    /// the buffer is reset once `Some` is returned.
    pub fn feed(&mut self, item: S::Input) -> Option<&mut S::Buf> {
        if self.pos == 0 {
            self.storage.reset();
        }

        self.storage.add(item, self.pos);
        self.pos += 1;

        if self.pos == self.storage.size() {
            self.reset();
            Some(self.storage.buf())
        } else {
            None
        }
    }
}
<commit_msg>Add some comments to buffer<commit_after>use bits;
use data;
use voice;

/// Backing storage for a Buffer.
pub trait Storage {
    /// Type of item stored.
    type Input: Copy;
    /// Type of backing storage.
    type Buf;

    /// Number of items that can be stored.
    fn size(&self) -> usize;
    /// Get the storage buffer.
    fn buf(&mut self) -> &mut Self::Buf;
    /// Add an item to the buffer at the given position.
    fn add(&mut self, item: Self::Input, pos: usize);
    /// Reset buffer to "empty" state.
    fn reset(&mut self);
}

macro_rules! storage_type {
    ($name: ident, [$input: ty; $size: expr]) => {
        pub struct $name([$input; $size]);

        impl $name {
            pub fn new() -> Self { $name([Default::default(); $size]) }
        }

        impl Storage for $name {
            type Input = $input;
            type Buf = [$input; $size];

            fn size(&self) -> usize { $size }
            fn buf(&mut self) -> &mut Self::Buf { &mut self.0 }
            fn add(&mut self, item: Self::Input, pos: usize) { self.0[pos] = item; }
            // No need to reset because the buffer won't be seen in a non-full state.
            fn reset(&mut self) {}
        }
    };
}

storage_type!(VoiceHeaderStorage, [bits::Hexbit; 36]);
storage_type!(VoiceFrameStorage, [bits::Dibit; voice::consts::FRAME_DIBITS]);
storage_type!(VoiceExtraStorage, [bits::Hexbit; 24]);
storage_type!(DataPayloadStorage, [bits::Dibit; data::consts::CODING_DIBITS]);

pub struct DibitStorage {
    buf: u64,
    size: usize,
}

impl DibitStorage {
    pub fn new(size: usize) -> DibitStorage {
        assert!(size <= 32);

        DibitStorage {
            buf: 0,
            size: size,
        }
    }
}

impl Storage for DibitStorage {
    type Input = bits::Dibit;
    type Buf = u64;

    fn size(&self) -> usize { self.size }
    fn buf(&mut self) -> &mut u64 { &mut self.buf }

    fn add(&mut self, item: Self::Input, _: usize) {
        self.buf <<= 2;
        self.buf |= item.bits() as u64;
    }

    fn reset(&mut self) { self.buf = 0; }
}

pub struct Buffer<S: Storage> {
    storage: S,
    pos: usize,
}

impl<S: Storage> Buffer<S> {
    pub fn new(storage: S) -> Buffer<S> {
        Buffer {
            storage: storage,
            pos: 0,
        }
    }

    pub fn reset(&mut self) { self.pos = 0; }

    /// Add the given item to the buffer and return the buffer if it's completed.
    pub fn feed(&mut self, item: S::Input) -> Option<&mut S::Buf> {
        if self.pos == 0 {
            self.storage.reset();
        }

        self.storage.add(item, self.pos);
        self.pos += 1;

        if self.pos == self.storage.size() {
            self.reset();
            Some(self.storage.buf())
        } else {
            None
        }
    }
}
<|endoftext|>