<commit_before>extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use handlebars::Handlebars;
use itertools::Itertools;
use serde_json::Value;
use std::collections::BTreeMap;

trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

#[derive(Debug, Deserialize)]
pub struct AMQProtocolDefinition {
    pub name:          String,
    #[serde(rename="major-version")]
    pub major_version: u8,
    #[serde(rename="minor-version")]
    pub minor_version: u8,
    pub revision:      u8,
    pub port:          u32,
    pub copyright:     Vec<String>,
    pub domains:       Vec<AMQPDomain>,
    pub constants:     Vec<AMQPConstant>,
    pub classes:       Vec<AMQPClass>,
}

impl AMQProtocolDefinition {
    pub fn codegen(&self, templates: &AMQPTemplates) -> String {
        let handlebars = register_templates(templates);
        let mut data   = BTreeMap::new();

        data.insert("name".to_string(),          self.name.clone());
        data.insert("major_version".to_string(), format!("{}", self.major_version));
        data.insert("minor_version".to_string(), format!("{}", self.minor_version));
        data.insert("revision".to_string(),      format!("{}", self.revision));
        data.insert("port".to_string(),          format!("{}", self.port));
        data.insert("copyright".to_string(),     self.copyright.iter().join("\n"));
        data.insert("domains".to_string(),       self.domains.iter().map(|domain| domain.codegen(&handlebars)).join("\n"));
        data.insert("constants".to_string(),     self.constants.iter().map(|constant| constant.codegen(&handlebars)).join("\n"));
        data.insert("classes".to_string(),       self.classes.iter().map(|klass| klass.codegen(&handlebars)).join("\n"));

        handlebars.render("main", &data).expect("Failed to render main template")
    }
}

fn register_templates(templates: &AMQPTemplates) -> Handlebars {
    let mut handlebars = Handlebars::new();

    handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
    handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
    handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
    handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
    handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
    handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
    handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

    handlebars
}

pub struct AMQPTemplates {
    pub main:     String,
    pub domain:   String,
    pub constant: String,
    pub klass:    String,
    pub method:   String,
    pub argument: String,
    pub property: String,
}

#[derive(Debug, Deserialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl AMQPType {
    fn to_string(&self) -> String {
        match *self {
            AMQPType::Bit       => "bit",
            AMQPType::Octet     => "octet",
            AMQPType::Short     => "short",
            AMQPType::Long      => "long",
            AMQPType::LongLong  => "longlong",
            AMQPType::ShortStr  => "shortstr",
            AMQPType::LongStr   => "longstr",
            AMQPType::Table     => "table",
            AMQPType::Timestamp => "timestamp",
        }.to_string()
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPDomain(String, AMQPType);

impl Codegen for AMQPDomain {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(), self.0.clone());
        data.insert("type".to_string(), self.1.to_string());

        handlebars.render("domain", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPConstant {
    pub name:  String,
    pub value: u16,
    #[serde(rename="class")]
    pub klass: Option<String>,
}

impl Codegen for AMQPConstant {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),  self.name.clone());
        data.insert("value".to_string(), format!("{}", self.value));
        if let Some(ref klass) = self.klass {
            data.insert("class".to_string(), klass.clone());
        }

        handlebars.render("constant", &data).expect("Failed to render constant template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPClass {
    pub id:         u8,
    pub methods:    Vec<AMQPMethod>,
    pub name:       String,
    pub properties: Option<Vec<AMQPProperty>>,
}

impl Codegen for AMQPClass {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),      format!("{}", self.id));
        data.insert("methods".to_string(), self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),    self.name.clone());
        if let Some(ref properties) = self.properties {
            data.insert("properties".to_string(), properties.iter().map(|prop| prop.codegen(&handlebars)).join("\n"));
        }

        handlebars.render("class", &data).expect("Failed to render class template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPMethod {
    pub id:          u8,
    pub arguments:   Vec<AMQPArgument>,
    pub name:        String,
    pub synchronous: Option<bool>,
}

impl Codegen for AMQPMethod {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),          format!("{}", self.id));
        data.insert("arguments".to_string(),   self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),        self.name.clone());
        data.insert("synchronous".to_string(), format!("{}", self.synchronous.unwrap_or(false)));

        handlebars.render("method", &data).expect("Failed to render method template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPArgument {
    #[serde(rename="type")]
    pub amqp_type:     Option<AMQPType>,
    pub name:          String,
    #[serde(rename="default-value")]
    pub default_value: Option<Value>,
    pub domain:        Option<String>,
}

impl Codegen for AMQPArgument {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        if let Some(ref amqp_type) = self.amqp_type {
            data.insert("type".to_string(), amqp_type.to_string());
        }
        if let Some(ref default_value) = self.default_value {
            data.insert("default_value".to_string(), default_value.to_string()); /* FIXME: handlebars fials with string here transforming " into &amp;amp;quot; */
        }
        data.insert("name".to_string(),   self.name.clone());
        if let Some(ref domain) = self.domain {
            data.insert("domain".to_string(), domain.clone());
        }

        handlebars.render("argument", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPProperty {
    #[serde(rename="type")]
    pub amqp_type: AMQPType,
    pub name:      String,
}

impl Codegen for AMQPProperty {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("type".to_string(), self.amqp_type.to_string());
        data.insert("name".to_string(), self.name.clone());

        handlebars.render("property", &data).expect("Failed to render domain template")
    }
}

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

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1".to_string(), "Copyright 2".to_string()],
            domains:       vec![AMQPDomain("domain1".to_string(), AMQPType::Octet)],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::Long),
                                    name:          "argument1".to_string(),
                                    default_value: Some(From::from(666)),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongStr,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{name}} - {{major_version}}.{{minor_version}}.{{revision}}
{{copyright}}
port {{port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{name}}: {{type}}".to_string(),
            constant: "{{name}}({{class}}) = {{value}}".to_string(),
            klass:    r#"
{{id}} - {{name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{id}} - {{name}}
synchronous: {{synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{name}}({{domain}}): {{type}} = {{default_value}}".to_string(),
            property: "{{name}}: {{type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().codegen(&templates()), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: octet
constant1(class1) = 128

42 - class1
property1: longstr

64 - method1
synchronous: true
argument1(domain1): long = 666

"#);
    }
}
<commit_msg>codegen: fix escaping in templates<commit_after>extern crate handlebars;
extern crate itertools;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use handlebars::Handlebars;
use itertools::Itertools;
use serde_json::Value;
use std::collections::BTreeMap;

trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

#[derive(Debug, Deserialize)]
pub struct AMQProtocolDefinition {
    pub name:          String,
    #[serde(rename="major-version")]
    pub major_version: u8,
    #[serde(rename="minor-version")]
    pub minor_version: u8,
    pub revision:      u8,
    pub port:          u32,
    pub copyright:     Vec<String>,
    pub domains:       Vec<AMQPDomain>,
    pub constants:     Vec<AMQPConstant>,
    pub classes:       Vec<AMQPClass>,
}

impl AMQProtocolDefinition {
    pub fn codegen(&self, templates: &AMQPTemplates) -> String {
        let handlebars = register_templates(templates);
        let mut data   = BTreeMap::new();

        data.insert("name".to_string(),          self.name.clone());
        data.insert("major_version".to_string(), format!("{}", self.major_version));
        data.insert("minor_version".to_string(), format!("{}", self.minor_version));
        data.insert("revision".to_string(),      format!("{}", self.revision));
        data.insert("port".to_string(),          format!("{}", self.port));
        data.insert("copyright".to_string(),     self.copyright.iter().join("\n"));
        data.insert("domains".to_string(),       self.domains.iter().map(|domain| domain.codegen(&handlebars)).join("\n"));
        data.insert("constants".to_string(),     self.constants.iter().map(|constant| constant.codegen(&handlebars)).join("\n"));
        data.insert("classes".to_string(),       self.classes.iter().map(|klass| klass.codegen(&handlebars)).join("\n"));

        handlebars.render("main", &data).expect("Failed to render main template")
    }
}

fn register_templates(templates: &AMQPTemplates) -> Handlebars {
    let mut handlebars = Handlebars::new();

    handlebars.register_escape_fn(handlebars::no_escape);

    handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
    handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
    handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
    handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
    handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
    handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
    handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

    handlebars
}

pub struct AMQPTemplates {
    pub main:     String,
    pub domain:   String,
    pub constant: String,
    pub klass:    String,
    pub method:   String,
    pub argument: String,
    pub property: String,
}

#[derive(Debug, Deserialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Bit,
    #[serde(rename="octet")]
    Octet,
    #[serde(rename="short")]
    Short,
    #[serde(rename="long")]
    Long,
    #[serde(rename="longlong")]
    LongLong,
    #[serde(rename="shortstr")]
    ShortStr,
    #[serde(rename="longstr")]
    LongStr,
    #[serde(rename="table")]
    Table,
    #[serde(rename="timestamp")]
    Timestamp,
}

impl AMQPType {
    fn to_string(&self) -> String {
        match *self {
            AMQPType::Bit       => "bit",
            AMQPType::Octet     => "octet",
            AMQPType::Short     => "short",
            AMQPType::Long      => "long",
            AMQPType::LongLong  => "longlong",
            AMQPType::ShortStr  => "shortstr",
            AMQPType::LongStr   => "longstr",
            AMQPType::Table     => "table",
            AMQPType::Timestamp => "timestamp",
        }.to_string()
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPDomain(String, AMQPType);

impl Codegen for AMQPDomain {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(), self.0.clone());
        data.insert("type".to_string(), self.1.to_string());

        handlebars.render("domain", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPConstant {
    pub name:  String,
    pub value: u16,
    #[serde(rename="class")]
    pub klass: Option<String>,
}

impl Codegen for AMQPConstant {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("name".to_string(),  self.name.clone());
        data.insert("value".to_string(), format!("{}", self.value));
        if let Some(ref klass) = self.klass {
            data.insert("class".to_string(), klass.clone());
        }

        handlebars.render("constant", &data).expect("Failed to render constant template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPClass {
    pub id:         u8,
    pub methods:    Vec<AMQPMethod>,
    pub name:       String,
    pub properties: Option<Vec<AMQPProperty>>,
}

impl Codegen for AMQPClass {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),      format!("{}", self.id));
        data.insert("methods".to_string(), self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),    self.name.clone());
        if let Some(ref properties) = self.properties {
            data.insert("properties".to_string(), properties.iter().map(|prop| prop.codegen(&handlebars)).join("\n"));
        }

        handlebars.render("class", &data).expect("Failed to render class template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPMethod {
    pub id:          u8,
    pub arguments:   Vec<AMQPArgument>,
    pub name:        String,
    pub synchronous: Option<bool>,
}

impl Codegen for AMQPMethod {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("id".to_string(),          format!("{}", self.id));
        data.insert("arguments".to_string(),   self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"));
        data.insert("name".to_string(),        self.name.clone());
        data.insert("synchronous".to_string(), format!("{}", self.synchronous.unwrap_or(false)));

        handlebars.render("method", &data).expect("Failed to render method template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPArgument {
    #[serde(rename="type")]
    pub amqp_type:     Option<AMQPType>,
    pub name:          String,
    #[serde(rename="default-value")]
    pub default_value: Option<Value>,
    pub domain:        Option<String>,
}

impl Codegen for AMQPArgument {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        if let Some(ref amqp_type) = self.amqp_type {
            data.insert("type".to_string(), amqp_type.to_string());
        }
        if let Some(ref default_value) = self.default_value {
            data.insert("default_value".to_string(), default_value.to_string());
        }
        data.insert("name".to_string(),   self.name.clone());
        if let Some(ref domain) = self.domain {
            data.insert("domain".to_string(), domain.clone());
        }

        handlebars.render("argument", &data).expect("Failed to render domain template")
    }
}

#[derive(Debug, Deserialize)]
pub struct AMQPProperty {
    #[serde(rename="type")]
    pub amqp_type: AMQPType,
    pub name:      String,
}

impl Codegen for AMQPProperty {
    fn codegen(&self, handlebars: &Handlebars) -> String {
        let mut data = BTreeMap::new();

        data.insert("type".to_string(), self.amqp_type.to_string());
        data.insert("name".to_string(), self.name.clone());

        handlebars.render("property", &data).expect("Failed to render domain template")
    }
}

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

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1".to_string(), "Copyright 2".to_string()],
            domains:       vec![AMQPDomain("domain1".to_string(), AMQPType::Octet)],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::LongStr),
                                    name:          "argument1".to_string(),
                                    default_value: Some(From::from("value1")),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongStr,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{name}} - {{major_version}}.{{minor_version}}.{{revision}}
{{copyright}}
port {{port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{name}}: {{type}}".to_string(),
            constant: "{{name}}({{class}}) = {{value}}".to_string(),
            klass:    r#"
{{id}} - {{name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{id}} - {{name}}
synchronous: {{synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{name}}({{domain}}): {{type}} = {{default_value}}".to_string(),
            property: "{{name}}: {{type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().codegen(&templates()), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: octet
constant1(class1) = 128

42 - class1
property1: longstr

64 - method1
synchronous: true
argument1(domain1): longstr = "value1"

"#);
    }
}
<|endoftext|>


<commit_before>//! # A strongly restrictive color type.
use std::fmt;
use palette::pixel::Srgb;
use palette::{Rgb, Lch, Lab, Mix};

/// It is guaranteed that `T` can be and will always be only either `u8` or `f32`.
/// It can also be guaranteed that `Display` is not and will never be implemented
/// for `Color<f32>`.
/// It can also be guaranteed that arithmetics are not and will never be implemented
/// for `Color<u8>`.
///
/// ```rust,ignore
/// assert_fail_to_compile!(Color(0.0, 0.0, 0.0).to_string());
/// assert_fail_to_compile!(println!("{}", Color(0.0, 0.0, 0.0)));
/// assert_fail_to_compile!(Color(0, 0, 0) + Color(1, 1, 1));
/// ```
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Color<T>(pub T, pub T, pub T);

/// `Color888` can only do IO (convert to and from strings), and some simple equality tests.
/// Color is sRGB encoded.
pub type Color888 = Color<u8>;
/// `Colorf32` can only do arithmetics and convert to/from `Color888`.
/// Color is Linear RGB encoded.
pub type Colorf32 = Color<f32>;

impl fmt::Display for Color888 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Color(r, g, b) = *self;
        write!(f, "{:02x}{:02x}{:02x}", r, g, b)
    }
}

impl Eq for Color888 {}

impl From<Color888> for Colorf32 {
    /// Convert `Color888` (sRGB) to `Colorf32` (Linear RGB).
    fn from(color: Color888) -> Self {
        let Color(r, g, b) = color;
        let rgb = Rgb::<f32>::from(Srgb::new_u8(r, g, b));
        let Rgb { red: r, green: g, blue: b } = rgb;
        Color(r, g, b)
    }
}

impl Colorf32 {
    /// Convert `Colorf32` (Linear RGB) to `Color888` (sRGB).
    pub fn clamp_to_888(self) -> Color888 {
        /// This is used to "reduce" conversion error, so that
        /// `lossless_conversion` test can pass.
        const DELTA: f32 = 1e-6;

        let Color(r, g, b) = self;
        let srgb = Srgb::from(Rgb::new(r + DELTA, g + DELTA, b + DELTA));
        let Srgb { red: r, green: g, blue: b, .. } = srgb;
        let Color(r, g, b) = Color(r * 255.0, g * 255.0, b * 255.0).clamp_with(0.0, 255.0);
        Color(r as u8, g as u8, b as u8)
    }

    /// Clamp to [`min`, `max`].
    pub fn clamp_with(self, min: f32, max: f32) -> Self {
        let Color(r, g, b) = self;
        let r = r.max(min).min(max);
        let g = g.max(min).min(max);
        let b = b.max(min).min(max);
        Color(r, g, b)
    }

    /// Clamp to [0, 1].
    pub fn clamp(self) -> Self {
        self.clamp_with(0.0, 1.0)
    }

    /// Linear interpolate between colors.
    /// This is done in the CIE LCHab color space.
    pub fn mix(self, other: Self, factor: f32) -> Self {
        let Color(r1, g1, b1) = self;
        let Color(r2, g2, b2) = other;
        let lch1 = Lch::from(Rgb::new(r1, g1, b1));
        let lch2 = Lch::from(Rgb::new(r2, g2, b2));
        let lch = lch1.mix(&lch2, factor);
        let Rgb { red: r, green: g, blue: b } = Rgb::from(lch);
        Color(r, g, b)
    }

    /// Linear interpolate between colors.
    /// This is done in the Linear RGB color space.
    pub fn mix_fast(self, other: Self, factor: f32) -> Self {
        let Color(r1, g1, b1) = self;
        let Color(r2, g2, b2) = other;
        let r = (1.0 - factor) * r1 + factor * r2;
        let g = (1.0 - factor) * g1 + factor * g2;
        let b = (1.0 - factor) * b1 + factor * b2;
        Color(r, g, b)
    }

    /// Modify the perceptual lightness of current color.
    /// A value of `0.0` gives darkest color and `1.0` gives whitest.
    ///
    /// This is done in the CIE Lab color space by setting the L component.
    pub fn set_lightness(self, lightness: f32) -> Self {
        let Color(r, g, b) = self;
        let lab = Lab { l: lightness, ..Rgb::new(r, g, b).into() };
        let Rgb { red: r, green: g, blue: b } = lab.into();
        Color(r, g, b)
    }
}

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

    /// When this test fails, you may want to increase the `DELTA` constant
    /// in `Colorf32::clamp_to_888()`.
    #[test]
    fn lossless_conversion() {
        for i in 0..256 {
            let a = i as u8;
            let color = Color(a, a, a);
            let color2 = Colorf32::from(color).clamp_to_888();
            assert_eq!(color, color2);
        }
    }

    #[test]
    fn clampped_down_conversion() {
        let max = Color(255, 255, 255);
        for i in 256..512 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, max);
        }
    }

    #[test]
    fn clampped_up_conversion() {
        let min = Color(0, 0, 0);
        for i in -256..0 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, min);
        }
    }

    #[test]
    fn display_color888() {
        assert_eq!(Color(0, 0, 0).to_string(), "000000");
        assert_eq!(Color(255, 255, 255).to_string(), "ffffff");
        assert_eq!(Color(1, 254, 10).to_string(), "01fe0a");
    }

    // TODO: automate the checking of this test.
    #[test]
    fn mixing() {
        let c1 = Color(1.0, 0.0, 0.0);
        let c2 = Color(0.0, 0.0, 1.0);
        for i in 0..256 {
            let a = (i as f32) / 255.0;
            let mix1 = c1.mix(c2, a).clamp_to_888();
            let mix2 = c1.mix_fast(c2, a).clamp_to_888();
            println!("{} {}", mix1, mix2);
        }
    }

    #[test]
    fn lightness() {
        let c = Color(0.5, 0.5, 0.5);
        let black = c.set_lightness(0.0).clamp_to_888().to_string();
        let white = c.set_lightness(1.0).clamp_to_888().to_string();
        assert_eq!(black, "000000");
        assert_eq!(white, "ffffff");
    }
}

<commit_msg>color: clean up: trust more about Rust's type inference<commit_after>//! # A strongly restrictive color type.
use std::fmt;
use palette::pixel::Srgb;
use palette::{Rgb, Lch, Lab, Mix};

/// It is guaranteed that `T` can be and will always be only either `u8` or `f32`.
/// It can also be guaranteed that `Display` is not and will never be implemented
/// for `Color<f32>`.
/// It can also be guaranteed that arithmetics are not and will never be implemented
/// for `Color<u8>`.
///
/// ```rust,ignore
/// assert_fail_to_compile!(Color(0.0, 0.0, 0.0).to_string());
/// assert_fail_to_compile!(println!("{}", Color(0.0, 0.0, 0.0)));
/// assert_fail_to_compile!(Color(0, 0, 0) + Color(1, 1, 1));
/// ```
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Color<T>(pub T, pub T, pub T);

/// `Color888` can only do IO (convert to and from strings), and some simple equality tests.
/// Color is sRGB encoded.
pub type Color888 = Color<u8>;
/// `Colorf32` can only do arithmetics and convert to/from `Color888`.
/// Color is Linear RGB encoded.
pub type Colorf32 = Color<f32>;

impl fmt::Display for Color888 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Color(r, g, b) = *self;
        write!(f, "{:02x}{:02x}{:02x}", r, g, b)
    }
}

impl Eq for Color888 {}

impl From<Color888> for Colorf32 {
    /// Convert `Color888` (sRGB) to `Colorf32` (Linear RGB).
    fn from(color: Color888) -> Self {
        let Color(r, g, b) = color;
        let srgb = Srgb::new_u8(r, g, b);
        let Rgb { red: r, green: g, blue: b } = srgb.into();
        Color(r, g, b)
    }
}

impl Colorf32 {
    /// Convert `Colorf32` (Linear RGB) to `Color888` (sRGB).
    pub fn clamp_to_888(self) -> Color888 {
        /// This is used to "reduce" conversion error, so that
        /// `lossless_conversion` test can pass.
        const DELTA: f32 = 1e-6;

        let Color(r, g, b) = self;
        let rgb = Rgb::new(r + DELTA, g + DELTA, b + DELTA);
        let Srgb { red: r, green: g, blue: b, .. } = rgb.into();
        let color = Color(r * 255.0, g * 255.0, b * 255.0);
        let Color(r, g, b) = color.clamp_with(0.0, 255.0);
        Color(r as u8, g as u8, b as u8)
    }

    /// Clamp to [`min`, `max`].
    pub fn clamp_with(self, min: f32, max: f32) -> Self {
        let Color(r, g, b) = self;
        let r = r.max(min).min(max);
        let g = g.max(min).min(max);
        let b = b.max(min).min(max);
        Color(r, g, b)
    }

    /// Clamp to [0, 1].
    pub fn clamp(self) -> Self {
        self.clamp_with(0.0, 1.0)
    }

    /// Linear interpolate between colors.
    /// This is done in the CIE LCHab color space.
    pub fn mix(self, other: Self, factor: f32) -> Self {
        let Color(r1, g1, b1) = self;
        let Color(r2, g2, b2) = other;
        let lch1 = Lch::from(Rgb::new(r1, g1, b1));
        let lch2 = Lch::from(Rgb::new(r2, g2, b2));
        let lch = lch1.mix(&lch2, factor);
        let Rgb { red: r, green: g, blue: b } = lch.into();
        Color(r, g, b)
    }

    /// Linear interpolate between colors.
    /// This is done in the Linear RGB color space.
    pub fn mix_fast(self, other: Self, factor: f32) -> Self {
        let Color(r1, g1, b1) = self;
        let Color(r2, g2, b2) = other;
        let r = (1.0 - factor) * r1 + factor * r2;
        let g = (1.0 - factor) * g1 + factor * g2;
        let b = (1.0 - factor) * b1 + factor * b2;
        Color(r, g, b)
    }

    /// Modify the perceptual lightness of current color.
    /// A value of `0.0` gives darkest color and `1.0` gives whitest.
    ///
    /// This is done in the CIE Lab color space by setting the L component.
    pub fn set_lightness(self, lightness: f32) -> Self {
        let Color(r, g, b) = self;
        let rgb = Rgb::new(r, g, b);
        let lab = Lab { l: lightness, ..rgb.into() };
        let Rgb { red: r, green: g, blue: b } = lab.into();
        Color(r, g, b)
    }
}

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

    /// When this test fails, you may want to increase the `DELTA` constant
    /// in `Colorf32::clamp_to_888()`.
    #[test]
    fn lossless_conversion() {
        for i in 0..256 {
            let a = i as u8;
            let color = Color(a, a, a);
            let color2 = Colorf32::from(color).clamp_to_888();
            assert_eq!(color, color2);
        }
    }

    #[test]
    fn clampped_down_conversion() {
        let max = Color(255, 255, 255);
        for i in 256..512 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, max);
        }
    }

    #[test]
    fn clampped_up_conversion() {
        let min = Color(0, 0, 0);
        for i in -256..0 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, min);
        }
    }

    #[test]
    fn display_color888() {
        assert_eq!(Color(0, 0, 0).to_string(), "000000");
        assert_eq!(Color(255, 255, 255).to_string(), "ffffff");
        assert_eq!(Color(1, 254, 10).to_string(), "01fe0a");
    }

    // TODO: automate the checking of this test.
    #[test]
    fn mixing() {
        let c1 = Color(1.0, 0.0, 0.0);
        let c2 = Color(0.0, 0.0, 1.0);
        for i in 0..256 {
            let a = (i as f32) / 255.0;
            let mix1 = c1.mix(c2, a).clamp_to_888();
            let mix2 = c1.mix_fast(c2, a).clamp_to_888();
            println!("{} {}", mix1, mix2);
        }
    }

    #[test]
    fn lightness() {
        let c = Color(0.5, 0.5, 0.5);
        let black = c.set_lightness(0.0).clamp_to_888().to_string();
        let white = c.set_lightness(1.0).clamp_to_888().to_string();
        assert_eq!(black, "000000");
        assert_eq!(white, "ffffff");
    }
}

<|endoftext|>


<commit_before>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tls_api;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use futures_cpupool;

use exec::CpuPoolOption;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;
use service_paths::ServicePaths;

use server_conf::*;

pub use server_tls::ServerTlsOption;

struct LoopToServer {
    shutdown: ShutdownSignal,
    local_addr: SocketAddr,
}

pub struct ServerBuilder<A : tls_api::TlsAcceptor = tls_api_stub::TlsAcceptor> {
    pub conf: ServerConf,
    pub cpu_pool: CpuPoolOption,
    pub tls: ServerTlsOption<A>,
    pub addr: Option<SocketAddr>,
    pub service: ServicePaths,
}

impl ServerBuilder<tls_api_stub::TlsAcceptor> {
    /// New server builder with defaults.
    ///
    /// Port must be set, other properties are optional.
    pub fn new_plain() -> ServerBuilder<tls_api_stub::TlsAcceptor> {
        ServerBuilder::new()
    }
}

impl<A : tls_api::TlsAcceptor> ServerBuilder<A> {
    /// New server builder with defaults.
    ///
    /// To call this function `ServerBuilder` must be parameterized with TLS acceptor.
    /// If TLS is not needed, `ServerBuilder::new_plain` function can be used.
    ///
    /// Port must be set, other properties are optional.
    pub fn new() -> ServerBuilder<A> {
        ServerBuilder {
            conf: ServerConf::new(),
            cpu_pool: CpuPoolOption::SingleThread,
            tls: ServerTlsOption::Plain,
            addr: None,
            service: ServicePaths::new(),
        }
    }

    /// Create a CPU pool, and use it in HTTP server
    pub fn set_cpu_pool_threads(&mut self, threads: usize) {
        let cpu_pool = futures_cpupool::Builder::new()
            .pool_size(threads)
            .name_prefix("httpbis-server-")
            .create();
        self.cpu_pool = CpuPoolOption::CpuPool(cpu_pool);
    }

    pub fn set_tls(&mut self, acceptor: A) {
        self.tls = ServerTlsOption::Tls(Arc::new(acceptor));
    }

    /// Set port server listens on.
    /// Can be zero to bind on any available port,
    /// which can be later obtained by `Server::local_addr`.
    pub fn set_port(&mut self, port: u16) {
        self.set_addr(("::", port)).expect("set_addr");
    }

    /// Set port server listens on.
    pub fn set_addr<S : ToSocketAddrs>(&mut self, addr: S) -> Result<()> {
        let addrs: Vec<_> = addr.to_socket_addrs()?.collect();
        if addrs.is_empty() {
            return Err(Error::Other("addr is resolved to empty list"));
        } else if addrs.len() > 1 {
            return Err(Error::Other("addr is resolved to more than one addr"));
        }
        self.addr = Some(addrs.into_iter().next().unwrap());
        Ok(())
    }

    pub fn build(self) -> Result<Server> {
        let addr = self.addr.expect("listen addr is unset");

        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();
        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let join_handle = thread::Builder::new()
            .name(self.conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    self.tls,
                    self.cpu_pool,
                    self.conf,
                    self.service,
                    get_from_loop_tx,
                    alive_tx);
            })?;

        let loop_to_server = get_from_loop_rx.recv()
            .map_err(|_| Error::Other("failed to recv from event loop"))?;

        Ok(Server {
            state: state,
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    loop_to_server: LoopToServer,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    handle: &reactor::Handle,
    conf: &ServerConf)
        -> io::Result<TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    let listener = listener.listen(backlog)?;
    TcpListener::from_listener(listener, addr, handle)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    exec: CpuPoolOption,
    conf: ServerConf,
    service: S,
    send_to_back: mpsc::Sender<LoopToServer>,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let (shutdown_signal, shutdown_future) = shutdown_signal();

    let listen = listener(&listen_addr, &lp.handle(), &conf).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { shutdown: shutdown_signal, local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(
                &loop_handle, socket, tls, exec.clone(), conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.loop_to_server.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<commit_msg>Initialize shutdown signal from builder, not from thread<commit_after>use std::thread;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
use std::io;

use tls_api;

use tokio_core::reactor;
use tokio_core::net::TcpListener;

use futures::future;
use futures::future::Future;
use futures::future::join_all;
use futures::stream;
use futures::stream::Stream;

use futures_cpupool;

use exec::CpuPoolOption;

use error::Error;
use result::Result;

use solicit_async::*;

use futures_misc::*;

use net2;

use tls_api::TlsAcceptor;
use tls_api_stub;

use super::server_conn::*;
use super::common::*;

use service::Service;
use service_paths::ServicePaths;

use server_conf::*;

pub use server_tls::ServerTlsOption;

struct LoopToServer {
    local_addr: SocketAddr,
}

pub struct ServerBuilder<A : tls_api::TlsAcceptor = tls_api_stub::TlsAcceptor> {
    pub conf: ServerConf,
    pub cpu_pool: CpuPoolOption,
    pub tls: ServerTlsOption<A>,
    pub addr: Option<SocketAddr>,
    pub service: ServicePaths,
}

impl ServerBuilder<tls_api_stub::TlsAcceptor> {
    /// New server builder with defaults.
    ///
    /// Port must be set, other properties are optional.
    pub fn new_plain() -> ServerBuilder<tls_api_stub::TlsAcceptor> {
        ServerBuilder::new()
    }
}

impl<A : tls_api::TlsAcceptor> ServerBuilder<A> {
    /// New server builder with defaults.
    ///
    /// To call this function `ServerBuilder` must be parameterized with TLS acceptor.
    /// If TLS is not needed, `ServerBuilder::new_plain` function can be used.
    ///
    /// Port must be set, other properties are optional.
    pub fn new() -> ServerBuilder<A> {
        ServerBuilder {
            conf: ServerConf::new(),
            cpu_pool: CpuPoolOption::SingleThread,
            tls: ServerTlsOption::Plain,
            addr: None,
            service: ServicePaths::new(),
        }
    }

    /// Create a CPU pool, and use it in HTTP server
    pub fn set_cpu_pool_threads(&mut self, threads: usize) {
        let cpu_pool = futures_cpupool::Builder::new()
            .pool_size(threads)
            .name_prefix("httpbis-server-")
            .create();
        self.cpu_pool = CpuPoolOption::CpuPool(cpu_pool);
    }

    pub fn set_tls(&mut self, acceptor: A) {
        self.tls = ServerTlsOption::Tls(Arc::new(acceptor));
    }

    /// Set port server listens on.
    /// Can be zero to bind on any available port,
    /// which can be later obtained by `Server::local_addr`.
    pub fn set_port(&mut self, port: u16) {
        self.set_addr(("::", port)).expect("set_addr");
    }

    /// Set port server listens on.
    pub fn set_addr<S : ToSocketAddrs>(&mut self, addr: S) -> Result<()> {
        let addrs: Vec<_> = addr.to_socket_addrs()?.collect();
        if addrs.is_empty() {
            return Err(Error::Other("addr is resolved to empty list"));
        } else if addrs.len() > 1 {
            return Err(Error::Other("addr is resolved to more than one addr"));
        }
        self.addr = Some(addrs.into_iter().next().unwrap());
        Ok(())
    }

    pub fn build(self) -> Result<Server> {
        let addr = self.addr.expect("listen addr is unset");

        let listen_addr = addr.to_socket_addrs()?.next().unwrap();

        let (get_from_loop_tx, get_from_loop_rx) = mpsc::channel();
        let (alive_tx, alive_rx) = mpsc::channel();

        let state: Arc<Mutex<ServerState>> = Default::default();

        let state_copy = state.clone();

        let (shutdown_signal, shutdown_future) = shutdown_signal();

        let join_handle = thread::Builder::new()
            .name(self.conf.thread_name.clone().unwrap_or_else(|| "http2-server-loop".to_owned()).to_string())
            .spawn(move || {
                run_server_event_loop(
                    listen_addr,
                    state_copy,
                    self.tls,
                    self.cpu_pool,
                    shutdown_future,
                    self.conf,
                    self.service,
                    get_from_loop_tx,
                    alive_tx);
            })?;

        let loop_to_server = get_from_loop_rx.recv()
            .map_err(|_| Error::Other("failed to recv from event loop"))?;

        Ok(Server {
            state: state,
            shutdown: shutdown_signal,
            loop_to_server: loop_to_server,
            thread_join_handle: Some(join_handle),
            alive_rx: alive_rx,
        })
    }
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    loop_to_server: LoopToServer,
    shutdown: ShutdownSignal,
    alive_rx: mpsc::Receiver<()>,
    thread_join_handle: Option<thread::JoinHandle<()>>,
}

#[derive(Default)]
struct ServerState {
    last_conn_id: u64,
    conns: HashMap<u64, ServerConnection>,
}

impl ServerState {
    fn snapshot(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let futures: Vec<_> = self.conns.iter()
            .map(|(&id, conn)| conn.dump_state().map(move |state| (id, state)))
            .collect();

        Box::new(join_all(futures)
            .map(|states| ServerStateSnapshot {
                conns: states.into_iter().collect(),
            }))
    }
}

pub struct ServerStateSnapshot {
    pub conns: HashMap<u64, ConnectionStateSnapshot>,
}

impl ServerStateSnapshot {
    pub fn single_conn(&self) -> (u64, &ConnectionStateSnapshot) {
        let mut iter = self.conns.iter();
        let (&id, conn) = iter.next().expect("no conns");
        assert!(iter.next().is_none(), "more than one conn");
        (id, conn)
    }
}

#[cfg(unix)]
fn configure_tcp(tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    use net2::unix::UnixTcpBuilderExt;
    if let Some(reuse_port) = conf.reuse_port {
        tcp.reuse_port(reuse_port)?;
    }
    Ok(())
}

#[cfg(windows)]
fn configure_tcp(_tcp: &net2::TcpBuilder, conf: &ServerConf) -> io::Result<()> {
    Ok(())
}

fn listener(
    addr: &SocketAddr,
    handle: &reactor::Handle,
    conf: &ServerConf)
        -> io::Result<TcpListener>
{
    let listener = match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
    };
    configure_tcp(&listener, conf)?;
    listener.reuse_address(true)?;
    listener.bind(addr)?;
    let backlog = conf.backlog.unwrap_or(1024);
    let listener = listener.listen(backlog)?;
    TcpListener::from_listener(listener, addr, handle)
}

fn run_server_event_loop<S, A>(
    listen_addr: SocketAddr,
    state: Arc<Mutex<ServerState>>,
    tls: ServerTlsOption<A>,
    exec: CpuPoolOption,
    shutdown_future: ShutdownFuture,
    conf: ServerConf,
    service: S,
    send_to_back: mpsc::Sender<LoopToServer>,
    _alive_tx: mpsc::Sender<()>)
        where S : Service, A : TlsAcceptor,
{
    let service = Arc::new(service);

    let mut lp = reactor::Core::new().expect("http2server");

    let listen = listener(&listen_addr, &lp.handle(), &conf).unwrap();

    let stuff = stream::repeat((lp.handle(), service, state, tls, conf));

    let local_addr = listen.local_addr().unwrap();
    send_to_back
        .send(LoopToServer { local_addr: local_addr })
        .expect("send back");

    let loop_run = listen.incoming().map_err(Error::from).zip(stuff)
        .for_each(move |((socket, peer_addr), (loop_handle, service, state, tls, conf))| {
            info!("accepted connection from {}", peer_addr);

            let no_delay = conf.no_delay.unwrap_or(true);
            socket.set_nodelay(no_delay).expect("failed to set TCP_NODELAY");

            let (conn, future) = ServerConnection::new(
                &loop_handle, socket, tls, exec.clone(), conf, service);

            let conn_id = {
                let mut g = state.lock().expect("lock");
                g.last_conn_id += 1;
                let conn_id = g.last_conn_id;
                let prev = g.conns.insert(conn_id, conn);
                assert!(prev.is_none());
                conn_id
            };

            loop_handle.spawn(future
                .then(move |r| {
                    let mut g = state.lock().expect("lock");
                    let removed = g.conns.remove(&conn_id);
                    assert!(removed.is_some());
                    r
                })
                .map_err(|e| { warn!("connection end: {:?}", e); () }));
            Ok(())
        });

    let shutdown_future = shutdown_future
        .then(move |_| {
            // Must complete with error,
            // so `join` with this future cancels another future.
            future::failed::<(), _>(Error::Shutdown)
        });

    // Wait for either completion of connection (i. e. error)
    // or shutdown signal.
    let done = loop_run.join(shutdown_future);

    // TODO: do not ignore error
    lp.run(done).ok();
}

impl Server {
    pub fn local_addr(&self) -> &SocketAddr {
        &self.loop_to_server.local_addr
    }

    pub fn is_alive(&self) -> bool {
        self.alive_rx.try_recv() != Err(mpsc::TryRecvError::Disconnected)
    }

    // for tests
    pub fn dump_state(&self) -> HttpFutureSend<ServerStateSnapshot> {
        let g = self.state.lock().expect("lock");
        g.snapshot()
    }
}

// We shutdown the server in the destructor.
impl Drop for Server {
    fn drop(&mut self) {
        self.shutdown.shutdown();

        // do not ignore errors of take
        // ignore errors of join, it means that server event loop crashed
        drop(self.thread_join_handle.take().unwrap().join());
    }
}

<|endoftext|>


<commit_before>extern crate piston;
extern crate string_telephone;
extern crate collections;

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use std::rand;
use std::rand::{Rng, TaskRng};
use std::time::duration::Duration;

pub mod packet;
pub mod player;

fn update_tagged_player_validity(rng: &mut TaskRng, players: &Vec<(SocketAddr, player::Player)>, current_tagged: u16) -> u16 {
    if players.len() == 0 {
        current_tagged
    } else {
        let tagged_count = players.iter().filter(|&&(_, player)| &player.id == &current_tagged).count();
        if tagged_count == 0 {
            let index = rng.gen::<uint>() % players.len();
            let (_, player) = players[index];
            player.id
        } else {
            current_tagged
        }
    }
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: Duration::seconds(10),
        packet_deserializer: packet::deserializer,
        packet_serializer: packet::serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    let mut players:Vec<(SocketAddr, player::Player)> = vec![];
    let mut rng = rand::task_rng();
    let mut player_counter = 0;

    let mut next_broadcast = 0f64;
    let mut next_think = 0f64;
    let mut clock = 0f64;
    //let clock_rate = 0.0015;
    let broadcast_rate = 1.0 / 20.0;
    let mut tagged_player = 0;

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        match e {
            piston::Update(update_args) => {
                clock += update_args.dt;
                loop {
                    match server.poll() {
                        Some((Command(PacketConnect), addr_from)) => {
                            println!("{} connected", addr_from);
                            //TODO: Check this player doesn't already exist
                            players.push((addr_from, player::Player::new(player_counter, (rng.gen::<u32>() % 800) as i32, (rng.gen::<u32>() % 600) as i32)));
                            tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                            player_counter += 1;
                        },
                        Some((Command(PacketDisconnect), addr_from)) => {
                            println!("{} disconnected", addr_from);
                            players = players.into_iter().filter(|&(controller, _)| &controller != &addr_from).collect();
                            tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                        },
                        Some((UserPacket(packet::MovePacket(up, down, left, right)), addr_from)) => {
                            for &(controller, ref mut player) in players.iter_mut() {
                                if controller == addr_from {
                                    player.key_up = up;
                                    player.key_down = down;
                                    player.key_left = left;
                                    player.key_right = right;
                                    break;
                                }
                            };
                        },
                        Some(_) => (),
                        None => break
                    }
                };

                //Update the game world
                if clock >= next_think {
                    next_think = clock + 0.015;
                    //FIXME: There must be a better way of doing comparisons
                    let comparator_players = players.clone();
                    let mut pass_on_tag = None;

                    for &(_, ref mut player) in players.iter_mut() {
                        if !player.is_frozen(clock) {
                            let mut collided = player.id;
                            for &(_, ref other_player) in comparator_players.iter() {
                                if player.id != other_player.id {
                                    if player.will_collide(other_player) {
                                        collided = other_player.id;
                                        break;
                                    }
                                }
                            }
                            if collided == player.id {
                                player.think()
                            } else if player.id == tagged_player {
                                pass_on_tag = Some(collided)
                            }
                        }
                    };

                    match pass_on_tag {
                        Some(id) => {
                            for &(_, ref mut player) in players.iter_mut() {
                                if player.id == id {
                                    player.freeze(clock);
                                    break;
                                }
                            };
                            tagged_player = id;
                        },
                        None => ()
                    }
                }

                let culled = server.cull();
                if culled.len() > 0 {
                    println!("{} timed out", culled);
                    players = players.into_iter().filter(|&(player, _)| culled.contains(&player) == false).collect();
                    tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                }

                if clock >= next_broadcast {
                    next_broadcast = clock + broadcast_rate;
                    let serialized_state: Vec<player::Player> = players.iter().map(|&(_, data)| data).collect();
                    for &(ref user, ref data) in players.iter() {
                        server.send_to(&packet::FullServerState(data.id, tagged_player, serialized_state.clone()), user);
                    }
                }
            },
            _ => ()
        }
    }
}
<commit_msg>Don't allow duplicate connect packets to blow us up<commit_after>extern crate piston;
extern crate string_telephone;
extern crate collections;

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use std::rand;
use std::rand::{Rng, TaskRng};
use std::time::duration::Duration;

pub mod packet;
pub mod player;

fn update_tagged_player_validity(rng: &mut TaskRng, players: &Vec<(SocketAddr, player::Player)>, current_tagged: u16) -> u16 {
    if players.len() == 0 {
        current_tagged
    } else {
        let tagged_count = players.iter().filter(|&&(_, player)| &player.id == &current_tagged).count();
        if tagged_count == 0 {
            let index = rng.gen::<uint>() % players.len();
            let (_, player) = players[index];
            player.id
        } else {
            current_tagged
        }
    }
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: Duration::seconds(10),
        packet_deserializer: packet::deserializer,
        packet_serializer: packet::serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    let mut players:Vec<(SocketAddr, player::Player)> = vec![];
    let mut rng = rand::task_rng();
    let mut player_counter = 0;

    let mut next_broadcast = 0f64;
    let mut next_think = 0f64;
    let mut clock = 0f64;
    //let clock_rate = 0.0015;
    let broadcast_rate = 1.0 / 20.0;
    let mut tagged_player = 0;

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        match e {
            piston::Update(update_args) => {
                clock += update_args.dt;
                loop {
                    match server.poll() {
                        Some((Command(PacketConnect), addr_from)) => {
                            match players.iter().find(|&&(socket, _)|{ socket == addr_from}) {
                                Some(_) => {
                                    println!("{} tried to connect a second time", addr_from);
                                },
                                None => {
                                    println!("{} connected", addr_from);
                                    players.push((addr_from, player::Player::new(player_counter, (rng.gen::<u32>() % 800) as i32, (rng.gen::<u32>() % 600) as i32)));
                                    tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                                    player_counter += 1;
                                }
                            }
                        },
                        Some((Command(PacketDisconnect), addr_from)) => {
                            println!("{} disconnected", addr_from);
                            players = players.into_iter().filter(|&(controller, _)| &controller != &addr_from).collect();
                            tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                        },
                        Some((UserPacket(packet::MovePacket(up, down, left, right)), addr_from)) => {
                            for &(controller, ref mut player) in players.iter_mut() {
                                if controller == addr_from {
                                    player.key_up = up;
                                    player.key_down = down;
                                    player.key_left = left;
                                    player.key_right = right;
                                    break;
                                }
                            };
                        },
                        Some(_) => (),
                        None => break
                    }
                };

                //Update the game world
                if clock >= next_think {
                    next_think = clock + 0.015;
                    //FIXME: There must be a better way of doing comparisons
                    let comparator_players = players.clone();
                    let mut pass_on_tag = None;

                    for &(_, ref mut player) in players.iter_mut() {
                        if !player.is_frozen(clock) {
                            let mut collided = player.id;
                            for &(_, ref other_player) in comparator_players.iter() {
                                if player.id != other_player.id {
                                    if player.will_collide(other_player) {
                                        collided = other_player.id;
                                        break;
                                    }
                                }
                            }
                            if collided == player.id {
                                player.think()
                            } else if player.id == tagged_player {
                                pass_on_tag = Some(collided)
                            }
                        }
                    };

                    match pass_on_tag {
                        Some(id) => {
                            for &(_, ref mut player) in players.iter_mut() {
                                if player.id == id {
                                    player.freeze(clock);
                                    break;
                                }
                            };
                            tagged_player = id;
                        },
                        None => ()
                    }
                }

                let culled = server.cull();
                if culled.len() > 0 {
                    println!("{} timed out", culled);
                    players = players.into_iter().filter(|&(player, _)| culled.contains(&player) == false).collect();
                    tagged_player = update_tagged_player_validity(&mut rng, &players, tagged_player);
                }

                if clock >= next_broadcast {
                    next_broadcast = clock + broadcast_rate;
                    let serialized_state: Vec<player::Player> = players.iter().map(|&(_, data)| data).collect();
                    for &(ref user, ref data) in players.iter() {
                        server.send_to(&packet::FullServerState(data.id, tagged_player, serialized_state.clone()), user);
                    }
                }
            },
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>virtio: net: deduplicate handling deferred frames<commit_after><|endoftext|>


<commit_before>use parser::Identifier;
use memory::{MemoryBlock};

use operations::{Operation, expression};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            let unit_type = scope.primitives().unit();
            args.into_iter().skip(1).map(|arg| expression::call(
                scope,
                Identifier::from("std::fmt::Display::print"),
                vec![arg],
                unit_type,
                MemoryBlock::default()
            )).collect::<Result<Vec<_>, _>>().map(|op_vecs| {
                op_vecs.into_iter().flat_map(|ops| ops).collect()
            })
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, _| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                unit_type,
                MemoryBlock::default()
            )?;

            // Write a newline using a temporary cell
            let u8_type = scope.primitives().u8();
            let mem = scope.allocate(u8_type);
            ops.push(Operation::TempAllocate {
                temp: mem,
                body: vec![
                    Operation::Increment {
                        target: mem.position(),
                        amount: b'\n',
                    },
                ],
            });

            Ok(ops)
        }
    );

    stdout_type
}
<commit_msg>Bug in stdout.println where \n was not actually being written<commit_after>use parser::Identifier;
use memory::{MemoryBlock};

use operations::{Operation, expression};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            let unit_type = scope.primitives().unit();
            args.into_iter().skip(1).map(|arg| expression::call(
                scope,
                Identifier::from("std::fmt::Display::print"),
                vec![arg],
                unit_type,
                MemoryBlock::default()
            )).collect::<Result<Vec<_>, _>>().map(|op_vecs| {
                op_vecs.into_iter().flat_map(|ops| ops).collect()
            })
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, _| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                unit_type,
                MemoryBlock::default()
            )?;

            // Write a newline using a temporary cell
            let u8_type = scope.primitives().u8();
            let mem = scope.allocate(u8_type);
            ops.push(Operation::TempAllocate {
                temp: mem,
                body: vec![
                    Operation::Increment {
                        target: mem.position(),
                        amount: b'\n',
                    },
                    Operation::Write {
                        target: mem,
                    },
                ],
            });

            Ok(ops)
        }
    );

    stdout_type
}
<|endoftext|>


<commit_before>extern crate boxcars;
extern crate failure;
extern crate rayon;
extern crate serde_json;
extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use failure::{Error, ResultExt};
use structopt::StructOpt;
use std::fs::{File, OpenOptions};
use std::io::{self, BufWriter};
use std::io::prelude::*;
use rayon::prelude::*;
use boxcars::{CrcCheck, NetworkParse, ParserBuilder};

#[derive(StructOpt, Debug, Clone, PartialEq)]
#[structopt(name = "rrrocket", about = "Parses Rocket League replay files and writes a .json file with the decoded information")]
struct Opt {
    #[structopt(short = "c", long = "crc-check", help = "validate replay is not corrupt")]
    crc: bool,

    #[structopt(short = "n", long = "network-parse", help = "parses the network data of a replay")]
    body: bool,

    #[structopt(help = "Rocket League replay files")] input: Vec<String>,
}

fn read_file(input: &str) -> Result<Vec<u8>, Error> {
    let mut f = File::open(input)
        .with_context(|e| format!("Could not open rocket league file: {} -- {}", input, e))?;
    let mut buffer = vec![];
    f.read_to_end(&mut buffer)
        .with_context(|e| format!("Could not read rocket league file: {} -- {}", input, e))?;
    Ok(buffer)
}

fn run() -> Result<(), Error> {
    let opt = Opt::from_args();
    let res: Result<Vec<()>, Error> = opt.input
        .par_iter()
        .map(|file| {
            let outfile = format!("{}.json", file);
            let fout = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .open(&outfile)
                .with_context(|e| {
                    format!(
                        "Could not open json output file: {} with error: {}",
                        outfile, e
                    )
                })?;
            let mut writer = BufWriter::new(fout);
            let data = read_file(file)?;
            let replay = ParserBuilder::new(&data[..])
                .with_crc_check(if opt.crc {
                    CrcCheck::Always
                } else {
                    CrcCheck::OnError
                })
                .with_network_parse(if opt.body {
                    NetworkParse::Always
                } else {
                    NetworkParse::Never
                })
                .parse()
                .with_context(|e| format!("Could not parse: {} with error: {}", file, e))?;
            serde_json::to_writer(&mut writer, &replay).with_context(|e| {
                format!("Could not serialize replay {} to {}: {}", file, outfile, e)
            })?;
            Ok(())
        })
        .collect();
    res?;
    Ok(())
}

fn main() {
    if let Err(ref e) = run() {
        let mut stderr = io::stderr();
        for fail in e.causes() {
            let _ = writeln!(stderr, "{}", fail);
        }

        ::std::process::exit(1);
    }
}
<commit_msg>Update rrrocket help text<commit_after>extern crate boxcars;
extern crate failure;
extern crate rayon;
extern crate serde_json;
extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use failure::{Error, ResultExt};
use structopt::StructOpt;
use std::fs::{File, OpenOptions};
use std::io::{self, BufWriter};
use std::io::prelude::*;
use rayon::prelude::*;
use boxcars::{CrcCheck, NetworkParse, ParserBuilder};

#[derive(StructOpt, Debug, Clone, PartialEq)]
#[structopt(name = "rrrocket", about = "Parses Rocket League replay files and writes a .json file with the decoded information")]
struct Opt {
    #[structopt(short = "c", long = "crc-check", help = "forces a crc check for corruption even when replay was successfully parsed")]
    crc: bool,

    #[structopt(short = "n", long = "network-parse", help = "parses the network data of a replay instead of skipping it")]
    body: bool,

    #[structopt(help = "Rocket League replay files")] input: Vec<String>,
}

fn read_file(input: &str) -> Result<Vec<u8>, Error> {
    let mut f = File::open(input)
        .with_context(|e| format!("Could not open rocket league file: {} -- {}", input, e))?;
    let mut buffer = vec![];
    f.read_to_end(&mut buffer)
        .with_context(|e| format!("Could not read rocket league file: {} -- {}", input, e))?;
    Ok(buffer)
}

fn run() -> Result<(), Error> {
    let opt = Opt::from_args();
    let res: Result<Vec<()>, Error> = opt.input
        .par_iter()
        .map(|file| {
            let outfile = format!("{}.json", file);
            let fout = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .open(&outfile)
                .with_context(|e| {
                    format!(
                        "Could not open json output file: {} with error: {}",
                        outfile, e
                    )
                })?;
            let mut writer = BufWriter::new(fout);
            let data = read_file(file)?;
            let replay = ParserBuilder::new(&data[..])
                .with_crc_check(if opt.crc {
                    CrcCheck::Always
                } else {
                    CrcCheck::OnError
                })
                .with_network_parse(if opt.body {
                    NetworkParse::Always
                } else {
                    NetworkParse::Never
                })
                .parse()
                .with_context(|e| format!("Could not parse: {} with error: {}", file, e))?;
            serde_json::to_writer(&mut writer, &replay).with_context(|e| {
                format!("Could not serialize replay {} to {}: {}", file, outfile, e)
            })?;
            Ok(())
        })
        .collect();
    res?;
    Ok(())
}

fn main() {
    if let Err(ref e) = run() {
        let mut stderr = io::stderr();
        for fail in e.causes() {
            let _ = writeln!(stderr, "{}", fail);
        }

        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>//! SCCS-style delta weave stores.

use crate::{
    node,
    store::{Store, StoreTags, StoreVersion, StoreWriter, TempCleaner, TempFile, TempLoader, Version},
    Result, SureNode,
};
use crossbeam::{
    channel::{bounded, Receiver, Sender},
};
use failure::format_err;
use log::warn;
use std::{
    env,
    fs::{self, File},
    io::{self, BufRead, BufReader, BufWriter, Write},
    path::{Path, PathBuf},
    thread::{self, JoinHandle},
};
use weave::{self, DeltaWriter, NamingConvention, NewWeave, NullSink, Parser, SimpleNaming, Sink};

pub struct WeaveStore {
    naming: SimpleNaming,
}

impl WeaveStore {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, compressed: bool) -> WeaveStore {
        WeaveStore {
            naming: SimpleNaming::new(path, base, "dat", compressed),
        }
    }
}

impl Store for WeaveStore {
    fn get_versions(&self) -> Result<Vec<StoreVersion>> {
        let header = Parser::new(&self.naming, NullSink, 1)?.into_header();
        let mut versions: Vec<_> = header
            .deltas
            .iter()
            .map(|v| StoreVersion {
                name: v.name.clone(),
                time: v.time,
                version: Version::Tagged(v.number.to_string()),
            }).collect();
        versions.reverse();
        Ok(versions)
    }

    fn load_iter(&self, version: Version) -> Result<Box<dyn Iterator<Item = Result<SureNode>>>> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        let child_naming = self.naming.clone();
        let (sender, receiver) = bounded(32);
        let child = thread::spawn(move || {
            if let Err(err) = read_parse(&child_naming, last, sender.clone()) {
                // Attempt to send the last error over.
                if let Err(inner) = sender.send(Some(Err(err))) {
                    warn!("Error sending error on channel {:?}", inner);
                }
            }
        });

        fixed(&receiver, b"asure-2.0")?;
        fixed(&receiver, b"-----")?;

        Ok(Box::new(WeaveIter {
            _child: child,
            receiver: receiver,
        }))
    }

    fn make_temp(&self) -> Result<Box<dyn TempFile + '_>> {
        // TODO: Fixup naming to allow uncompressed writes.
        let (path, file) = self.naming.temp_file()?;
        let cpath = path.clone();
        Ok(Box::new(WeaveTemp {
            parent: self,
            path: path,
            file: BufWriter::new(file),
            cleaner: FileClean(cpath),
        }))
    }

    fn make_new(&self, tags: &StoreTags) -> Result<Box<dyn StoreWriter + '_>> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let wv = DeltaWriter::new(&self.naming, itags, base)?;
                Ok(Box::new(NewWeaveDelta { weave: wv }))
            }
            Err(_) => {
                // Create a new weave file.
                let wv = NewWeave::new(&self.naming, itags)?;
                Ok(Box::new(NewWeaveWriter { weave: wv }))
            }
        }
    }
}

struct WeaveTemp<'a> {
    parent: &'a WeaveStore,
    path: PathBuf,
    file: BufWriter<File>,
    cleaner: FileClean,
}

impl<'a> TempFile<'a> for WeaveTemp<'a> {
    fn into_loader(self: Box<Self>) -> Result<Box<dyn TempLoader + 'a>> {
        drop(self.file);
        Ok(Box::new(WeaveTempLoader {
            _parent: self.parent,
            path: self.path,
            cleaner: self.cleaner,
        }))
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

impl<'a> Write for WeaveTemp<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

pub struct WeaveTempLoader<'a> {
    _parent: &'a WeaveStore,
    path: PathBuf,
    cleaner: FileClean,
}

impl<'a> TempLoader for WeaveTempLoader<'a> {
    fn new_loader(&self) -> Result<Box<dyn BufRead>> {
        let read = BufReader::new(File::open(&self.path)?);
        Ok(Box::new(read))
    }

    fn path_ref(&self) -> &Path {
        &self.path
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

pub struct NewWeaveWriter<'a> {
    weave: NewWeave<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveWriter<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct NewWeaveDelta<'a> {
    weave: DeltaWriter<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveDelta<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveDelta<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct WeaveIter {
    // This field doesn't need to be referenced, just held onto, the Drop
    // implementation for it is sufficient cleanup.
    _child: JoinHandle<()>,
    receiver: Receiver<Option<Result<String>>>,
}

impl Iterator for WeaveIter {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        let line = match self.receiver.recv() {
            Ok(None) => return None,
            Ok(Some(Err(e))) => return Some(Err(e)),
            Ok(Some(Ok(line))) => line,
            Err(e) => return Some(Err(e.into())),
        };
        let line = line.as_bytes();

        match line[0] {
            b'd' => {
                let (dname, datts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::Enter{name: dname, atts: datts}))
            }
            b'f' => {
                let (fname, fatts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::File{name: fname, atts: fatts}))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => Some(Ok(SureNode::Leave)),
            ch => Some(Err(format_err!("Invalid surefile line start: {:?}", ch)))
        }
    }
}

// Parse a given delta, emitting the lines to the given channel.  Finishes with Ok(()), or an error
// if something goes wrong.
fn read_parse(
    naming: &dyn NamingConvention,
    delta: usize,
    chan: Sender<Option<Result<String>>>,
) -> Result<()> {
    let mut parser = Parser::new(naming, ReadSync { chan: chan }, delta)?;
    parser.parse_to(0)?;
    let sink = parser.get_sink();
    match sink.borrow().chan.send(None) {
        Ok(()) => (),
        Err(e) => return Err(format_err!("chan send error: {:?}", e)),
    }
    Ok(())
}

/// Try reading a specific line from the given channel.  Returns Err if the
/// line didn't match, or something went wrong with the read.
fn fixed(recv: &Receiver<Option<Result<String>>>, expect: &[u8]) -> Result<()> {
    match recv.recv() {
        Ok(Some(Ok(line))) => {
            if line.as_bytes() == expect {
                Ok(())
            } else {
                Err(format_err!("Unexpect line from channel: {:?} expect {:?}", line, expect))
            }
        }
        Ok(Some(Err(e))) => Err(format_err!("Error reading suredata: {:?}", e)),
        Ok(None) => Err(format_err!("Unexpected eof reading suredata")),
        Err(e) => Err(e.into()),
    }
}

struct ReadSync {
    chan: Sender<Option<Result<String>>>,
}

impl Sink for ReadSync {
    fn plain(&mut self, text: &str, keep: bool) -> weave::Result<()> {
        if keep {
            match self.chan.send(Some(Ok(text.to_string()))) {
                Ok(()) => Ok(()),
                Err(e) => Err(format_err!("chan send error: {:?}", e)),
            }
        } else {
            Ok(())
        }
    }
}

/// Own a PathBuf, and delete this file on drop.  This is in its own type
/// for two reason. 1. I makes it easy to have cleaning in multiple types,
/// passing ownership between them, and 2.  It prevents the need for those
/// types to implement drop, which prevents moves out of the fields.
struct FileClean(PathBuf);

impl Drop for FileClean {
    fn drop(&mut self) {
        if env::var_os("RSURE_KEEP").is_none() {
            let _ = fs::remove_file(&self.0);
        }
    }
}

impl TempCleaner for FileClean{}
<commit_msg>Use the pull parser in the store<commit_after>//! SCCS-style delta weave stores.

use crate::{
    node,
    store::{Store, StoreTags, StoreVersion, StoreWriter, TempCleaner, TempFile, TempLoader, Version},
    Result, SureNode,
};
use failure::format_err;
use std::{
    env,
    fs::{self, File},
    io::{self, BufRead, BufReader, BufWriter, Write},
    path::{Path, PathBuf},
};
use weave::{self, DeltaWriter, NamingConvention, NewWeave, NullSink, Parser, PullParser, SimpleNaming};

pub struct WeaveStore {
    naming: SimpleNaming,
}

impl WeaveStore {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, compressed: bool) -> WeaveStore {
        WeaveStore {
            naming: SimpleNaming::new(path, base, "dat", compressed),
        }
    }
}

impl Store for WeaveStore {
    fn get_versions(&self) -> Result<Vec<StoreVersion>> {
        let header = Parser::new(&self.naming, NullSink, 1)?.into_header();
        let mut versions: Vec<_> = header
            .deltas
            .iter()
            .map(|v| StoreVersion {
                name: v.name.clone(),
                time: v.time,
                version: Version::Tagged(v.number.to_string()),
            }).collect();
        versions.reverse();
        Ok(versions)
    }

    fn load_iter(&self, version: Version) -> Result<Box<dyn Iterator<Item = Result<SureNode>>>> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        Ok(Box::new(WeaveIter::new(&self.naming, last)?))
    }

    fn make_temp(&self) -> Result<Box<dyn TempFile + '_>> {
        // TODO: Fixup naming to allow uncompressed writes.
        let (path, file) = self.naming.temp_file()?;
        let cpath = path.clone();
        Ok(Box::new(WeaveTemp {
            parent: self,
            path: path,
            file: BufWriter::new(file),
            cleaner: FileClean(cpath),
        }))
    }

    fn make_new(&self, tags: &StoreTags) -> Result<Box<dyn StoreWriter + '_>> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let wv = DeltaWriter::new(&self.naming, itags, base)?;
                Ok(Box::new(NewWeaveDelta { weave: wv }))
            }
            Err(_) => {
                // Create a new weave file.
                let wv = NewWeave::new(&self.naming, itags)?;
                Ok(Box::new(NewWeaveWriter { weave: wv }))
            }
        }
    }
}

struct WeaveTemp<'a> {
    parent: &'a WeaveStore,
    path: PathBuf,
    file: BufWriter<File>,
    cleaner: FileClean,
}

impl<'a> TempFile<'a> for WeaveTemp<'a> {
    fn into_loader(self: Box<Self>) -> Result<Box<dyn TempLoader + 'a>> {
        drop(self.file);
        Ok(Box::new(WeaveTempLoader {
            _parent: self.parent,
            path: self.path,
            cleaner: self.cleaner,
        }))
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

impl<'a> Write for WeaveTemp<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

pub struct WeaveTempLoader<'a> {
    _parent: &'a WeaveStore,
    path: PathBuf,
    cleaner: FileClean,
}

impl<'a> TempLoader for WeaveTempLoader<'a> {
    fn new_loader(&self) -> Result<Box<dyn BufRead>> {
        let read = BufReader::new(File::open(&self.path)?);
        Ok(Box::new(read))
    }

    fn path_ref(&self) -> &Path {
        &self.path
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

pub struct NewWeaveWriter<'a> {
    weave: NewWeave<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveWriter<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct NewWeaveDelta<'a> {
    weave: DeltaWriter<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveDelta<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveDelta<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct WeaveIter {
    pull: Box<dyn Iterator<Item = Result<String>>>,
}

impl WeaveIter {
    fn new(naming: &dyn NamingConvention, delta: usize) -> Result<WeaveIter> {
        let mut pull = PullParser::new(naming, delta)?.filter_map(kept_text);
        fixed(&mut pull, "asure-2.0")?;
        fixed(&mut pull, "-----")?;
        Ok(WeaveIter { pull: Box::new(pull) })
    }
}

impl Iterator for WeaveIter {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        let line = match self.pull.next() {
            Some(Err(e)) => return Some(Err(e)),
            Some(Ok(line)) => line,
            None => return None,
        };
        let line = line.as_bytes();

        match line[0] {
            b'd' => {
                let (dname, datts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::Enter{name: dname, atts: datts}))
            }
            b'f' => {
                let (fname, fatts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::File{name: fname, atts: fatts}))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => Some(Ok(SureNode::Leave)),
            ch => Some(Err(format_err!("Invalid surefile line start: {:?}", ch)))
        }
    }
}

// Filter nodes to only include kept text lines.
fn kept_text(node: Result<weave::Entry>) -> Option<Result<String>> {
    match node {
        Err(e) => Some(Err(e)),
        Ok(weave::Entry::Plain { text, keep }) if keep => Some(Ok(text)),
        _ => None,
    }
}

/// Try reading a specific line from the given iterator.  Returns Err if
/// the line didn't match, or something went wrong with the read.
fn fixed<I>(pull: &mut I, expect: &str) -> Result<()>
    where I: Iterator<Item = Result<String>>
{
    match pull.next() {
        Some(Ok(line)) => {
            if line == expect {
                Ok(())
            } else {
                Err(format_err!("Unexpected line from weave: {:?} expect {:?}", line, expect))
            }
        }
        Some(Err(e)) => Err(e),
        None => Err(format_err!("Unexpected eof reading suredata")),
    }
}
/*
fn fixed(recv: &Receiver<Option<Result<String>>>, expect: &[u8]) -> Result<()> {
    match recv.recv() {
        Ok(Some(Ok(line))) => {
            if line.as_bytes() == expect {
                Ok(())
            } else {
                Err(format_err!("Unexpect line from channel: {:?} expect {:?}", line, expect))
            }
        }
        Ok(Some(Err(e))) => Err(format_err!("Error reading suredata: {:?}", e)),
        Ok(None) => Err(format_err!("Unexpected eof reading suredata")),
        Err(e) => Err(e.into()),
    }
}
*/

/// Own a PathBuf, and delete this file on drop.  This is in its own type
/// for two reason. 1. I makes it easy to have cleaning in multiple types,
/// passing ownership between them, and 2.  It prevents the need for those
/// types to implement drop, which prevents moves out of the fields.
struct FileClean(PathBuf);

impl Drop for FileClean {
    fn drop(&mut self) {
        if env::var_os("RSURE_KEEP").is_none() {
            let _ = fs::remove_file(&self.0);
        }
    }
}

impl TempCleaner for FileClean{}
<|endoftext|>