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

<%! from data import to_rust_ident %>
<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import ALL_SIZES, PHYSICAL_SIDES, LOGICAL_SIDES %>

<% data.new_style_struct("Position", inherited=False) %>

// "top" / "left" / "bottom" / "right"
% for side in PHYSICAL_SIDES:
    ${helpers.predefined_type(side, "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
                              animatable=True)}
% endfor
// offset-* logical properties, map to "top" / "left" / "bottom" / "right"
% for side in LOGICAL_SIDES:
    ${helpers.predefined_type("offset-%s" % side, "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              spec="https://drafts.csswg.org/css-logical-props/#propdef-offset-%s" % side,
                              animatable=True, logical=True)}
% endfor

${helpers.predefined_type("z-index", "IntegerOrAuto",
                          "Either::Second(Auto)",
                          spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
                          creates_stacking_context=True,
                          animatable="True")}

// CSS Flexible Box Layout Module Level 1
// http://www.w3.org/TR/css3-flexbox/

// Flex container properties
${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse",
                         spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
                         extra_prefixes="webkit", animatable=False)}

${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
                         spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property",
                         extra_prefixes="webkit", animatable=False)}

% if product == "servo":
    // FIXME: Update Servo to support the same Syntax as Gecko.
    ${helpers.single_keyword("justify-content", "flex-start stretch flex-end center space-between space-around",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="justify-content",
                              type="AlignJustifyContent",
                              initial_value="specified::AlignJustifyContent::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                              extra_prefixes="webkit",
                              animatable=False)}
% endif

% if product == "servo":
    // FIXME: Update Servo to support the same Syntax as Gecko.
    ${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                             animatable=False)}

    ${helpers.single_keyword("align-items",
                             "stretch flex-start flex-end center baseline",
                             need_clone=True,
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="align-content",
                              type="AlignJustifyContent",
                              initial_value="specified::AlignJustifyContent::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="align-items",
                              type="AlignItems",
                              initial_value="specified::AlignItems::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-items",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="justify-items",
                              type="JustifyItems",
                              initial_value="specified::JustifyItems::auto()",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
                              animatable=False)}
% endif

// Flex item properties
${helpers.predefined_type("flex-grow", "Number",
                          "0.0", "parse_non_negative",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
                          extra_prefixes="webkit",
                          needs_context=False,
                          animatable=True)}

${helpers.predefined_type("flex-shrink", "Number",
                          "1.0", "parse_non_negative",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
                          extra_prefixes="webkit",
                          needs_context=False,
                          animatable=True)}

// https://drafts.csswg.org/css-align/#align-self-property
% if product == "servo":
    // FIXME: Update Servo to support the same syntax as Gecko.
    ${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline",
                             need_clone=True,
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="align-self",
                              type="AlignJustifySelf",
                              initial_value="specified::AlignJustifySelf::auto()",
                              spec="https://drafts.csswg.org/css-align/#align-self-property",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="justify-self",
                              type="AlignJustifySelf",
                              initial_value="specified::AlignJustifySelf::auto()",
                              spec="https://drafts.csswg.org/css-align/#justify-self-property",
                              animatable=False)}
% endif

// https://drafts.csswg.org/css-flexbox/#propdef-order
${helpers.predefined_type("order", "Integer", "0",
                          animatable=True,
                          spec="https://drafts.csswg.org/css-flexbox/#order-property")}

// FIXME: Gecko doesn't support content value yet.
// FIXME: This property should be animatable.
${helpers.predefined_type("flex-basis",
                          "LengthOrPercentageOrAuto" if product == "gecko" else
                          "LengthOrPercentageOrAutoOrContent",
                          "computed::LengthOrPercentageOrAuto::Auto" if product == "gecko" else
                          "computed::LengthOrPercentageOrAutoOrContent::Auto",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
                          extra_prefixes="webkit",
                          animatable=True if product == "gecko" else False)}

% for (size, logical) in ALL_SIZES:
    <%
      spec = "https://drafts.csswg.org/css-box/#propdef-%s"
      if logical:
        spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s"
    %>
    // width, height, block-size, inline-size
    ${helpers.predefined_type("%s" % size,
                              "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              "parse_non_negative",
                              needs_context=False,
                              spec=spec % size,
                              animatable=True, logical = logical)}
    % if product == "gecko":
        % for min_max in ["min", "max"]:
            <%
                MinMax = min_max.title()
                initial = "None" if "max" == min_max else "Auto"
            %>

            // min-width, min-height, min-block-size, min-inline-size,
            // max-width, max-height, max-block-size, max-inline-size
            //
            // Keyword values are only valid in the inline direction; they must
            // be replaced with auto/none in block.
            <%helpers:longhand name="${min_max}-${size}" spec="${spec % ('%s-%s' % (min_max, size))}"
                               animatable="True" logical="${logical}" predefined_type="${MinMax}Length">

                use std::fmt;
                use style_traits::ToCss;
                use values::HasViewportPercentage;
                use values::specified::${MinMax}Length;

                impl HasViewportPercentage for SpecifiedValue {
                    fn has_viewport_percentage(&self) -> bool {
                        self.0.has_viewport_percentage()
                    }
                }

                pub mod computed_value {
                    pub type T = ::values::computed::${MinMax}Length;
                }

                #[derive(PartialEq, Clone, Debug)]
                #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
                pub struct SpecifiedValue(${MinMax}Length);

                #[inline]
                pub fn get_initial_value() -> computed_value::T {
                    use values::computed::${MinMax}Length;
                    ${MinMax}Length::${initial}
                }
                fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
                    ${MinMax}Length::parse(context, input).map(SpecifiedValue)
                }

                impl ToCss for SpecifiedValue {
                    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                        self.0.to_css(dest)
                    }
                }

                impl ToComputedValue for SpecifiedValue {
                    type ComputedValue = computed_value::T;
                    #[inline]
                    fn to_computed_value(&self, context: &Context) -> computed_value::T {
                        use values::computed::${MinMax}Length;
                        let computed = self.0.to_computed_value(context);

                        // filter out keyword values in the block direction
                        % if logical:
                            % if "block" in size:
                                if let ${MinMax}Length::ExtremumLength(..) = computed {
                                    return get_initial_value()
                                }
                            % endif
                        % else:
                            if let ${MinMax}Length::ExtremumLength(..) = computed {
                                <% is_height = "true" if "height" in size else "false" %>
                                if ${is_height} != context.style().writing_mode.is_vertical() {
                                    return get_initial_value()
                                }
                            }
                        % endif
                        computed
                    }

                    #[inline]
                    fn from_computed_value(computed: &computed_value::T) -> Self {
                        SpecifiedValue(ToComputedValue::from_computed_value(computed))
                    }
                }
            </%helpers:longhand>
        % endfor
    % else:
        // servo versions (no keyword support)
        ${helpers.predefined_type("min-%s" % size,
                                  "LengthOrPercentage",
                                  "computed::LengthOrPercentage::Length(Au(0))",
                                  "parse_non_negative",
                                  needs_context=False,
                                  spec=spec % ("min-%s" % size),
                                  animatable=True, logical = logical)}
        ${helpers.predefined_type("max-%s" % size,
                                  "LengthOrPercentageOrNone",
                                  "computed::LengthOrPercentageOrNone::None",
                                  "parse_non_negative",
                                  needs_context=False,
                                  spec=spec % ("min-%s" % size),
                                  animatable=True, logical = logical)}
    % endif
% endfor

${helpers.single_keyword("box-sizing",
                         "content-box border-box",
                         extra_prefixes="moz webkit",
                         spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
                         animatable=False)}

${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
                         products="gecko", animatable=False,
                         spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}

${helpers.predefined_type("object-position",
                          "Position",
                          "computed::Position::zero()",
                          products="gecko",
                          boxed="True",
                          spec="https://drafts.csswg.org/css-images-3/#the-object-position",
                          animatable=True)}

% for kind in ["row", "column"]:
    ${helpers.predefined_type("grid-%s-gap" % kind,
                              "LengthOrPercentage",
                              "computed::LengthOrPercentage::Length(Au(0))",
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
                              animatable=True,
                              products="gecko")}

    % for range in ["start", "end"]:
        ${helpers.predefined_type("grid-%s-%s" % (kind, range),
                                  "GridLine",
                                  "Default::default()",
                                  animatable=False,
                                  spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
                                  products="gecko",
                                  boxed=True)}
    % endfor

    // NOTE: According to the spec, this should handle multiple values of `<track-size>`,
    // but gecko supports only a single value
    ${helpers.predefined_type("grid-auto-%ss" % kind,
                              "TrackSize",
                              "Default::default()",
                              animatable=False,
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                              products="gecko",
                              boxed=True)}
% endfor

<%helpers:longhand name="grid-auto-flow"
        spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow"
        products="gecko"
        animatable="False">
    use std::fmt;
    use style_traits::ToCss;
    use values::HasViewportPercentage;
    use values::computed::ComputedValueAsSpecified;

    pub type SpecifiedValue = computed_value::T;

    pub mod computed_value {
        #[derive(PartialEq, Clone, Eq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum AutoFlow {
            Row,
            Column,
        }

        #[derive(PartialEq, Clone, Eq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T {
            pub autoflow: AutoFlow,
            pub dense: bool,
        }
    }

    no_viewport_percentage!(SpecifiedValue);
    impl ComputedValueAsSpecified for SpecifiedValue {}

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            dest.write_str(match self.autoflow {
                computed_value::AutoFlow::Column => "column",
                computed_value::AutoFlow::Row => "row"
            })?;

            if self.dense { dest.write_str(" dense")?; }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            autoflow: computed_value::AutoFlow::Row,
            dense: false
        }
    }

    /// [ row | column ] || dense
    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        use self::computed_value::AutoFlow;

        let mut value = None;
        let mut dense = false;

        while !input.is_exhausted() {
            match_ignore_ascii_case! { &input.expect_ident()?,
                "row" if value.is_none() => {
                    value = Some(AutoFlow::Row);
                    continue
                },
                "column" if value.is_none() => {
                    value = Some(AutoFlow::Column);
                    continue
                },
                "dense" if !dense => {
                    dense = true;
                    continue
                },
                _ => return Err(())
            }
        }

        if value.is_some() || dense {
            Ok(computed_value::T {
                autoflow: value.unwrap_or(AutoFlow::Row),
                dense: dense,
            })
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<commit_msg>Auto merge of #16151 - emilio:fixup-webkit-order, r=emilio<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%! from data import to_rust_ident %>
<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import ALL_SIZES, PHYSICAL_SIDES, LOGICAL_SIDES %>

<% data.new_style_struct("Position", inherited=False) %>

// "top" / "left" / "bottom" / "right"
% for side in PHYSICAL_SIDES:
    ${helpers.predefined_type(side, "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
                              animatable=True)}
% endfor
// offset-* logical properties, map to "top" / "left" / "bottom" / "right"
% for side in LOGICAL_SIDES:
    ${helpers.predefined_type("offset-%s" % side, "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              spec="https://drafts.csswg.org/css-logical-props/#propdef-offset-%s" % side,
                              animatable=True, logical=True)}
% endfor

${helpers.predefined_type("z-index", "IntegerOrAuto",
                          "Either::Second(Auto)",
                          spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
                          creates_stacking_context=True,
                          animatable="True")}

// CSS Flexible Box Layout Module Level 1
// http://www.w3.org/TR/css3-flexbox/

// Flex container properties
${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse",
                         spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
                         extra_prefixes="webkit", animatable=False)}

${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
                         spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property",
                         extra_prefixes="webkit", animatable=False)}

% if product == "servo":
    // FIXME: Update Servo to support the same Syntax as Gecko.
    ${helpers.single_keyword("justify-content", "flex-start stretch flex-end center space-between space-around",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="justify-content",
                              type="AlignJustifyContent",
                              initial_value="specified::AlignJustifyContent::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                              extra_prefixes="webkit",
                              animatable=False)}
% endif

% if product == "servo":
    // FIXME: Update Servo to support the same Syntax as Gecko.
    ${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                             animatable=False)}

    ${helpers.single_keyword("align-items",
                             "stretch flex-start flex-end center baseline",
                             need_clone=True,
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="align-content",
                              type="AlignJustifyContent",
                              initial_value="specified::AlignJustifyContent::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="align-items",
                              type="AlignItems",
                              initial_value="specified::AlignItems::normal()",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-items",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="justify-items",
                              type="JustifyItems",
                              initial_value="specified::JustifyItems::auto()",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
                              animatable=False)}
% endif

// Flex item properties
${helpers.predefined_type("flex-grow", "Number",
                          "0.0", "parse_non_negative",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
                          extra_prefixes="webkit",
                          needs_context=False,
                          animatable=True)}

${helpers.predefined_type("flex-shrink", "Number",
                          "1.0", "parse_non_negative",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
                          extra_prefixes="webkit",
                          needs_context=False,
                          animatable=True)}

// https://drafts.csswg.org/css-align/#align-self-property
% if product == "servo":
    // FIXME: Update Servo to support the same syntax as Gecko.
    ${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline",
                             need_clone=True,
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
                             animatable=False)}
% else:
    ${helpers.predefined_type(name="align-self",
                              type="AlignJustifySelf",
                              initial_value="specified::AlignJustifySelf::auto()",
                              spec="https://drafts.csswg.org/css-align/#align-self-property",
                              extra_prefixes="webkit",
                              animatable=False)}

    ${helpers.predefined_type(name="justify-self",
                              type="AlignJustifySelf",
                              initial_value="specified::AlignJustifySelf::auto()",
                              spec="https://drafts.csswg.org/css-align/#justify-self-property",
                              animatable=False)}
% endif

// https://drafts.csswg.org/css-flexbox/#propdef-order
${helpers.predefined_type("order", "Integer", "0",
                          extra_prefixes="webkit",
                          animatable=True,
                          spec="https://drafts.csswg.org/css-flexbox/#order-property")}

// FIXME: Gecko doesn't support content value yet.
// FIXME: This property should be animatable.
${helpers.predefined_type("flex-basis",
                          "LengthOrPercentageOrAuto" if product == "gecko" else
                          "LengthOrPercentageOrAutoOrContent",
                          "computed::LengthOrPercentageOrAuto::Auto" if product == "gecko" else
                          "computed::LengthOrPercentageOrAutoOrContent::Auto",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
                          extra_prefixes="webkit",
                          animatable=True if product == "gecko" else False)}

% for (size, logical) in ALL_SIZES:
    <%
      spec = "https://drafts.csswg.org/css-box/#propdef-%s"
      if logical:
        spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s"
    %>
    // width, height, block-size, inline-size
    ${helpers.predefined_type("%s" % size,
                              "LengthOrPercentageOrAuto",
                              "computed::LengthOrPercentageOrAuto::Auto",
                              "parse_non_negative",
                              needs_context=False,
                              spec=spec % size,
                              animatable=True, logical = logical)}
    % if product == "gecko":
        % for min_max in ["min", "max"]:
            <%
                MinMax = min_max.title()
                initial = "None" if "max" == min_max else "Auto"
            %>

            // min-width, min-height, min-block-size, min-inline-size,
            // max-width, max-height, max-block-size, max-inline-size
            //
            // Keyword values are only valid in the inline direction; they must
            // be replaced with auto/none in block.
            <%helpers:longhand name="${min_max}-${size}" spec="${spec % ('%s-%s' % (min_max, size))}"
                               animatable="True" logical="${logical}" predefined_type="${MinMax}Length">

                use std::fmt;
                use style_traits::ToCss;
                use values::HasViewportPercentage;
                use values::specified::${MinMax}Length;

                impl HasViewportPercentage for SpecifiedValue {
                    fn has_viewport_percentage(&self) -> bool {
                        self.0.has_viewport_percentage()
                    }
                }

                pub mod computed_value {
                    pub type T = ::values::computed::${MinMax}Length;
                }

                #[derive(PartialEq, Clone, Debug)]
                #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
                pub struct SpecifiedValue(${MinMax}Length);

                #[inline]
                pub fn get_initial_value() -> computed_value::T {
                    use values::computed::${MinMax}Length;
                    ${MinMax}Length::${initial}
                }
                fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
                    ${MinMax}Length::parse(context, input).map(SpecifiedValue)
                }

                impl ToCss for SpecifiedValue {
                    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                        self.0.to_css(dest)
                    }
                }

                impl ToComputedValue for SpecifiedValue {
                    type ComputedValue = computed_value::T;
                    #[inline]
                    fn to_computed_value(&self, context: &Context) -> computed_value::T {
                        use values::computed::${MinMax}Length;
                        let computed = self.0.to_computed_value(context);

                        // filter out keyword values in the block direction
                        % if logical:
                            % if "block" in size:
                                if let ${MinMax}Length::ExtremumLength(..) = computed {
                                    return get_initial_value()
                                }
                            % endif
                        % else:
                            if let ${MinMax}Length::ExtremumLength(..) = computed {
                                <% is_height = "true" if "height" in size else "false" %>
                                if ${is_height} != context.style().writing_mode.is_vertical() {
                                    return get_initial_value()
                                }
                            }
                        % endif
                        computed
                    }

                    #[inline]
                    fn from_computed_value(computed: &computed_value::T) -> Self {
                        SpecifiedValue(ToComputedValue::from_computed_value(computed))
                    }
                }
            </%helpers:longhand>
        % endfor
    % else:
        // servo versions (no keyword support)
        ${helpers.predefined_type("min-%s" % size,
                                  "LengthOrPercentage",
                                  "computed::LengthOrPercentage::Length(Au(0))",
                                  "parse_non_negative",
                                  needs_context=False,
                                  spec=spec % ("min-%s" % size),
                                  animatable=True, logical = logical)}
        ${helpers.predefined_type("max-%s" % size,
                                  "LengthOrPercentageOrNone",
                                  "computed::LengthOrPercentageOrNone::None",
                                  "parse_non_negative",
                                  needs_context=False,
                                  spec=spec % ("min-%s" % size),
                                  animatable=True, logical = logical)}
    % endif
% endfor

${helpers.single_keyword("box-sizing",
                         "content-box border-box",
                         extra_prefixes="moz webkit",
                         spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
                         animatable=False)}

${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
                         products="gecko", animatable=False,
                         spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}

${helpers.predefined_type("object-position",
                          "Position",
                          "computed::Position::zero()",
                          products="gecko",
                          boxed="True",
                          spec="https://drafts.csswg.org/css-images-3/#the-object-position",
                          animatable=True)}

% for kind in ["row", "column"]:
    ${helpers.predefined_type("grid-%s-gap" % kind,
                              "LengthOrPercentage",
                              "computed::LengthOrPercentage::Length(Au(0))",
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-gap" % kind,
                              animatable=True,
                              products="gecko")}

    % for range in ["start", "end"]:
        ${helpers.predefined_type("grid-%s-%s" % (kind, range),
                                  "GridLine",
                                  "Default::default()",
                                  animatable=False,
                                  spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
                                  products="gecko",
                                  boxed=True)}
    % endfor

    // NOTE: According to the spec, this should handle multiple values of `<track-size>`,
    // but gecko supports only a single value
    ${helpers.predefined_type("grid-auto-%ss" % kind,
                              "TrackSize",
                              "Default::default()",
                              animatable=False,
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                              products="gecko",
                              boxed=True)}
% endfor

<%helpers:longhand name="grid-auto-flow"
        spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow"
        products="gecko"
        animatable="False">
    use std::fmt;
    use style_traits::ToCss;
    use values::HasViewportPercentage;
    use values::computed::ComputedValueAsSpecified;

    pub type SpecifiedValue = computed_value::T;

    pub mod computed_value {
        #[derive(PartialEq, Clone, Eq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum AutoFlow {
            Row,
            Column,
        }

        #[derive(PartialEq, Clone, Eq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T {
            pub autoflow: AutoFlow,
            pub dense: bool,
        }
    }

    no_viewport_percentage!(SpecifiedValue);
    impl ComputedValueAsSpecified for SpecifiedValue {}

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            dest.write_str(match self.autoflow {
                computed_value::AutoFlow::Column => "column",
                computed_value::AutoFlow::Row => "row"
            })?;

            if self.dense { dest.write_str(" dense")?; }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            autoflow: computed_value::AutoFlow::Row,
            dense: false
        }
    }

    /// [ row | column ] || dense
    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        use self::computed_value::AutoFlow;

        let mut value = None;
        let mut dense = false;

        while !input.is_exhausted() {
            match_ignore_ascii_case! { &input.expect_ident()?,
                "row" if value.is_none() => {
                    value = Some(AutoFlow::Row);
                    continue
                },
                "column" if value.is_none() => {
                    value = Some(AutoFlow::Column);
                    continue
                },
                "dense" if !dense => {
                    dense = true;
                    continue
                },
                _ => return Err(())
            }
        }

        if value.is_some() || dense {
            Ok(computed_value::T {
                autoflow: value.unwrap_or(AutoFlow::Row),
                dense: dense,
            })
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="outline" sub_properties="outline-color outline-style outline-width"
                    spec="https://drafts.csswg.org/css-ui/#propdef-outline">
    use properties::longhands::{outline_color, outline_width, outline_style};
    use values::specified;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let _unused = context;
        let mut color = None;
        let mut style = None;
        let mut width = None;
        let mut any = false;
        loop {
            if color.is_none() {
                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                    color = Some(value);
                    any = true;
                    continue
                }
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| outline_style::parse(context, input)) {
                    style = Some(value);
                    any = true;
                    continue
                }
            }
            if width.is_none() {
                if let Ok(value) = input.try(|input| outline_width::parse(context, input)) {
                    width = Some(value);
                    any = true;
                    continue
                }
            }
            break
        }
        if any {
            Ok(Longhands {
                outline_color: unwrap_or_initial!(outline_color, color),
                outline_style: unwrap_or_initial!(outline_style, style),
                outline_width: unwrap_or_initial!(outline_width, width),
            })
        } else {
            Err(())
        }
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.outline_width.to_css(dest));
            try!(write!(dest, " "));
            try!(self.outline_style.to_css(dest));
            try!(write!(dest, " "));
            self.outline_color.to_css(dest)
        }
    }
</%helpers:shorthand>

// The -moz-outline-radius shorthand is non-standard and not on a standards track.
<%helpers:shorthand name="-moz-outline-radius" sub_properties="${' '.join(
    '-moz-outline-radius-%s' % corner
    for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
)}" products="gecko" spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)">
    use properties::shorthands;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        // Re-use border-radius parsing.
        shorthands::border_radius::parse_value(context, input).map(|longhands| {
            Longhands {
                % for corner in ["top_left", "top_right", "bottom_right", "bottom_left"]:
                _moz_outline_radius_${corner.replace("_", "")}: longhands.border_${corner}_radius,
                % endfor
            }
        })
    }

    // TODO: Border radius for the radius shorthand is not implemented correctly yet
    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self._moz_outline_radius_topleft.to_css(dest));
            try!(write!(dest, " "));

            try!(self._moz_outline_radius_topright.to_css(dest));
            try!(write!(dest, " "));

            try!(self._moz_outline_radius_bottomright.to_css(dest));
            try!(write!(dest, " "));

            self._moz_outline_radius_bottomleft.to_css(dest)
        }
    }
</%helpers:shorthand>
<commit_msg>Fix serialization for -moz-outline-radius<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="outline" sub_properties="outline-color outline-style outline-width"
                    spec="https://drafts.csswg.org/css-ui/#propdef-outline">
    use properties::longhands::{outline_color, outline_width, outline_style};
    use values::specified;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let _unused = context;
        let mut color = None;
        let mut style = None;
        let mut width = None;
        let mut any = false;
        loop {
            if color.is_none() {
                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                    color = Some(value);
                    any = true;
                    continue
                }
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| outline_style::parse(context, input)) {
                    style = Some(value);
                    any = true;
                    continue
                }
            }
            if width.is_none() {
                if let Ok(value) = input.try(|input| outline_width::parse(context, input)) {
                    width = Some(value);
                    any = true;
                    continue
                }
            }
            break
        }
        if any {
            Ok(Longhands {
                outline_color: unwrap_or_initial!(outline_color, color),
                outline_style: unwrap_or_initial!(outline_style, style),
                outline_width: unwrap_or_initial!(outline_width, width),
            })
        } else {
            Err(())
        }
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.outline_width.to_css(dest));
            try!(write!(dest, " "));
            try!(self.outline_style.to_css(dest));
            try!(write!(dest, " "));
            self.outline_color.to_css(dest)
        }
    }
</%helpers:shorthand>

// The -moz-outline-radius shorthand is non-standard and not on a standards track.
<%helpers:shorthand name="-moz-outline-radius" sub_properties="${' '.join(
    '-moz-outline-radius-%s' % corner
    for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
)}" products="gecko" spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)">
    use properties::shorthands;
    use values::specified::basic_shape::serialize_radius_values;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        // Re-use border-radius parsing.
        shorthands::border_radius::parse_value(context, input).map(|longhands| {
            Longhands {
                % for corner in ["top_left", "top_right", "bottom_right", "bottom_left"]:
                _moz_outline_radius_${corner.replace("_", "")}: longhands.border_${corner}_radius,
                % endfor
            }
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            serialize_radius_values(dest,
                &self._moz_outline_radius_topleft.0,
                &self._moz_outline_radius_topright.0,
                &self._moz_outline_radius_bottomright.0,
                &self._moz_outline_radius_bottomleft.0,
            )
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>extern crate rand;

use rand::Rng;

use std::net::SocketAddr;

use messages::{Any, RawMessage, Connect, Status, Message, RequestPeers};
use events::Channel;
use super::{NodeHandler, RequestData, ExternalMessage, NodeTimeout};

impl<S> NodeHandler<S>
    where S: Channel<ApplicationEvent = ExternalMessage, Timeout = NodeTimeout>
{
    pub fn handle_message(&mut self, raw: RawMessage) {
        // TODO: check message headers (network id, protocol version)
        // FIXME: call message.verify method
        //     if !raw.verify() {
        //         return;
        //     }

        //FIXME: add whitelist verify public_key

        let msg = Any::from_raw(raw).unwrap();
        match msg {
            Any::Connect(msg) => self.handle_connect(msg),
            Any::Status(msg) => self.handle_status(msg),
            Any::Consensus(msg) => self.handle_consensus(msg),
            Any::Request(msg) => self.handle_request(msg),
            Any::Block(msg) => self.handle_block(msg),
            Any::Transaction(msg) => self.handle_tx(msg),
        }
    }

    pub fn handle_connected(&mut self, addr: &SocketAddr) {
        info!("Connected to: {}", addr);
        let message = self.state.our_connect_message().clone();
        self.send_to_addr(addr, message.raw());
    }

    pub fn handle_disconnected(&mut self, addr: &SocketAddr) {
        info!("Disconnected from: {}", addr);
        let need_reconnect = self.state.remove_peer_with_addr(addr);
        if need_reconnect {
            self.connect(addr);
        }
    }

    pub fn handle_connect(&mut self, message: Connect) {
        // TODO add spam protection
        let address = message.addr();
        if address == self.state.our_connect_message().addr() {
            return;
        }
        // Check if we have another connect message from peer with the given public_key
        let public_key = *message.pub_key();
        let mut need_connect = true;
        if let Some(saved_message) = self.state.peers().get(&public_key) {
            if saved_message.time() > message.time() {
                error!("Received outdated Connect message from {}", address);
                return;
            } else if saved_message.time() < message.time() {
                need_connect = saved_message.addr() != message.addr();
            } else if saved_message.addr() != message.addr() {
                error!("Received weird Connect message from {}", address);
                return;
            }
        }
        info!("Received Connect message from {}, {}",
              address,
              need_connect);
        self.state.add_peer(public_key, message);
        if need_connect {
            // TODO: reduce double sending of connect message
            info!("Send Connect message to {}", address);
            self.connect(&address);
        }
    }

    pub fn handle_status(&mut self, msg: Status) {
        let height = self.state.height();
        trace!("HANDLE STATUS: current height = {}, msg height = {}", height, msg.height());

        // Handle message from future height
        if msg.height() > height {
            let peer = msg.from();

            //verify message
            if !msg.verify_signature(peer) {
                return;
            }

            // Check validator height info
            if msg.height() > self.state.node_height(peer) {
                // Update validator height
                self.state.set_node_height(*peer, msg.height());
            }

            // Request block
            self.request(RequestData::Block(height), *peer);
        }
    }

    pub fn handle_request_peers(&mut self, msg: RequestPeers) {
        let peers: Vec<Connect> = self.state.peers().iter().map(|(_, b)| b.clone()).collect();
        debug!("HANDLE REQUEST PEERS: Sending {:?} peers to {:?}", peers, msg.from());

        for peer in peers {
            self.send_to_peer(*msg.from(), peer.raw());
        }
    }

    pub fn handle_status_timeout(&mut self) {
        let hash = self.blockchain.last_hash().unwrap();
        // Send status
        let status = Status::new(self.state.public_key(),
                                 self.state.height(),
                                 &hash,
                                 self.state.secret_key());
        trace!("Broadcast status: {:?}", status);
        self.broadcast(status.raw());

        self.add_status_timeout();
    }

    pub fn handle_peer_exchange_timeout(&mut self) {
        if !self.state.peers().is_empty() {
            let to = self.state.peers().len();
            let gen_peer_id = || -> usize {
                let mut rng = rand::thread_rng();
                rng.gen_range(0, to)
            };

            let peer = self.state
                .peers()
                .iter()
                .map(|x| x.1.clone())
                .nth(gen_peer_id())
                .unwrap();
            let peer = peer.clone();
            let msg = RequestPeers::new(self.state.public_key(),
                                        peer.pub_key(),
                                        self.state.secret_key());
            trace!("Request peers from peer with addr {:?}", peer.addr());
            self.send_to_peer(*peer.pub_key(), msg.raw());
        }
        self.add_peer_exchange_timeout();
    }
}
<commit_msg>Replace debug by trace<commit_after>extern crate rand;

use rand::Rng;

use std::net::SocketAddr;

use messages::{Any, RawMessage, Connect, Status, Message, RequestPeers};
use events::Channel;
use super::{NodeHandler, RequestData, ExternalMessage, NodeTimeout};

impl<S> NodeHandler<S>
    where S: Channel<ApplicationEvent = ExternalMessage, Timeout = NodeTimeout>
{
    pub fn handle_message(&mut self, raw: RawMessage) {
        // TODO: check message headers (network id, protocol version)
        // FIXME: call message.verify method
        //     if !raw.verify() {
        //         return;
        //     }

        //FIXME: add whitelist verify public_key

        let msg = Any::from_raw(raw).unwrap();
        match msg {
            Any::Connect(msg) => self.handle_connect(msg),
            Any::Status(msg) => self.handle_status(msg),
            Any::Consensus(msg) => self.handle_consensus(msg),
            Any::Request(msg) => self.handle_request(msg),
            Any::Block(msg) => self.handle_block(msg),
            Any::Transaction(msg) => self.handle_tx(msg),
        }
    }

    pub fn handle_connected(&mut self, addr: &SocketAddr) {
        info!("Connected to: {}", addr);
        let message = self.state.our_connect_message().clone();
        self.send_to_addr(addr, message.raw());
    }

    pub fn handle_disconnected(&mut self, addr: &SocketAddr) {
        info!("Disconnected from: {}", addr);
        let need_reconnect = self.state.remove_peer_with_addr(addr);
        if need_reconnect {
            self.connect(addr);
        }
    }

    pub fn handle_connect(&mut self, message: Connect) {
        // TODO add spam protection
        let address = message.addr();
        if address == self.state.our_connect_message().addr() {
            return;
        }
        // Check if we have another connect message from peer with the given public_key
        let public_key = *message.pub_key();
        let mut need_connect = true;
        if let Some(saved_message) = self.state.peers().get(&public_key) {
            if saved_message.time() > message.time() {
                error!("Received outdated Connect message from {}", address);
                return;
            } else if saved_message.time() < message.time() {
                need_connect = saved_message.addr() != message.addr();
            } else if saved_message.addr() != message.addr() {
                error!("Received weird Connect message from {}", address);
                return;
            }
        }
        info!("Received Connect message from {}, {}",
              address,
              need_connect);
        self.state.add_peer(public_key, message);
        if need_connect {
            // TODO: reduce double sending of connect message
            info!("Send Connect message to {}", address);
            self.connect(&address);
        }
    }

    pub fn handle_status(&mut self, msg: Status) {
        let height = self.state.height();
        trace!("HANDLE STATUS: current height = {}, msg height = {}", height, msg.height());

        // Handle message from future height
        if msg.height() > height {
            let peer = msg.from();

            //verify message
            if !msg.verify_signature(peer) {
                return;
            }

            // Check validator height info
            if msg.height() > self.state.node_height(peer) {
                // Update validator height
                self.state.set_node_height(*peer, msg.height());
            }

            // Request block
            self.request(RequestData::Block(height), *peer);
        }
    }

    pub fn handle_request_peers(&mut self, msg: RequestPeers) {
        let peers: Vec<Connect> = self.state.peers().iter().map(|(_, b)| b.clone()).collect();
        trace!("HANDLE REQUEST PEERS: Sending {:?} peers to {:?}", peers, msg.from());

        for peer in peers {
            self.send_to_peer(*msg.from(), peer.raw());
        }
    }

    pub fn handle_status_timeout(&mut self) {
        let hash = self.blockchain.last_hash().unwrap();
        // Send status
        let status = Status::new(self.state.public_key(),
                                 self.state.height(),
                                 &hash,
                                 self.state.secret_key());
        trace!("Broadcast status: {:?}", status);
        self.broadcast(status.raw());

        self.add_status_timeout();
    }

    pub fn handle_peer_exchange_timeout(&mut self) {
        if !self.state.peers().is_empty() {
            let to = self.state.peers().len();
            let gen_peer_id = || -> usize {
                let mut rng = rand::thread_rng();
                rng.gen_range(0, to)
            };

            let peer = self.state
                .peers()
                .iter()
                .map(|x| x.1.clone())
                .nth(gen_peer_id())
                .unwrap();
            let peer = peer.clone();
            let msg = RequestPeers::new(self.state.public_key(),
                                        peer.pub_key(),
                                        self.state.secret_key());
            trace!("Request peers from peer with addr {:?}", peer.addr());
            self.send_to_peer(*peer.pub_key(), msg.raw());
        }
        self.add_peer_exchange_timeout();
    }
}
<|endoftext|>


<commit_before>//! Module containing font changing tools.
//!
//! # Examples
//! The following from [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management):
//!
//! ```text
//! font: UbuntuMono-R.ttf, size=12;
//! 0x5E: curcumflex.png;
//! 0xE000: tileset.png, size=16x16, spacing=2x1;
//! ```
//!
//! Is equivalent to
//!
//! ```
//! use bear_lib_terminal::terminal;
//! use bear_lib_terminal::terminal::config::font;
//! use bear_lib_terminal::geometry::Size;
//! # assert!({let result =
//! terminal::set(font::true_type(font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('^'), "circumflex.png"));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! # result});
//! ```

use std::fmt;
use std::path::Path;
use geometry::Size;
use terminal::config::{ConfigPart, escape_config_string};

/// Construct a bitmap font override segment repr.
pub fn bitmap<T: AsRef<Path>>(origin: Origin, path: T) -> Bitmap {
	Bitmap{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: None,
		resize: None,
		resize_filter: None,
		resize_mode: None,
		raw_size: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// Construct a TrueType font override segment repr.
///
/// If `title_size.width` is `0`, the resulting `size` prop will be `size=<title_size.width>` as opposed to `size=<title_size>`.
pub fn true_type<T: AsRef<Path>>(origin: Origin, path: T, tile_size: Size) -> TrueType {
	TrueType{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: tile_size,
		size_reference: None,
		mode: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// The origin for the font (the part before `:` in the config string).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Origin {
	/// `font`
	Root,
	/// `named font`
	Named(String),
	/// `0xNNNN`
	Offset(char),
}

/// Rasterization mode for TrueType fonts.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum RasterizationMode {
	Monochrome,
	Normal,
	/// Forces an opaque black background.
	Lcd,
}

/// Resizing filter for bitmaps.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeFilter {
	Nearest,
	Bilinear,
	Bicubic,
}

/// How to aspect-change when resizing a bitmap.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeMode {
	Stretch,
	Fit,
	Crop,
}

/// Per-tileset tile alignment.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Align {
	Center,
	TopLeft,
	BottomLeft,
	TopRight,
	BottomRight,
}

// What's the format for this?
// ref: http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management
// pub enum Background {
// 	Auto,
// 	Color(Color),
// }

/// A bitmap font override segment repr, constructed with [`bitmap()`](fn.bitmap.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Bitmap {
	origin       : Origin,
	path         : String,
	size         : Option<Size>,
	resize       : Option<Size>,
	resize_filter: Option<ResizeFilter>,
	resize_mode  : Option<ResizeMode>,
	raw_size     : Option<Size>,
	codepage     : Option<String>,
	align        : Option<Align>,
	spacing      : Option<Size>,
//	transparent  : Option<Background>,
}

/// A TrueType font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TrueType {
	origin        : Origin,
	path          : String,
	size          : Size,
	size_reference: Option<char>,
	mode          : Option<RasterizationMode>,
	codepage      : Option<String>,
	align         : Option<Align>,
	spacing       : Option<Size>,
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl Bitmap {
	/// The size of a single tile in the tileset.
	pub fn size         (mut self, size: Size)                  -> Self {self.size          = Some(size)         ; self}

	/// The size to resize the image to.
	pub fn resize       (mut self, resize: Size)                -> Self {self.resize        = Some(resize)       ; self}

	/// How to resize the image.
	///
	/// Default: `ResizeFilter::Bilinear`.
	pub fn resize_filter(mut self, resize_filter: ResizeFilter) -> Self {self.resize_filter = Some(resize_filter); self}

	/// Resize aspect method.
	///
	/// Default: `ResizeMode::Stretch`.
	pub fn resize_mode  (mut self, resize_mode: ResizeMode)     -> Self {self.resize_mode   = Some(resize_mode)  ; self}

	/// Raw memory size, `size` if not specified.
	pub fn raw_size     (mut self, raw_size: Size)              -> Self {self.raw_size      = Some(raw_size)     ; self}

	/// Tileset's codepage.
	///
	/// Default: `"ascii"`.
	pub fn codepage     (mut self, codepage: String)            -> Self {self.codepage      = Some(codepage)     ; self}

	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align        (mut self, align: Align)                -> Self {self.align         = Some(align)        ; self}

	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing      (mut self, spacing: Size)               -> Self {self.spacing       = Some(spacing)      ; self}
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl TrueType {
	/// Character used for size probing.
	///
	/// Default: `'@'`.
	pub fn size_reference(mut self, size_reference: char)    -> Self {self.size_reference = Some(size_reference); self}

	/// Rasterization mode. Note: `RasterizationMode::Lcd` forces opaque black background.
	///
	/// Default: `RasterizationMode::Normal`.
	pub fn mode          (mut self, mode: RasterizationMode) -> Self {self.mode           = Some(mode)          ; self}

	/// Reverse codepage for loading symbols.
	pub fn codepage      (mut self, codepage: String)        -> Self {self.codepage       = Some(codepage)      ; self}

	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align         (mut self, align: Align)            -> Self {self.align          = Some(align)         ; self}

	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing       (mut self, spacing: Size)           -> Self {self.spacing        = Some(spacing)       ; self}
}

impl ConfigPart for Bitmap {
	fn to_config_str(&self) -> String {
		format!("{}: {}{}{}{}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				None           => "".to_string(),
				Some(ref size) => format!(", size={}", size),
			},
			match self.resize {
				None             => "".to_string(),
				Some(ref resize) => format!(", resize={}", resize),
			},
			match self.resize_filter {
				None                    => "".to_string(),
				Some(ref resize_filter) => format!(", resize-filter={}", resize_filter),
			},
			match self.resize_mode {
				None                  => "".to_string(),
				Some(ref resize_mode) => format!(", resize-mode={}", resize_mode),
			},
			match self.raw_size {
				None               => "".to_string(),
				Some(ref raw_size) => format!(", raw-size={}", raw_size),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl ConfigPart for TrueType {
	fn to_config_str(&self) -> String {
		format!("{}: {}, size={}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				Size{width: 0, height} => format!("{}", height),
				size                   => format!("{}", size),
			},
			match self.size_reference {
				None                     => "".to_string(),
				Some(ref size_reference) => format!(", size-reference=0x{:X}", *size_reference as i32),
			},
			match self.mode {
				None           => "".to_string(),
				Some(ref mode) => format!(", mode={}", mode),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl fmt::Display for Origin {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Origin::Root      => formatter.write_str("font"),
			&Origin::Named(n)  => formatter.write_str("{} font", &n),
			&Origin::Offset(o) => formatter.write_str(&*&format!("0x{:X}", o as i32)),
		}
	}
}

impl fmt::Display for RasterizationMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&RasterizationMode::Monochrome => formatter.write_str("monochrome"),
			&RasterizationMode::Normal     => formatter.write_str("normal"),
			&RasterizationMode::Lcd        => formatter.write_str("lcd"),
		}
	}
}

impl fmt::Display for ResizeFilter {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeFilter::Nearest  => formatter.write_str("nearest"),
			&ResizeFilter::Bilinear => formatter.write_str("bilinear"),
			&ResizeFilter::Bicubic  => formatter.write_str("bicubic"),
		}
	}
}

impl fmt::Display for ResizeMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeMode::Stretch => formatter.write_str("stretch"),
			&ResizeMode::Fit     => formatter.write_str("fit"),
			&ResizeMode::Crop    => formatter.write_str("crop"),
		}
	}
}

impl fmt::Display for Align {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Align::Center      => formatter.write_str("center"),
			&Align::TopLeft     => formatter.write_str("top-left"),
			&Align::BottomLeft  => formatter.write_str("bottom-left"),
			&Align::TopRight    => formatter.write_str("top-right"),
			&Align::BottomRight => formatter.write_str("bottom-right"),
		}
	}
}
<commit_msg>Fix error.<commit_after>//! Module containing font changing tools.
//!
//! # Examples
//! The following from [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management):
//!
//! ```text
//! font: UbuntuMono-R.ttf, size=12;
//! 0x5E: curcumflex.png;
//! 0xE000: tileset.png, size=16x16, spacing=2x1;
//! ```
//!
//! Is equivalent to
//!
//! ```
//! use bear_lib_terminal::terminal;
//! use bear_lib_terminal::terminal::config::font;
//! use bear_lib_terminal::geometry::Size;
//! # assert!({let result =
//! terminal::set(font::true_type(font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('^'), "circumflex.png"));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! # result});
//! ```

use std::fmt;
use std::path::Path;
use geometry::Size;
use terminal::config::{ConfigPart, escape_config_string};

/// Construct a bitmap font override segment repr.
pub fn bitmap<T: AsRef<Path>>(origin: Origin, path: T) -> Bitmap {
	Bitmap{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: None,
		resize: None,
		resize_filter: None,
		resize_mode: None,
		raw_size: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// Construct a TrueType font override segment repr.
///
/// If `title_size.width` is `0`, the resulting `size` prop will be `size=<title_size.width>` as opposed to `size=<title_size>`.
pub fn true_type<T: AsRef<Path>>(origin: Origin, path: T, tile_size: Size) -> TrueType {
	TrueType{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: tile_size,
		size_reference: None,
		mode: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// The origin for the font (the part before `:` in the config string).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Origin {
	/// `font`
	Root,
	/// `named font`
	Named(String),
	/// `0xNNNN`
	Offset(char),
}

/// Rasterization mode for TrueType fonts.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum RasterizationMode {
	Monochrome,
	Normal,
	/// Forces an opaque black background.
	Lcd,
}

/// Resizing filter for bitmaps.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeFilter {
	Nearest,
	Bilinear,
	Bicubic,
}

/// How to aspect-change when resizing a bitmap.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeMode {
	Stretch,
	Fit,
	Crop,
}

/// Per-tileset tile alignment.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Align {
	Center,
	TopLeft,
	BottomLeft,
	TopRight,
	BottomRight,
}

// What's the format for this?
// ref: http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management
// pub enum Background {
// 	Auto,
// 	Color(Color),
// }

/// A bitmap font override segment repr, constructed with [`bitmap()`](fn.bitmap.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Bitmap {
	origin       : Origin,
	path         : String,
	size         : Option<Size>,
	resize       : Option<Size>,
	resize_filter: Option<ResizeFilter>,
	resize_mode  : Option<ResizeMode>,
	raw_size     : Option<Size>,
	codepage     : Option<String>,
	align        : Option<Align>,
	spacing      : Option<Size>,
//	transparent  : Option<Background>,
}

/// A TrueType font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TrueType {
	origin        : Origin,
	path          : String,
	size          : Size,
	size_reference: Option<char>,
	mode          : Option<RasterizationMode>,
	codepage      : Option<String>,
	align         : Option<Align>,
	spacing       : Option<Size>,
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl Bitmap {
	/// The size of a single tile in the tileset.
	pub fn size         (mut self, size: Size)                  -> Self {self.size          = Some(size)         ; self}

	/// The size to resize the image to.
	pub fn resize       (mut self, resize: Size)                -> Self {self.resize        = Some(resize)       ; self}

	/// How to resize the image.
	///
	/// Default: `ResizeFilter::Bilinear`.
	pub fn resize_filter(mut self, resize_filter: ResizeFilter) -> Self {self.resize_filter = Some(resize_filter); self}

	/// Resize aspect method.
	///
	/// Default: `ResizeMode::Stretch`.
	pub fn resize_mode  (mut self, resize_mode: ResizeMode)     -> Self {self.resize_mode   = Some(resize_mode)  ; self}

	/// Raw memory size, `size` if not specified.
	pub fn raw_size     (mut self, raw_size: Size)              -> Self {self.raw_size      = Some(raw_size)     ; self}

	/// Tileset's codepage.
	///
	/// Default: `"ascii"`.
	pub fn codepage     (mut self, codepage: String)            -> Self {self.codepage      = Some(codepage)     ; self}

	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align        (mut self, align: Align)                -> Self {self.align         = Some(align)        ; self}

	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing      (mut self, spacing: Size)               -> Self {self.spacing       = Some(spacing)      ; self}
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl TrueType {
	/// Character used for size probing.
	///
	/// Default: `'@'`.
	pub fn size_reference(mut self, size_reference: char)    -> Self {self.size_reference = Some(size_reference); self}

	/// Rasterization mode. Note: `RasterizationMode::Lcd` forces opaque black background.
	///
	/// Default: `RasterizationMode::Normal`.
	pub fn mode          (mut self, mode: RasterizationMode) -> Self {self.mode           = Some(mode)          ; self}

	/// Reverse codepage for loading symbols.
	pub fn codepage      (mut self, codepage: String)        -> Self {self.codepage       = Some(codepage)      ; self}

	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align         (mut self, align: Align)            -> Self {self.align          = Some(align)         ; self}

	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing       (mut self, spacing: Size)           -> Self {self.spacing        = Some(spacing)       ; self}
}

impl ConfigPart for Bitmap {
	fn to_config_str(&self) -> String {
		format!("{}: {}{}{}{}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				None           => "".to_string(),
				Some(ref size) => format!(", size={}", size),
			},
			match self.resize {
				None             => "".to_string(),
				Some(ref resize) => format!(", resize={}", resize),
			},
			match self.resize_filter {
				None                    => "".to_string(),
				Some(ref resize_filter) => format!(", resize-filter={}", resize_filter),
			},
			match self.resize_mode {
				None                  => "".to_string(),
				Some(ref resize_mode) => format!(", resize-mode={}", resize_mode),
			},
			match self.raw_size {
				None               => "".to_string(),
				Some(ref raw_size) => format!(", raw-size={}", raw_size),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl ConfigPart for TrueType {
	fn to_config_str(&self) -> String {
		format!("{}: {}, size={}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				Size{width: 0, height} => format!("{}", height),
				size                   => format!("{}", size),
			},
			match self.size_reference {
				None                     => "".to_string(),
				Some(ref size_reference) => format!(", size-reference=0x{:X}", *size_reference as i32),
			},
			match self.mode {
				None           => "".to_string(),
				Some(ref mode) => format!(", mode={}", mode),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl fmt::Display for Origin {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Origin::Root          => formatter.write_str("font"),
			&Origin::Named(ref n)  => formatter.write_str(&*&format!("{} font", &n)),
			&Origin::Offset(o)     => formatter.write_str(&*&format!("0x{:X}", o as i32)),
		}
	}
}

impl fmt::Display for RasterizationMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&RasterizationMode::Monochrome => formatter.write_str("monochrome"),
			&RasterizationMode::Normal     => formatter.write_str("normal"),
			&RasterizationMode::Lcd        => formatter.write_str("lcd"),
		}
	}
}

impl fmt::Display for ResizeFilter {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeFilter::Nearest  => formatter.write_str("nearest"),
			&ResizeFilter::Bilinear => formatter.write_str("bilinear"),
			&ResizeFilter::Bicubic  => formatter.write_str("bicubic"),
		}
	}
}

impl fmt::Display for ResizeMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeMode::Stretch => formatter.write_str("stretch"),
			&ResizeMode::Fit     => formatter.write_str("fit"),
			&ResizeMode::Crop    => formatter.write_str("crop"),
		}
	}
}

impl fmt::Display for Align {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Align::Center      => formatter.write_str("center"),
			&Align::TopLeft     => formatter.write_str("top-left"),
			&Align::BottomLeft  => formatter.write_str("bottom-left"),
			&Align::TopRight    => formatter.write_str("top-right"),
			&Align::BottomRight => formatter.write_str("bottom-right"),
		}
	}
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate ipc_channel;
extern crate test;

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

mod platform {
    extern crate crossbeam;

    use ipc_channel::platform;
    use ITERATIONS;

    use std::sync::{mpsc, Mutex};
    use test;

    #[bench]
    fn create_channel(b: &mut test::Bencher) {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                platform::channel().unwrap();
            }
        });
    }

    fn bench_transfer_data(b: &mut test::Bencher, size: usize) {
        let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
        let (tx, rx) = platform::channel().unwrap();

        let (wait_tx, wait_rx) = mpsc::channel();
        let wait_rx = Mutex::new(wait_rx);

        if size > platform::OsIpcSender::get_max_fragment_size() {
            b.iter(|| {
                crossbeam::scope(|scope| {
                    let tx = tx.clone();
                    scope.spawn(|| {
                        let wait_rx = wait_rx.lock().unwrap();
                        let tx = tx;
                        for _ in 0..ITERATIONS {
                            tx.send(&data, vec![], vec![]).unwrap();
                            if ITERATIONS > 1 {
                                // Prevent beginning of the next send
                                // from overlapping with receive of last fragment,
                                // as otherwise results of runs with a large tail fragment
                                // are significantly skewed.
                                wait_rx.recv().unwrap();
                            }
                        }
                    });
                    for _ in 0..ITERATIONS {
                        rx.recv().unwrap();
                        if ITERATIONS > 1 {
                            wait_tx.send(()).unwrap();
                        }
                    }
                    // For reasons mysterious to me,
                    // not returning a value *from every branch*
                    // adds some 100 ns or so of overhead to all results --
                    // which is quite significant for very short tests...
                    0
                })
            });
        } else {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    tx.send(&data, vec![], vec![]).unwrap();
                    rx.recv().unwrap();
                }
                0
            });
        }
    }

    #[bench]
    fn transfer_data_00_1(b: &mut test::Bencher) {
        bench_transfer_data(b, 1);
    }
    #[bench]
    fn transfer_data_01_2(b: &mut test::Bencher) {
        bench_transfer_data(b, 2);
    }
    #[bench]
    fn transfer_data_02_4(b: &mut test::Bencher) {
        bench_transfer_data(b, 4);
    }
    #[bench]
    fn transfer_data_03_8(b: &mut test::Bencher) {
        bench_transfer_data(b, 8);
    }
    #[bench]
    fn transfer_data_04_16(b: &mut test::Bencher) {
        bench_transfer_data(b, 16);
    }
    #[bench]
    fn transfer_data_05_32(b: &mut test::Bencher) {
        bench_transfer_data(b, 32);
    }
    #[bench]
    fn transfer_data_06_64(b: &mut test::Bencher) {
        bench_transfer_data(b, 64);
    }
    #[bench]
    fn transfer_data_07_128(b: &mut test::Bencher) {
        bench_transfer_data(b, 128);
    }
    #[bench]
    fn transfer_data_08_256(b: &mut test::Bencher) {
        bench_transfer_data(b, 256);
    }
    #[bench]
    fn transfer_data_09_512(b: &mut test::Bencher) {
        bench_transfer_data(b, 512);
    }
    #[bench]
    fn transfer_data_10_1k(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024);
    }
    #[bench]
    fn transfer_data_11_2k(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024);
    }
    #[bench]
    fn transfer_data_12_4k(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024);
    }
    #[bench]
    fn transfer_data_13_8k(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024);
    }
    #[bench]
    fn transfer_data_14_16k(b: &mut test::Bencher) {
        bench_transfer_data(b, 16 * 1024);
    }
    #[bench]
    fn transfer_data_15_32k(b: &mut test::Bencher) {
        bench_transfer_data(b, 32 * 1024);
    }
    #[bench]
    fn transfer_data_16_64k(b: &mut test::Bencher) {
        bench_transfer_data(b, 64 * 1024);
    }
    #[bench]
    fn transfer_data_17_128k(b: &mut test::Bencher) {
        bench_transfer_data(b, 128 * 1024);
    }
    #[bench]
    fn transfer_data_18_256k(b: &mut test::Bencher) {
        bench_transfer_data(b, 256 * 1024);
    }
    #[bench]
    fn transfer_data_19_512k(b: &mut test::Bencher) {
        bench_transfer_data(b, 512 * 1024);
    }
    #[bench]
    fn transfer_data_20_1m(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_21_2m(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_22_4m(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_23_8m(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024 * 1024);
    }
}

mod ipc {
    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use test;

        fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
            let mut active = Vec::with_capacity(to_send);
            let mut dormant = Vec::with_capacity(n - to_send);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..to_send {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                active.push(tx);
            }
            for _ in to_send..n {
                let (tx, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
                dormant.push(tx);
            }
            b.iter(|| {
                for tx in active.iter() {
                    tx.send(()).unwrap();
                }
                let mut received = 0;
                while received < to_send {
                    for result in rx_set.select().unwrap().into_iter() {
                        let (_, _) = result.unwrap();
                        received += 1;
                    }
                }
            });
        }

        #[bench]
        fn send_on_1_of_1(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 1);
        }

        #[bench]
        fn send_on_1_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 5);
        }

        #[bench]
        fn send_on_2_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 2, 5);
        }

        #[bench]
        fn send_on_5_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 5);
        }

        #[bench]
        fn send_on_1_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 20);
        }

        #[bench]
        fn send_on_5_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 20);
        }

        #[bench]
        fn send_on_20_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 20);
        }

        #[bench]
        fn send_on_1_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 100);
        }

        #[bench]
        fn send_on_5_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 100);
        }
        #[bench]
        fn send_on_20_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 100);
        }

        #[bench]
        fn send_on_100_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 100, 100);
        }

        fn create_set_of_n(n: usize) -> IpcReceiverSet {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
            rx_set
        }

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(0);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_1(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(1);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(10);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_100(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(100);
            });
        }

        #[bench]
        // Benchmark adding and removing closed receivers from the set
        fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = create_set_of_n(1);
                // On select Receivers with a "ClosedChannel" event
                // will be closed
                rx_set.select().unwrap();
            });
        }
    }
}
<commit_msg>Benchmarks: cleanup: Improve some comments<commit_after>#![feature(test)]

extern crate ipc_channel;
extern crate test;

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

mod platform {
    extern crate crossbeam;

    use ipc_channel::platform;
    use ITERATIONS;

    use std::sync::{mpsc, Mutex};
    use test;

    #[bench]
    fn create_channel(b: &mut test::Bencher) {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                platform::channel().unwrap();
            }
        });
    }

    fn bench_transfer_data(b: &mut test::Bencher, size: usize) {
        let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
        let (tx, rx) = platform::channel().unwrap();

        let (wait_tx, wait_rx) = mpsc::channel();
        let wait_rx = Mutex::new(wait_rx);

        if size > platform::OsIpcSender::get_max_fragment_size() {
            b.iter(|| {
                crossbeam::scope(|scope| {
                    let tx = tx.clone();
                    scope.spawn(|| {
                        let wait_rx = wait_rx.lock().unwrap();
                        let tx = tx;
                        for _ in 0..ITERATIONS {
                            tx.send(&data, vec![], vec![]).unwrap();
                            if ITERATIONS > 1 {
                                // Prevent beginning of the next send
                                // from overlapping with receive of last fragment,
                                // as otherwise results of runs with a large tail fragment
                                // are significantly skewed.
                                wait_rx.recv().unwrap();
                            }
                        }
                    });
                    for _ in 0..ITERATIONS {
                        rx.recv().unwrap();
                        if ITERATIONS > 1 {
                            wait_tx.send(()).unwrap();
                        }
                    }
                    // For reasons mysterious to me,
                    // not returning a value *from every branch*
                    // adds some 100 ns or so of overhead to all results --
                    // which is quite significant for very short tests...
                    0
                })
            });
        } else {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    tx.send(&data, vec![], vec![]).unwrap();
                    rx.recv().unwrap();
                }
                0
            });
        }
    }

    #[bench]
    fn transfer_data_00_1(b: &mut test::Bencher) {
        bench_transfer_data(b, 1);
    }
    #[bench]
    fn transfer_data_01_2(b: &mut test::Bencher) {
        bench_transfer_data(b, 2);
    }
    #[bench]
    fn transfer_data_02_4(b: &mut test::Bencher) {
        bench_transfer_data(b, 4);
    }
    #[bench]
    fn transfer_data_03_8(b: &mut test::Bencher) {
        bench_transfer_data(b, 8);
    }
    #[bench]
    fn transfer_data_04_16(b: &mut test::Bencher) {
        bench_transfer_data(b, 16);
    }
    #[bench]
    fn transfer_data_05_32(b: &mut test::Bencher) {
        bench_transfer_data(b, 32);
    }
    #[bench]
    fn transfer_data_06_64(b: &mut test::Bencher) {
        bench_transfer_data(b, 64);
    }
    #[bench]
    fn transfer_data_07_128(b: &mut test::Bencher) {
        bench_transfer_data(b, 128);
    }
    #[bench]
    fn transfer_data_08_256(b: &mut test::Bencher) {
        bench_transfer_data(b, 256);
    }
    #[bench]
    fn transfer_data_09_512(b: &mut test::Bencher) {
        bench_transfer_data(b, 512);
    }
    #[bench]
    fn transfer_data_10_1k(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024);
    }
    #[bench]
    fn transfer_data_11_2k(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024);
    }
    #[bench]
    fn transfer_data_12_4k(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024);
    }
    #[bench]
    fn transfer_data_13_8k(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024);
    }
    #[bench]
    fn transfer_data_14_16k(b: &mut test::Bencher) {
        bench_transfer_data(b, 16 * 1024);
    }
    #[bench]
    fn transfer_data_15_32k(b: &mut test::Bencher) {
        bench_transfer_data(b, 32 * 1024);
    }
    #[bench]
    fn transfer_data_16_64k(b: &mut test::Bencher) {
        bench_transfer_data(b, 64 * 1024);
    }
    #[bench]
    fn transfer_data_17_128k(b: &mut test::Bencher) {
        bench_transfer_data(b, 128 * 1024);
    }
    #[bench]
    fn transfer_data_18_256k(b: &mut test::Bencher) {
        bench_transfer_data(b, 256 * 1024);
    }
    #[bench]
    fn transfer_data_19_512k(b: &mut test::Bencher) {
        bench_transfer_data(b, 512 * 1024);
    }
    #[bench]
    fn transfer_data_20_1m(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_21_2m(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_22_4m(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_23_8m(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024 * 1024);
    }
}

mod ipc {
    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use test;

        // Benchmark selecting over a set of `n` receivers,
        // with `to_send` of them actually having pending data.
        fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
            let mut active = Vec::with_capacity(to_send);
            let mut dormant = Vec::with_capacity(n - to_send);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..to_send {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                active.push(tx);
            }
            for _ in to_send..n {
                let (tx, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
                dormant.push(tx);
            }
            b.iter(|| {
                for tx in active.iter() {
                    tx.send(()).unwrap();
                }
                let mut received = 0;
                while received < to_send {
                    for result in rx_set.select().unwrap().into_iter() {
                        let (_, _) = result.unwrap();
                        received += 1;
                    }
                }
            });
        }

        #[bench]
        fn send_on_1_of_1(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 1);
        }

        #[bench]
        fn send_on_1_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 5);
        }

        #[bench]
        fn send_on_2_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 2, 5);
        }

        #[bench]
        fn send_on_5_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 5);
        }

        #[bench]
        fn send_on_1_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 20);
        }

        #[bench]
        fn send_on_5_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 20);
        }

        #[bench]
        fn send_on_20_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 20);
        }

        #[bench]
        fn send_on_1_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 100);
        }

        #[bench]
        fn send_on_5_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 100);
        }
        #[bench]
        fn send_on_20_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 100);
        }

        #[bench]
        fn send_on_100_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 100, 100);
        }

        fn create_set_of_n(n: usize) -> IpcReceiverSet {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..n {
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
            rx_set
        }

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(0);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_1(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(1);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(10);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_100(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_set_of_n(100);
            });
        }

        #[bench]
        // Benchmark performance of removing closed receivers from set.
        // This also includes the time for adding receivers,
        // as there is no way to measure the removing in isolation.
        fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = create_set_of_n(1);
                // On `select()`, receivers with a "ClosedChannel" event will be closed,
                // and automatically dropped from the set.
                rx_set.select().unwrap();
            });
        }
    }
}
<|endoftext|>