<commit_before>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{Parser, ParserInput};
use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }

    fn parse_input<'i, 't>(p: &mut Parser<'i, 't>) -> Result<AspectRatio, ()> {
        let defer = p.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| FitMode::parse(ident))
        }).unwrap_or(FitMode::default());

        p.expect_exhausted().map_err(|_| ())?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

impl Align {
    fn parse_xy(s: &str) -> Result<Option<(Align1D, Align1D)>, ()> {
        use self::Align1D::*;

        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Min, Min))),
            "xMidYMin" => Ok(Some((Mid, Min))),
            "xMaxYMin" => Ok(Some((Max, Min))),

            "xMinYMid" => Ok(Some((Min, Mid))),
            "xMidYMid" => Ok(Some((Mid, Mid))),
            "xMaxYMid" => Ok(Some((Max, Mid))),

            "xMinYMax" => Ok(Some((Min, Max))),
            "xMidYMax" => Ok(Some((Mid, Max))),
            "xMaxYMax" => Ok(Some((Max, Max))),

            _ => Err(()),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ()> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(()),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut input = ParserInput::new(s);
        AspectRatio::parse_input(&mut Parser::new(&mut input)).map_err(|_| {
            AttributeError::Parse(ParseError::new(
                "expected \"[defer] <align> [meet | slice]\"",
            ))
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<commit_msg>aspect_ratio: Move impl Defualts under the struct declarations.<commit_after>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{Parser, ParserInput};
use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }

    fn parse_input<'i, 't>(p: &mut Parser<'i, 't>) -> Result<AspectRatio, ()> {
        let defer = p.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| FitMode::parse(ident))
        }).unwrap_or(FitMode::default());

        p.expect_exhausted().map_err(|_| ())?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

impl Align {
    fn parse_xy(s: &str) -> Result<Option<(Align1D, Align1D)>, ()> {
        use self::Align1D::*;

        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Min, Min))),
            "xMidYMin" => Ok(Some((Mid, Min))),
            "xMaxYMin" => Ok(Some((Max, Min))),

            "xMinYMid" => Ok(Some((Min, Mid))),
            "xMidYMid" => Ok(Some((Mid, Mid))),
            "xMaxYMid" => Ok(Some((Max, Mid))),

            "xMinYMax" => Ok(Some((Min, Max))),
            "xMidYMax" => Ok(Some((Mid, Max))),
            "xMaxYMax" => Ok(Some((Max, Max))),

            _ => Err(()),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ()> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(()),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut input = ParserInput::new(s);
        AspectRatio::parse_input(&mut Parser::new(&mut input)).map_err(|_| {
            AttributeError::Parse(ParseError::new(
                "expected \"[defer] <align> [meet | slice]\"",
            ))
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::Entry::{Occupied, Vacant};

use failure::{err_msg, Error};
use ggez::{graphics, Context, GameResult};
use ggez_goodies::scene::{Scene, SceneSwitch};
use warmy::{LogicalKey, Store};

use crate::game::{Game, SceneState};
use crate::input::{Axis, Button, InputEvent};
use crate::objects::TextureAtlas;
use crate::palette::PaletteSwaps;
use crate::piv::{extract_palette, Colour};
use crate::scenes::FSceneSwitch;

use super::menu::Menu;

enum State {
    Selecting,
    Naming,
}

pub struct SelectKnight {
    menu: Menu,
    oscillate: ColourOscillate,
    swap_colour: Colour,

    state: State,

    current: usize,
    selected: Vec<u32>,
    available: Vec<u32>,
}

struct ColourOscillate {
    from: Colour,
    to: Colour,
    current: Colour,
    target: Colour,
}

impl ColourOscillate {
    pub fn new(from: Colour, to: Colour) -> Self {
        ColourOscillate {
            from: from.clone(),
            to: to.clone(),
            current: from.clone(),
            target: to.clone(),
        }
    }
}

impl Iterator for ColourOscillate {
    type Item = Colour;

    fn next(&mut self) -> Option<Self::Item> {
        if self.target.r > self.current.r {
            self.current.r += 16
        } else if self.target.r < self.current.r {
            self.current.r -= 16
        };

        if self.target.g > self.current.g {
            self.current.g += 16
        } else if self.target.g < self.current.g {
            self.current.g -= 16
        };

        if self.target.b > self.current.b {
            self.current.b += 16
        } else if self.target.b < self.current.b {
            self.current.b -= 16
        };

        if self.current == self.target {
            if self.target == self.from {
                self.target = self.to
            } else {
                self.target = self.from
            }
        }
        Some(self.current.clone())
    }
}

impl SelectKnight {
    pub fn new(ctx: &mut Context, store: &mut Store<Context>) -> Result<Self, Error> {
        let menu = Menu::new(ctx, store, "/select_knight.yaml")?;

        let swaps_res = store.get::<_, PaletteSwaps>(&LogicalKey::new("/palettes.yaml"), ctx)?;
        let swaps = swaps_res.borrow();
        let raw_palette = swaps
            .0
            .get("select_knight")
            .ok_or_else(|| err_msg("failed to load select_knight.yaml"))?;
        let mut swap_colour = extract_palette(raw_palette)
            .first()
            .ok_or_else(|| err_msg("select_knight palette does not have a colour defined"))?
            .clone();
        swap_colour.a = 255;

        let original_colour = menu.palette[15].clone();

        let oscillate = ColourOscillate::new(original_colour, swap_colour);

        Ok(Self {
            menu,
            oscillate,
            swap_colour: original_colour.clone(),
            state: State::Selecting,
            current: 0,
            available: vec![0, 1, 2, 3],
            selected: Vec::new(),
        })
    }

    fn draw_cursor(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        let atlas = game
            .store
            .get::<_, TextureAtlas>(&LogicalKey::new(&self.menu.screen.cursor.sheet), ctx)
            // TODO: raise error
            .expect("Couldn't find sel.cel yaml metadata");

        let ggez_image = match game.images.entry(format!(
            "{}-{}-{}-{}",
            self.menu.screen.cursor.sheet,
            self.swap_colour.r,
            self.swap_colour.g,
            self.swap_colour.b
        )) {
            Occupied(i) => i.into_mut(),
            Vacant(i) => {
                let mut palette = self.menu.palette.clone();
                palette[15] = self.swap_colour;

                let atlas_dimension = atlas.borrow().image.width as u32;
                i.insert(graphics::Image::from_rgba8(
                    ctx,
                    atlas_dimension as u16,
                    atlas_dimension as u16,
                    &atlas.borrow().image.to_rgba8(&palette),
                )?)
            }
        };

        let rect = atlas.borrow().rects[self.menu.screen.cursor.image];
        let texture_size = atlas.borrow().image.width as f32;
        let draw_params = graphics::DrawParam {
            src: graphics::Rect {
                x: rect.x as f32 / texture_size,
                y: rect.y as f32 / texture_size,
                w: rect.w as f32 / texture_size,
                h: rect.h as f32 / texture_size,
            },
            dest: graphics::Point2::new(
                self.menu.screen.cursor.x as f32 * 3.0,
                self.menu.screen.cursor.y as f32 * 3.0,
            ),
            scale: graphics::Point2::new(3.0, 3.0),
            ..Default::default()
        };
        graphics::draw_ex(ctx, ggez_image, draw_params)?;

        Ok(())
    }
}

impl Scene<Game, InputEvent> for SelectKnight {
    fn update(&mut self, _game: &mut Game, _ctx: &mut Context) -> FSceneSwitch {
        if let Some(colour) = self.oscillate.next() {
            self.swap_colour = colour;
        }
        self.menu.screen.cursor.x = self
            .menu
            .screen
            .images
            .iter()
            .map(|i| i.x)
            .nth(self.current)
            .unwrap_or_else(|| self.menu.screen.cursor.x);
        SceneSwitch::None
    }

    fn draw(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::from((0, 0, 0, 255)));
        graphics::clear(ctx);
        self.menu.draw(game, ctx);
        self.draw_cursor(game, ctx);
        Ok(())
    }

    fn name(&self) -> &str {
        "Select a Knight"
    }

    fn input(&mut self, gameworld: &mut Game, _event: InputEvent, started: bool) {
        match self.state {
            State::Selecting => {
                let x = gameworld.input.get_axis_raw(Axis::Horz1) as i32;
                let len = self.available.len() as i32;
                if x > 0 {
                    self.current = ((self.current as i32 + x) % len) as usize;
                } else {
                    self.current = ((self.current as i32 + x + len) % len) as usize;
                }
            }
            State::Naming => (),
        }
    }
}
<commit_msg>save selected knights.<commit_after>use std::collections::hash_map::Entry::{Occupied, Vacant};

use failure::{err_msg, Error};
use ggez::{graphics, Context, GameResult};
use ggez_goodies::scene::{Scene, SceneSwitch};
use warmy::{LogicalKey, Store};

use crate::game::{Game, SceneState};
use crate::input::{Axis, Button, InputEvent};
use crate::objects::TextureAtlas;
use crate::palette::PaletteSwaps;
use crate::piv::{extract_palette, Colour};
use crate::scenes::FSceneSwitch;

use super::menu::Menu;

enum State {
    Selecting,
    Naming,
}

pub struct SelectKnight {
    menu: Menu,
    oscillate: ColourOscillate,
    swap_colour: Colour,

    state: State,

    current: usize,
    selected: Vec<u32>,
    available: Vec<u32>,
}

struct ColourOscillate {
    from: Colour,
    to: Colour,
    current: Colour,
    target: Colour,
}

impl ColourOscillate {
    pub fn new(from: Colour, to: Colour) -> Self {
        ColourOscillate {
            from: from.clone(),
            to: to.clone(),
            current: from.clone(),
            target: to.clone(),
        }
    }
}

impl Iterator for ColourOscillate {
    type Item = Colour;

    fn next(&mut self) -> Option<Self::Item> {
        if self.target.r > self.current.r {
            self.current.r += 16
        } else if self.target.r < self.current.r {
            self.current.r -= 16
        };

        if self.target.g > self.current.g {
            self.current.g += 16
        } else if self.target.g < self.current.g {
            self.current.g -= 16
        };

        if self.target.b > self.current.b {
            self.current.b += 16
        } else if self.target.b < self.current.b {
            self.current.b -= 16
        };

        if self.current == self.target {
            if self.target == self.from {
                self.target = self.to
            } else {
                self.target = self.from
            }
        }
        Some(self.current.clone())
    }
}

impl SelectKnight {
    pub fn new(ctx: &mut Context, store: &mut Store<Context>) -> Result<Self, Error> {
        let menu = Menu::new(ctx, store, "/select_knight.yaml")?;

        let swaps_res = store.get::<_, PaletteSwaps>(&LogicalKey::new("/palettes.yaml"), ctx)?;
        let swaps = swaps_res.borrow();
        let raw_palette = swaps
            .0
            .get("select_knight")
            .ok_or_else(|| err_msg("failed to load select_knight.yaml"))?;
        let mut swap_colour = extract_palette(raw_palette)
            .first()
            .ok_or_else(|| err_msg("select_knight palette does not have a colour defined"))?
            .clone();
        swap_colour.a = 255;

        let original_colour = menu.palette[15].clone();

        let oscillate = ColourOscillate::new(original_colour, swap_colour);

        Ok(Self {
            menu,
            oscillate,
            swap_colour: original_colour.clone(),
            state: State::Selecting,
            current: 0,
            available: vec![0, 1, 2, 3],
            selected: Vec::new(),
        })
    }

    fn draw_cursor(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        let atlas = game
            .store
            .get::<_, TextureAtlas>(&LogicalKey::new(&self.menu.screen.cursor.sheet), ctx)
            // TODO: raise error
            .expect("Couldn't find sel.cel yaml metadata");

        let ggez_image = match game.images.entry(format!(
            "{}-{}-{}-{}",
            self.menu.screen.cursor.sheet,
            self.swap_colour.r,
            self.swap_colour.g,
            self.swap_colour.b
        )) {
            Occupied(i) => i.into_mut(),
            Vacant(i) => {
                let mut palette = self.menu.palette.clone();
                palette[15] = self.swap_colour;

                let atlas_dimension = atlas.borrow().image.width as u32;
                i.insert(graphics::Image::from_rgba8(
                    ctx,
                    atlas_dimension as u16,
                    atlas_dimension as u16,
                    &atlas.borrow().image.to_rgba8(&palette),
                )?)
            }
        };

        let rect = atlas.borrow().rects[self.menu.screen.cursor.image];
        let texture_size = atlas.borrow().image.width as f32;
        let draw_params = graphics::DrawParam {
            src: graphics::Rect {
                x: rect.x as f32 / texture_size,
                y: rect.y as f32 / texture_size,
                w: rect.w as f32 / texture_size,
                h: rect.h as f32 / texture_size,
            },
            dest: graphics::Point2::new(
                self.menu.screen.cursor.x as f32 * 3.0,
                self.menu.screen.cursor.y as f32 * 3.0,
            ),
            scale: graphics::Point2::new(3.0, 3.0),
            ..Default::default()
        };
        graphics::draw_ex(ctx, ggez_image, draw_params)?;

        Ok(())
    }

    fn select_current_knight(&mut self) {
        self.selected.push(self.available.remove(self.current));
        self.menu.screen.images.remove(self.current);

        self.current = 0;
    }
}

impl Scene<Game, InputEvent> for SelectKnight {
    fn update(&mut self, game: &mut Game, _ctx: &mut Context) -> FSceneSwitch {
        if let Some(colour) = self.oscillate.next() {
            self.swap_colour = colour;
        }
        self.menu.screen.cursor.x = self
            .menu
            .screen
            .images
            .iter()
            .map(|i| i.x)
            .nth(self.current)
            .unwrap_or_else(|| self.menu.screen.cursor.x);

        if self.selected.len() == game.num_players as usize {
            SceneSwitch::Pop
        } else {
            SceneSwitch::None
        }
    }

    fn draw(&mut self, game: &mut Game, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::Color::from((0, 0, 0, 255)));
        graphics::clear(ctx);
        self.menu.draw(game, ctx);
        self.draw_cursor(game, ctx);
        Ok(())
    }

    fn name(&self) -> &str {
        "Select a Knight"
    }

    fn input(&mut self, gameworld: &mut Game, _event: InputEvent, started: bool) {
        match self.state {
            State::Selecting => {
                let x = gameworld.input.get_axis_raw(Axis::Horz1) as i32;
                let len = self.available.len() as i32;
                if x > 0 {
                    self.current = ((self.current as i32 + x) % len) as usize;
                } else {
                    self.current = ((self.current as i32 + x + len) % len) as usize;
                }

                if gameworld.input.get_button_down(Button::Fire1) {
                    self.select_current_knight();
                }
            }
            State::Naming => (),
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Write};

use parser::html;
use parser::html::Expression as Expr;
use parser::html::Statement as Stmt;
use parser::html::{Link, LinkDest, Fmt};
use parser::html::Statement::{Element, Store, Condition, Output};
use parser::{Ast, Block};
use util::join;

use super::ast::{Code, Statement, Param, Expression};
use super::ast::Expression as E;

use super::Generator;

impl<'a, W:Write+'a> Generator<'a, W> {

    fn compile_expr(&self, expr: &Expr) -> Expression
    {
        match expr {
            &Expr::Name(ref name) => Expression::Name(name.clone()),
            &Expr::Str(ref value) => Expression::Str(value.clone()),

            // TODO(tailhook) validate numeric suffixes
            &Expr::Num(ref value) => Expression::Num(value.clone()),

            &Expr::New(ref expr)
            => Expression::New(Box::new(self.compile_expr(expr))),
            &Expr::Attr(ref expr, ref value)
            => Expression::Attr(Box::new(self.compile_expr(expr)),
                                value.clone()),
            &Expr::Call(ref expr, ref args)
            => Expression::Call(Box::new(self.compile_expr(expr)),
                args.iter().map(|x| self.compile_expr(x)).collect()),
            &Expr::Add(ref a, ref b)
            => Expression::Add(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Sub(ref a, ref b)
            => Expression::Sub(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Mul(ref a, ref b)
            => Expression::Mul(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Div(ref a, ref b)
            => Expression::Div(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Comparison(op, ref a, ref b)
            => Expression::Comparison(op,
                Box::new(self.compile_expr(a)),
                Box::new(self.compile_expr(b))),
            &Expr::Format(ref value) => {
                self.compile_format(value)
            }
        }
    }
    fn compile_format(&self, items: &Vec<Fmt>) -> Expression
    {
        let mut exprs = items.iter().map(|e| match e {
            &Fmt::Raw(ref x) => Expression::Str(x.clone()),
            &Fmt::Str(ref e) => self.compile_expr(e),
            &Fmt::Float(ref e, _) => self.compile_expr(e), // TODO(tailhook)
            &Fmt::Int(ref e) => self.compile_expr(e),
        }).collect::<Vec<_>>();
        let first = exprs.remove(0);
        exprs.into_iter().fold(first, |acc, item| {
            Expression::Add(Box::new(acc), Box::new(item))
        })
    }

    fn attrs(&self, name: &String, cls: &Vec<(String, Option<Expr>)>,
        attrs: &Vec<(String, Expr)>)
        -> Expression
    {
        let mut class_literals = vec!();
        let mut class_expr = vec!();
        if cls.len() > 0 || self.bare_element_names.contains(name) {
            class_literals.push(self.block_name.to_string());
        }
        for &(ref cname, ref opt_cond) in cls {
            if let &Some(ref cond) = opt_cond {
                class_expr.push(Expression::Ternary(
                    Box::new(self.compile_expr(cond)),
                    Box::new(Expression::Str(cname.clone())),
                    Box::new(Expression::Str(String::from("")))));
            } else {
                class_literals.push(cname.clone());
            }
        }
        let mut rattrs = vec!();
        for &(ref name, ref value) in attrs {
            if &name[..] == "class" {
                class_expr.push(self.compile_expr(value));
            } else {
                rattrs.push((name.clone(), self.compile_expr(value)));
            }
        }
        if class_literals.len() > 0 {
            class_expr.insert(0,
                Expression::Str(join(class_literals.iter(), " ")));
        }
        if class_expr.len() > 0 {
            let first = class_expr.remove(0);
            rattrs.push((String::from("class"), class_expr.into_iter()
                .fold(first, |acc, val|
                    Expression::Add(Box::new(
                        Expression::Add(
                            Box::new(acc),
                            Box::new(Expression::Str(String::from(" "))))),
                        Box::new(val)))));
        }
        Expression::Object(rattrs)
    }
    fn element(&self, st: &html::Statement) -> Expression {
        match st {
            &Element { ref name, ref classes, ref body, ref attributes } => {
                let mut properties = vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                ];
                let mut statements = vec![];
                let mut events = vec![];
                for item in body.iter() {
                    match item {
                        &Store(ref name, ref value) => {
                            let prop = String::from("store_") +name;
                            statements.push(Statement::Var(name.clone(),
                                E::Or(
                                    Box::new(E::And(
                                        Box::new(E::Name(String::from("old_node"))),
                                        Box::new(E::Attr(Box::new(
                                                E::Name(String::from("old_node"))),
                                                prop.clone())))),
                                    Box::new(self.compile_expr(value)))));
                            properties.push((prop, E::Name(name.clone())));
                        }
                        &Stmt::Link(ref links) => {
                            for lnk in links {
                                match lnk {
                                    &Link::One(ref s, LinkDest::Stream(ref expr)) => {
                                        events.push((s.clone(),
                                            E::Attr(Box::new(self.compile_expr(expr)),
                                                String::from("handle_event")),
                                            ));
                                    }
                                    &Link::Multi(ref names, LinkDest::Stream(ref expr)) => {
                                        let v = format!("_stream_{}",
                                            statements.len());
                                        statements.push(Statement::Var(
                                            v.clone(),
                                            self.compile_expr(expr)));
                                        for &(ref attr, ref event) in names {
                                            events.push((
                                                event.as_ref().unwrap_or(attr)
                                                    .clone(),
                                                E::Attr(
                                                    Box::new(E::Attr(
                                                        Box::new(E::Name(v.clone())),
                                                        attr.clone())),
                                                    String::from("handle_event"))));
                                        }
                                    }
                                    &Link::One(_, LinkDest::Mapping(_, _)) => unimplemented!(),
                                    &Link::Multi(_, LinkDest::Mapping(_, _)) => unimplemented!(),
                                }
                            }
                        }
                        _ => {}
                    }
                }
                if classes.len() > 0 || attributes.len() > 0 {
                    properties.push(
                        (String::from("attrs"),
                            self.attrs(name, classes, attributes)));
                }
                if body.len() > 0 {
                    properties.push(
                        (String::from("children"), self.fragment(&body)));
                }
                if events.len() > 0 {
                    properties.push(
                        (String::from("events"), Expression::Object(events)));
                }
                if statements.len() > 0 {
                    statements.push(
                        Statement::Return(Expression::Object(properties)));
                    return Expression::Function(None,
                        vec![Param {
                            name: String::from("old_node"),
                            default_value: None,
                        }],
                        statements);
                } else {
                    return Expression::Object(properties);
                }
            }
            &Stmt::Format(ref value) => {
                self.compile_format(value)
            }
            &Output(ref expr) => {
                self.compile_expr(expr)
            }
            &Condition(ref conditions, ref fallback) => {
                conditions.iter().rev()
                .fold(fallback.as_ref()
                    .map(|x| self.fragment(x))
                    .unwrap_or(Expression::Str(String::new())),
                    |old, &(ref cond, ref value)| Expression::Ternary(
                        Box::new(self.compile_expr(cond)),
                        Box::new(self.fragment(value)),
                        Box::new(old),
                    ))
            }
            &Stmt::Store(_, _) => unreachable!(),  // not an actual child
            &Stmt::Link(_) => unreachable!(),  // not an actual child
        }
    }
    fn fragment(&self, statements: &Vec<html::Statement>) -> Expression {
        let stmt = statements.iter().filter(|x| match x {
            &&Stmt::Store(_, _) | &&Stmt::Link(_) => false,
            _ => true,
            }).collect::<Vec<_>>();
        if statements.len() == 1 {
            return self.element(&statements[0]);
        } else {
            return Expression::Object(vec![(
                String::from("children"),
                Expression::List(
                    stmt.iter()
                    .map(|s| self.element(s))
                    .collect())
                )]);
        }
    }
    pub fn code(&self, ast: &Ast) -> Code {
        let mut stmt = vec!();
        for blk in ast.blocks.iter() {
            if let &Block::Html {ref name, ref params, ref statements, ..} = blk {
                stmt.push(Statement::Function(name.clone(),
                    params.iter().map(|p| Param {
                        name: p.name.clone(),
                        default_value: p.default_value.as_ref().map(
                            |v| Expression::Str(v.clone())),
                    }).collect(),
                    vec![
                        Statement::Return(self.fragment(statements)),
                    ]
                ));
            }
        }
        return Code {
            statements: stmt,
        }
    }

}
<commit_msg>Stringify all pieces of format string<commit_after>use std::io::{Write};

use parser::html;
use parser::html::Expression as Expr;
use parser::html::Statement as Stmt;
use parser::html::{Link, LinkDest, Fmt};
use parser::html::Statement::{Element, Store, Condition, Output};
use parser::{Ast, Block};
use util::join;

use super::ast::{Code, Statement, Param, Expression};
use super::ast::Expression as E;

use super::Generator;

impl<'a, W:Write+'a> Generator<'a, W> {

    fn compile_expr(&self, expr: &Expr) -> Expression
    {
        match expr {
            &Expr::Name(ref name) => Expression::Name(name.clone()),
            &Expr::Str(ref value) => Expression::Str(value.clone()),

            // TODO(tailhook) validate numeric suffixes
            &Expr::Num(ref value) => Expression::Num(value.clone()),

            &Expr::New(ref expr)
            => Expression::New(Box::new(self.compile_expr(expr))),
            &Expr::Attr(ref expr, ref value)
            => Expression::Attr(Box::new(self.compile_expr(expr)),
                                value.clone()),
            &Expr::Call(ref expr, ref args)
            => Expression::Call(Box::new(self.compile_expr(expr)),
                args.iter().map(|x| self.compile_expr(x)).collect()),
            &Expr::Add(ref a, ref b)
            => Expression::Add(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Sub(ref a, ref b)
            => Expression::Sub(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Mul(ref a, ref b)
            => Expression::Mul(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Div(ref a, ref b)
            => Expression::Div(Box::new(self.compile_expr(a)),
                               Box::new(self.compile_expr(b))),
            &Expr::Comparison(op, ref a, ref b)
            => Expression::Comparison(op,
                Box::new(self.compile_expr(a)),
                Box::new(self.compile_expr(b))),
            &Expr::Format(ref value) => {
                self.compile_format(value)
            }
        }
    }
    fn compile_format(&self, items: &Vec<Fmt>) -> Expression
    {
        let mut exprs = items.iter().map(|e| match e {
            &Fmt::Raw(ref x) => Expression::Str(x.clone()),
            &Fmt::Str(ref e) => Expression::Call(
                Box::new(Expression::Name(String::from("String"))),
                vec![self.compile_expr(e)]),
            &Fmt::Int(ref e) => Expression::Call(
                Box::new(Expression::Name(String::from("String"))),
                vec![self.compile_expr(e)]),
            &Fmt::Float(ref e, _) => Expression::Call(
                Box::new(Expression::Name(String::from("String"))),
                vec![self.compile_expr(e)]),
        }).collect::<Vec<_>>();
        let first = exprs.remove(0);
        exprs.into_iter().fold(first, |acc, item| {
            Expression::Add(Box::new(acc), Box::new(item))
        })
    }

    fn attrs(&self, name: &String, cls: &Vec<(String, Option<Expr>)>,
        attrs: &Vec<(String, Expr)>)
        -> Expression
    {
        let mut class_literals = vec!();
        let mut class_expr = vec!();
        if cls.len() > 0 || self.bare_element_names.contains(name) {
            class_literals.push(self.block_name.to_string());
        }
        for &(ref cname, ref opt_cond) in cls {
            if let &Some(ref cond) = opt_cond {
                class_expr.push(Expression::Ternary(
                    Box::new(self.compile_expr(cond)),
                    Box::new(Expression::Str(cname.clone())),
                    Box::new(Expression::Str(String::from("")))));
            } else {
                class_literals.push(cname.clone());
            }
        }
        let mut rattrs = vec!();
        for &(ref name, ref value) in attrs {
            if &name[..] == "class" {
                class_expr.push(self.compile_expr(value));
            } else {
                rattrs.push((name.clone(), self.compile_expr(value)));
            }
        }
        if class_literals.len() > 0 {
            class_expr.insert(0,
                Expression::Str(join(class_literals.iter(), " ")));
        }
        if class_expr.len() > 0 {
            let first = class_expr.remove(0);
            rattrs.push((String::from("class"), class_expr.into_iter()
                .fold(first, |acc, val|
                    Expression::Add(Box::new(
                        Expression::Add(
                            Box::new(acc),
                            Box::new(Expression::Str(String::from(" "))))),
                        Box::new(val)))));
        }
        Expression::Object(rattrs)
    }
    fn element(&self, st: &html::Statement) -> Expression {
        match st {
            &Element { ref name, ref classes, ref body, ref attributes } => {
                let mut properties = vec![
                        (String::from("tag"), Expression::Str(name.clone())),
                ];
                let mut statements = vec![];
                let mut events = vec![];
                for item in body.iter() {
                    match item {
                        &Store(ref name, ref value) => {
                            let prop = String::from("store_") +name;
                            statements.push(Statement::Var(name.clone(),
                                E::Or(
                                    Box::new(E::And(
                                        Box::new(E::Name(String::from("old_node"))),
                                        Box::new(E::Attr(Box::new(
                                                E::Name(String::from("old_node"))),
                                                prop.clone())))),
                                    Box::new(self.compile_expr(value)))));
                            properties.push((prop, E::Name(name.clone())));
                        }
                        &Stmt::Link(ref links) => {
                            for lnk in links {
                                match lnk {
                                    &Link::One(ref s, LinkDest::Stream(ref expr)) => {
                                        events.push((s.clone(),
                                            E::Attr(Box::new(self.compile_expr(expr)),
                                                String::from("handle_event")),
                                            ));
                                    }
                                    &Link::Multi(ref names, LinkDest::Stream(ref expr)) => {
                                        let v = format!("_stream_{}",
                                            statements.len());
                                        statements.push(Statement::Var(
                                            v.clone(),
                                            self.compile_expr(expr)));
                                        for &(ref attr, ref event) in names {
                                            events.push((
                                                event.as_ref().unwrap_or(attr)
                                                    .clone(),
                                                E::Attr(
                                                    Box::new(E::Attr(
                                                        Box::new(E::Name(v.clone())),
                                                        attr.clone())),
                                                    String::from("handle_event"))));
                                        }
                                    }
                                    &Link::One(_, LinkDest::Mapping(_, _)) => unimplemented!(),
                                    &Link::Multi(_, LinkDest::Mapping(_, _)) => unimplemented!(),
                                }
                            }
                        }
                        _ => {}
                    }
                }
                if classes.len() > 0 || attributes.len() > 0 {
                    properties.push(
                        (String::from("attrs"),
                            self.attrs(name, classes, attributes)));
                }
                if body.len() > 0 {
                    properties.push(
                        (String::from("children"), self.fragment(&body)));
                }
                if events.len() > 0 {
                    properties.push(
                        (String::from("events"), Expression::Object(events)));
                }
                if statements.len() > 0 {
                    statements.push(
                        Statement::Return(Expression::Object(properties)));
                    return Expression::Function(None,
                        vec![Param {
                            name: String::from("old_node"),
                            default_value: None,
                        }],
                        statements);
                } else {
                    return Expression::Object(properties);
                }
            }
            &Stmt::Format(ref value) => {
                self.compile_format(value)
            }
            &Output(ref expr) => {
                self.compile_expr(expr)
            }
            &Condition(ref conditions, ref fallback) => {
                conditions.iter().rev()
                .fold(fallback.as_ref()
                    .map(|x| self.fragment(x))
                    .unwrap_or(Expression::Str(String::new())),
                    |old, &(ref cond, ref value)| Expression::Ternary(
                        Box::new(self.compile_expr(cond)),
                        Box::new(self.fragment(value)),
                        Box::new(old),
                    ))
            }
            &Stmt::Store(_, _) => unreachable!(),  // not an actual child
            &Stmt::Link(_) => unreachable!(),  // not an actual child
        }
    }
    fn fragment(&self, statements: &Vec<html::Statement>) -> Expression {
        let stmt = statements.iter().filter(|x| match x {
            &&Stmt::Store(_, _) | &&Stmt::Link(_) => false,
            _ => true,
            }).collect::<Vec<_>>();
        if statements.len() == 1 {
            return self.element(&statements[0]);
        } else {
            return Expression::Object(vec![(
                String::from("children"),
                Expression::List(
                    stmt.iter()
                    .map(|s| self.element(s))
                    .collect())
                )]);
        }
    }
    pub fn code(&self, ast: &Ast) -> Code {
        let mut stmt = vec!();
        for blk in ast.blocks.iter() {
            if let &Block::Html {ref name, ref params, ref statements, ..} = blk {
                stmt.push(Statement::Function(name.clone(),
                    params.iter().map(|p| Param {
                        name: p.name.clone(),
                        default_value: p.default_value.as_ref().map(
                            |v| Expression::Str(v.clone())),
                    }).collect(),
                    vec![
                        Statement::Return(self.fragment(statements)),
                    ]
                ));
            }
        }
        return Code {
            statements: stmt,
        }
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2020-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use {crate::compressor::CCtx, pyo3::prelude::*, std::sync::Arc};

#[pyclass]
pub struct ZstdCompressionWriter {
    cctx: Arc<CCtx<'static>>,
    writer: PyObject,
    source_size: u64,
    write_size: usize,
    write_return_read: bool,
    closefd: bool,
    entered: bool,
    closing: bool,
    closed: bool,
    bytes_compressed: usize,
}

impl ZstdCompressionWriter {
    pub fn new(
        py: Python,
        cctx: Arc<CCtx<'static>>,
        writer: &PyAny,
        source_size: u64,
        write_size: usize,
        write_return_read: bool,
        closefd: bool,
    ) -> Self {
        Self {
            cctx,
            writer: writer.into_py(py),
            source_size,
            write_size,
            write_return_read,
            closefd,
            entered: false,
            closing: false,
            closed: false,
            bytes_compressed: 0,
        }
    }
}
<commit_msg>rust: add stubs for ZstdCompressionWriter<commit_after>// Copyright (c) 2020-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use {
    crate::compressor::CCtx,
    pyo3::{exceptions::PyNotImplementedError, prelude::*},
    std::sync::Arc,
};

#[pyclass]
pub struct ZstdCompressionWriter {
    cctx: Arc<CCtx<'static>>,
    writer: PyObject,
    source_size: u64,
    write_size: usize,
    write_return_read: bool,
    closefd: bool,
    entered: bool,
    closing: bool,
    closed: bool,
    bytes_compressed: usize,
}

impl ZstdCompressionWriter {
    pub fn new(
        py: Python,
        cctx: Arc<CCtx<'static>>,
        writer: &PyAny,
        source_size: u64,
        write_size: usize,
        write_return_read: bool,
        closefd: bool,
    ) -> Self {
        Self {
            cctx,
            writer: writer.into_py(py),
            source_size,
            write_size,
            write_return_read,
            closefd,
            entered: false,
            closing: false,
            closed: false,
            bytes_compressed: 0,
        }
    }
}

#[pymethods]
impl ZstdCompressionWriter {
    // TODO __enter__
    // TODO __exit__

    fn memory_size(&self) -> usize {
        self.cctx.memory_size()
    }

    fn fileno(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn close(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[getter]
    fn closed(&self) -> bool {
        self.closed
    }

    fn isatty(&self) -> bool {
        false
    }

    fn readable(&self) -> bool {
        false
    }

    #[args(size = "None")]
    fn readline(&self, py: Python, _size: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    #[args(size = "None")]
    fn readlines(&self, py: Python, _hint: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    #[args(pos, whence = "None")]
    fn seek(&self, pos: isize, whence: Option<&PyAny>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn seekable(&self) -> bool {
        false
    }

    fn truncate(&self, py: Python, size: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn writable(&self) -> bool {
        true
    }

    fn writelines(&self, lines: &PyAny) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[args(size = "None")]
    fn read(&self, py: Python, size: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn readall(&self, py: Python) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn readinto(&self, py: Python, b: &PyAny) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn write(&self, data: &PyAny) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[args(flush_mode = "None")]
    fn flush_mode(&self, flush_mode: Option<&PyAny>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn tell(&self) -> usize {
        self.bytes_compressed
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{BitAnd, BitOr};

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl GuestAddress {
    /// Returns the address as a usize offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    pub fn raw_value(self) -> usize {
        self.0
    }

    /// Returns the offset from this address to the given base address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use memory_model::GuestAddress;
    ///   let base = GuestAddress(0x100);
    ///   let addr = GuestAddress(0x150);
    ///   assert_eq!(addr.unchecked_offset_from(base), 0x50usize);
    /// ```
    pub fn unchecked_offset_from(self, base: GuestAddress) -> usize {
        self.0 - base.0
    }

    /// Returns the result of the add or None if there is overflow.
    pub fn checked_add(self, other: usize) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    pub fn unchecked_add(self, offset: usize) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    pub fn checked_sub(self, other: usize) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }

    /// Returns the bitwise and of the address with the given mask.
    pub fn mask(self, mask: u64) -> GuestAddress {
        GuestAddress(self.0 & mask as usize)
    }
}

impl BitAnd<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 & other as usize)
    }
}

impl BitOr<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 | other as usize)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn mask() {
        let a = GuestAddress(0x5050);
        assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
        assert_eq!(GuestAddress(0x5000), a.mask(0xff00u64));
        assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn checked_sub_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }
}
<commit_msg>[GuestAddress] remove mask()<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{BitAnd, BitOr};

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl GuestAddress {
    /// Returns the address as a usize offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    pub fn raw_value(self) -> usize {
        self.0
    }

    /// Returns the offset from this address to the given base address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use memory_model::GuestAddress;
    ///   let base = GuestAddress(0x100);
    ///   let addr = GuestAddress(0x150);
    ///   assert_eq!(addr.unchecked_offset_from(base), 0x50usize);
    /// ```
    pub fn unchecked_offset_from(self, base: GuestAddress) -> usize {
        self.0 - base.0
    }

    /// Returns the result of the add or None if there is overflow.
    pub fn checked_add(self, other: usize) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    pub fn unchecked_add(self, offset: usize) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    pub fn checked_sub(self, other: usize) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }
}

impl BitAnd<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 & other as usize)
    }
}

impl BitOr<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 | other as usize)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn checked_sub_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }
}
<|endoftext|>


<commit_before>//! Endpoints for key management

use std::{collections::BTreeMap, fmt::Debug};

use ruma_identifiers::{DeviceKeyId, UserId};
use serde::{Deserialize, Serialize};

pub mod claim_keys;
pub mod get_key_changes;
pub mod get_keys;
pub mod upload_keys;

#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signatures;
#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signing_keys;

/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedKey {
    /// Base64-encoded 32-byte Curve25519 public key.
    pub key: String,

    /// Signatures for the key object.
    pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
}

/// A one-time public key for "pre-key" messages.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneTimeKey {
    /// A key containing signatures, for the SignedCurve25519 algorithm.
    SignedKey(SignedKey),

    /// A string-valued key, for the Ed25519 and Curve25519 algorithms.
    Key(String),
}

/// A cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CrossSigningKey {
    /// The ID of the user the key belongs to.
    pub user_id: UserId,

    /// What the key is used for.
    pub usage: Vec<KeyUsage>,

    /// The public key. The object must have exactly one property.
    pub keys: BTreeMap<String, String>,

    /// Signatures of the key. Only optional for master key.
    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
    pub signatures: BTreeMap<UserId, BTreeMap<String, String>>,
}

/// The usage of a cross signing key.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
    /// Master key.
    Master,
    /// Self-signing key.
    SelfSigning,
    /// User-signing key.
    UserSigning,
}
<commit_msg>client-api: Make the CrossSigningKey serialization invertible<commit_after>//! Endpoints for key management

use std::{collections::BTreeMap, fmt::Debug};

use ruma_identifiers::{DeviceKeyId, UserId};
use serde::{Deserialize, Serialize};

pub mod claim_keys;
pub mod get_key_changes;
pub mod get_keys;
pub mod upload_keys;

#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signatures;
#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signing_keys;

/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedKey {
    /// Base64-encoded 32-byte Curve25519 public key.
    pub key: String,

    /// Signatures for the key object.
    pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
}

/// A one-time public key for "pre-key" messages.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneTimeKey {
    /// A key containing signatures, for the SignedCurve25519 algorithm.
    SignedKey(SignedKey),

    /// A string-valued key, for the Ed25519 and Curve25519 algorithms.
    Key(String),
}

/// A cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CrossSigningKey {
    /// The ID of the user the key belongs to.
    pub user_id: UserId,

    /// What the key is used for.
    pub usage: Vec<KeyUsage>,

    /// The public key. The object must have exactly one property.
    pub keys: BTreeMap<String, String>,

    /// Signatures of the key. Only optional for master key.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub signatures: BTreeMap<UserId, BTreeMap<String, String>>,
}

/// The usage of a cross signing key.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
    /// Master key.
    Master,
    /// Self-signing key.
    SelfSigning,
    /// User-signing key.
    UserSigning,
}
<|endoftext|>


<commit_before>//! An "hello world" echo server with tokio-core
//!
//! This server will create a TCP listener, accept connections in a loop, and
//! simply write back everything that's read off of each TCP connection. Each
//! TCP connection is processed concurrently with all other TCP connections, and
//! each connection will have its own buffer that it's reading in/out of.
//!
//! To see this server in action, you can run this in one terminal:
//!
//!     cargo run --example echo
//!
//! and in another terminal you can run:
//!
//!     cargo run --example connect 127.0.0.1:8080
//!
//! Each line you type in to the `connect` terminal should be echo'd back to
//! you! If you open up multiple terminals running the `connect` example you
//! should be able to see them all make progress simultaneously.

extern crate futures;
extern crate tokio_core;

use std::env;
use std::net::SocketAddr;

use futures::Future;
use futures::stream::Stream;
use tokio_core::io::{copy, Io};
use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;
use std::cell::RefCell;

type ConnectionList = RefCell<Vec<tokio_core::io::WriteHalf<tokio_core::net::TcpStream>>>;

fn main() {
    // Allow passing an address to listen on as the first argument of this
    // program, but otherwise we'll just set up our TCP listener on
    // 127.0.0.1:8080 for connections.
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:1337".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    let connection_list : ConnectionList = RefCell::new(vec![]);
    // First up we'll create the event loop that's going to drive this server.
    // This is done by creating an instance of the `Core` type, tokio-core's
    // event loop. Most functions in tokio-core return an `io::Result`, and
    // `Core::new` is no exception. For this example, though, we're mostly just
    // ignoring errors, so we unwrap the return value.
    //
    // After the event loop is created we acquire a handle to it through the
    // `handle` method. With this handle we'll then later be able to create I/O
    // objects and spawn futures.
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    // Next up we create a TCP listener which will listen for incoming
    // connections. This TCP listener is bound to the address we determined
    // above and must be associated with an event loop, so we pass in a handle
    // to our event loop. After the socket's created we inform that we're ready
    // to go and start accepting connections.
    let socket = TcpListener::bind(&addr, &handle).unwrap();
    println!("Listening on: {}", addr);

    // Here we convert the `TcpListener` to a stream of incoming connections
    // with the `incoming` method. We then define how to process each element in
    // the stream with the `for_each` method.
    //
    // This combinator, defined on the `Stream` trait, will allow us to define a
    // computation to happen for all items on the stream (in this case TCP
    // connections made to the server).  The return value of the `for_each`
    // method is itself a future representing processing the entire stream of
    // connections, and ends up being our server.
    let done = socket.incoming().for_each(move |(socket, addr)| {

        // Once we're inside this closure this represents an accepted client
        // from our server. The `socket` is the client connection and `addr` is
        // the remote address of the client (similar to how the standard library
        // operates).
        //
        // We just want to copy all data read from the socket back onto the
        // socket itself (e.g. "echo"). We can use the standard `io::copy`
        // combinator in the `tokio-core` crate to do precisely this!
        //
        // The `copy` function takes two arguments, where to read from and where
        // to write to. We only have one argument, though, with `socket`.
        // Luckily there's a method, `Io::split`, which will split an Read/Write
        // stream into its two halves. This operation allows us to work with
        // each stream independently, such as pass them as two arguments to the
        // `copy` function.
        //
        // The `copy` function then returns a future, and this future will be
        // resolved when the copying operation is complete, resolving to the
        // amount of data that was copied.
        let (reader, writer) = socket.split();

        connection_list.borrow_mut().push(writer);

        //let amt = coq(reader, writer);

        // After our copy operation is complete we just print out some helpful
        // information.
        let msg = amt.then(move |result| {
            match result {
                Ok(amt) => println!("wrote {} bytes to {}", amt, addr),
                Err(e) => println!("error on {}: {}", addr, e),
            }

            Ok(())
        });

        // And this is where much of the magic of this server happens. We
        // crucially want all clients to make progress concurrently, rather than
        // blocking one on completion of another. To achieve this we use the
        // `spawn` function on `Handle` to essentially execute some work in the
        // background.
        //
        // This function will transfer ownership of the future (`msg` in this
        // case) to the event loop that `handle` points to. The event loop will
        // then drive the future to completion.
        //
        // Essentially here we're spawning a new task to run concurrently, which
        // will allow all of our clients to be processed concurrently.
        handle.spawn(msg);

        Ok(())
    });

    // And finally now that we've define what our server is, we run it! We
    // didn't actually do much I/O up to this point and this `Core::run` method
    // is responsible for driving the entire server to completion.
    //
    // The `run` method will return the result of the future that it's running,
    // but in our case the `done` future won't ever finish because a TCP
    // listener is never done accepting clients. That basically just means that
    // we're going to be running the server until it's killed (e.g. ctrl-c).
    core.run(done).unwrap();
}
<commit_msg>change port to protocol port<commit_after>//! A chat server that broadcasts a message to all connections.
//!
//! This is a simple line-based server which accepts connections, reads lines
//! from those connections, and broadcasts the lines to all other connected
//! clients. In a sense this is a bit of a "poor man's chat server".
//!
//! You can test this out by running:
//!
//!     cargo run --example chat
//!
//! And then in another window run:
//!
//!     nc -4 localhost 8080
//!
//! You can run the second command in multiple windows and then chat between the
//! two, seeing the messages from the other client as they're received. For all
//! connected clients they'll all join the same room and see everyone else's
//! messages.

extern crate tokio_core;
extern crate futures;

use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::iter;
use std::env;
use std::io::{Error, ErrorKind, BufReader};

use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;
use tokio_core::io::{self, Io};

use futures::stream::{self, Stream};
use futures::Future;

fn main() {
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:1337".to_string());
    let addr = addr.parse().unwrap();

    // Create the event loop and TCP listener we'll accept connections on.
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let socket = TcpListener::bind(&addr, &handle).unwrap();
    println!("Listening on: {}", addr);

    // This is a single-threaded server, so we can just use Rc and RefCell to
    // store the map of all connections we know about.
    let connections = Rc::new(RefCell::new(HashMap::new()));

    let srv = socket.incoming().for_each(move |(stream, addr)| {
        println!("New Connection: {}", addr);
        let (reader, writer) = stream.split();

        // Create a channel for our stream, which other sockets will use to
        // send us messages. Then register our address with the stream to send
        // data to us.
        let (tx, rx) = futures::sync::mpsc::unbounded();
        connections.borrow_mut().insert(addr, tx);

        // Define here what we do for the actual I/O. That is, read a bunch of
        // lines from the socket and dispatch them while we also write any lines
        // from other sockets.
        let connections_inner = connections.clone();
        let reader = BufReader::new(reader);

        // Model the read portion of this socket by mapping an infinite
        // iterator to each line off the socket. This "loop" is then
        // terminated with an error once we hit EOF on the socket.
        let iter = stream::iter(iter::repeat(()).map(Ok::<(), Error>));
        let socket_reader = iter.fold(reader, move |reader, _| {
            // Read a line off the socket, failing if we're at EOF
            let line = io::read_until(reader, b'\n', Vec::new());
            let line = line.and_then(|(reader, vec)| {
                if vec.len() == 0 {
                    Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
                } else {
                    Ok((reader, vec))
                }
            });

            // Convert the bytes we read into a string, and then send that
            // string to all other connected clients.
            let line = line.map(|(reader, vec)| {
                (reader, String::from_utf8(vec))
            });
            let connections = connections_inner.clone();
            line.map(move |(reader, message)| {
                println!("{}: {:?}", addr, message);
                let mut conns = connections.borrow_mut();
                if let Ok(msg) = message {
                    // For each open connection except the sender, send the
                    // string via the channel.
                    let iter = conns.iter_mut()
                                    .filter(|&(&k, _)| k != addr)
                                    .map(|(_, v)| v);
                    for tx in iter {
                        tx.send(format!("{}: {}", addr, msg)).unwrap();
                    }
                } else {
                    let tx = conns.get_mut(&addr).unwrap();
                    tx.send("You didn't send valid UTF-8.".to_string()).unwrap();
                }
                reader
            })
        });

        // Whenever we receive a string on the Receiver, we write it to
        // `WriteHalf<TcpStream>`.
        let socket_writer = rx.fold(writer, |writer, msg| {
            let amt = io::write_all(writer, msg.into_bytes());
            let amt = amt.map(|(writer, _)| writer);
            amt.map_err(|_| ())
        });

        // Now that we've got futures representing each half of the socket, we
        // use the `select` combinator to wait for either half to be done to
        // tear down the other. Then we spawn off the result.
        let connections = connections.clone();
        let socket_reader = socket_reader.map_err(|_| ());
        let connection = socket_reader.map(|_| ()).select(socket_writer.map(|_| ()));
        handle.spawn(connection.then(move |_| {
            connections.borrow_mut().remove(&addr);
            println!("Connection {} closed.", addr);
            Ok(())
        }));

        Ok(())
    });

    // execute server
    core.run(srv).unwrap();
}
<|endoftext|>