<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,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        animation_value_type="ComputedValue",
        allow_quirks=True,
        servo_restyle_damage="reflow_out_of_flow"
    )}
% endfor
// inset-* logical properties, map to "top" / "left" / "bottom" / "right"
% for side in LOGICAL_SIDES:
    ${helpers.predefined_type(
        "inset-%s" % side,
        "LengthOrPercentageOrAuto",
        "computed::LengthOrPercentageOrAuto::Auto",
        spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        alias="offset-%s" % side,
        animation_value_type="ComputedValue",
        logical=True,
    )}
% endfor

#[cfg(feature = "gecko")]
macro_rules! impl_align_conversions {
    ($name: path) => {
        impl From<u8> for $name {
            fn from(bits: u8) -> $name {
                $name(::values::specified::align::AlignFlags::from_bits(bits)
                      .expect("bits contain valid flag"))
            }
        }

        impl From<$name> for u8 {
            fn from(v: $name) -> u8 {
                v.0.bits()
            }
        }
    };
}

${helpers.predefined_type(
    "z-index",
    "ZIndex",
    "computed::ZIndex::auto()",
    spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
    flags="CREATES_STACKING_CONTEXT",
    animation_value_type="ComputedValue",
)}

// 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",
                         animation_value_type="discrete",
                         servo_restyle_damage = "reflow")}

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

% 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",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="justify-content",
                              type="JustifyContent",
                              initial_value="specified::JustifyContent(specified::ContentDistribution::normal())",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                              extra_prefixes="webkit",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}
% 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",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}

    ${helpers.single_keyword("align-items",
                             "stretch flex-start flex-end center baseline",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="align-content",
                              type="AlignContent",
                              initial_value="specified::AlignContent(specified::ContentDistribution::normal())",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                              extra_prefixes="webkit",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}

    ${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",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::AlignItems);

    ${helpers.predefined_type(
        name="justify-items",
        type="JustifyItems",
        initial_value="computed::JustifyItems::legacy()",
        spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
        animation_value_type="discrete",
    )}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::JustifyItems);
% endif

// Flex item properties
${helpers.predefined_type("flex-grow", "NonNegativeNumber",
                          "From::from(0.0)",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
                          extra_prefixes="webkit",
                          animation_value_type="NonNegativeNumber",
                          servo_restyle_damage = "reflow")}

${helpers.predefined_type("flex-shrink", "NonNegativeNumber",
                          "From::from(1.0)",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
                          extra_prefixes="webkit",
                          animation_value_type="NonNegativeNumber",
                          servo_restyle_damage = "reflow")}

// 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",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="align-self",
                              type="AlignSelf",
                              initial_value="specified::AlignSelf(specified::SelfAlignment::auto())",
                              spec="https://drafts.csswg.org/css-align/#align-self-property",
                              extra_prefixes="webkit",
                              animation_value_type="discrete")}

    ${helpers.predefined_type(name="justify-self",
                              type="JustifySelf",
                              initial_value="specified::JustifySelf(specified::SelfAlignment::auto())",
                              spec="https://drafts.csswg.org/css-align/#justify-self-property",
                              animation_value_type="discrete")}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::SelfAlignment);
% endif

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

${helpers.predefined_type(
    "flex-basis",
    "FlexBasis",
    "computed::FlexBasis::auto()",
    spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
    extra_prefixes="webkit",
    animation_value_type="FlexBasis",
    servo_restyle_damage = "reflow"
)}

% 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"
    %>
    // NOTE: Block-size doesn't support -moz-*-content keywords, since they make
    // no sense on the block axis, but it simplifies things the have that it has
    // the same type as the other properties, since otherwise we'd need to
    // handle logical props where the types are different, which looks like a
    // pain.
    % if product == "gecko":
        <%
            parse_function = "parse" if size != "block-size" else "parse_disallow_keyword"
        %>
        // width, height, block-size, inline-size
        ${helpers.predefined_type(
            size,
            "MozLength",
            "computed::MozLength::auto()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MozLength",
            flags="GETCS_NEEDS_LAYOUT_FLUSH",
            servo_restyle_damage="reflow"
        )}
        // min-width, min-height, min-block-size, min-inline-size,
        ${helpers.predefined_type(
            "min-%s" % size,
            "MozLength",
            "computed::MozLength::auto()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MozLength",
            servo_restyle_damage = "reflow"
        )}
        ${helpers.predefined_type(
            "max-%s" % size,
            "MaxLength",
            "computed::MaxLength::none()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MaxLength",
            servo_restyle_damage = "reflow"
        )}
    % else:
        // servo versions (no keyword support)
        ${helpers.predefined_type(size,
                                  "LengthOrPercentageOrAuto",
                                  "computed::LengthOrPercentageOrAuto::Auto",
                                  "parse_non_negative",
                                  spec=spec % size,
                                  allow_quirks=not logical,
                                  animation_value_type="ComputedValue", logical = logical,
                                  servo_restyle_damage = "reflow")}
        ${helpers.predefined_type("min-%s" % size,
                                  "LengthOrPercentage",
                                  "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
                                  "parse_non_negative",
                                  spec=spec % ("min-%s" % size),
                                  animation_value_type="ComputedValue",
                                  logical=logical,
                                  allow_quirks=not logical,
                                  servo_restyle_damage = "reflow")}
        ${helpers.predefined_type("max-%s" % size,
                                  "LengthOrPercentageOrNone",
                                  "computed::LengthOrPercentageOrNone::None",
                                  "parse_non_negative",
                                  spec=spec % ("min-%s" % size),
                                  animation_value_type="ComputedValue",
                                  logical=logical,
                                  allow_quirks=not logical,
                                  servo_restyle_damage = "reflow")}
    % endif
% endfor

${helpers.single_keyword("box-sizing",
                         "content-box border-box",
                         extra_prefixes="moz:layout.css.prefixes.box-sizing webkit",
                         spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
                         gecko_enum_prefix="StyleBoxSizing",
                         custom_consts={ "content-box": "Content", "border-box": "Border" },
                         animation_value_type="discrete",
                         servo_restyle_damage = "reflow")}

${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
                         products="gecko", animation_value_type="discrete",
                         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",
                          animation_value_type="ComputedValue")}

% for kind in ["row", "column"]:
    % for range in ["start", "end"]:
        ${helpers.predefined_type("grid-%s-%s" % (kind, range),
                                  "GridLine",
                                  "Default::default()",
                                  animation_value_type="discrete",
                                  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()",
                              animation_value_type="discrete",
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                              products="gecko",
                              boxed=True)}

    ${helpers.predefined_type(
        "grid-template-%ss" % kind,
        "GridTemplateComponent",
        "specified::GenericGridTemplateComponent::None",
        products="gecko",
        spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind,
        boxed=True,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        animation_value_type="discrete"
    )}

% endfor

${helpers.predefined_type("grid-auto-flow",
                          "GridAutoFlow",
                          initial_value="computed::GridAutoFlow::row()",
                          products="gecko",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow")}

${helpers.predefined_type("grid-template-areas",
                          "GridTemplateAreas",
                          initial_value="computed::GridTemplateAreas::none()",
                          products="gecko",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas")}

${helpers.predefined_type("column-gap",
                          "length::NonNegativeLengthOrPercentageOrNormal",
                          "Either::Second(Normal)",
                          alias="grid-column-gap" if product == "gecko" else "",
                          extra_prefixes="moz",
                          servo_pref="layout.columns.enabled",
                          spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap",
                          animation_value_type="NonNegativeLengthOrPercentageOrNormal",
                          servo_restyle_damage = "reflow")}

// no need for -moz- prefixed alias for this property
${helpers.predefined_type("row-gap",
                          "length::NonNegativeLengthOrPercentageOrNormal",
                          "Either::Second(Normal)",
                          alias="grid-row-gap",
                          products="gecko",
                          spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap",
                          animation_value_type="NonNegativeLengthOrPercentageOrNormal",
                          servo_restyle_damage = "reflow")}
<commit_msg>style: Put offset-* aliases behind a pref.<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,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        animation_value_type="ComputedValue",
        allow_quirks=True,
        servo_restyle_damage="reflow_out_of_flow"
    )}
% endfor
// inset-* logical properties, map to "top" / "left" / "bottom" / "right"
% for side in LOGICAL_SIDES:
    ${helpers.predefined_type(
        "inset-%s" % side,
        "LengthOrPercentageOrAuto",
        "computed::LengthOrPercentageOrAuto::Auto",
        spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
        animation_value_type="ComputedValue",
        logical=True,
    )}
% endfor

#[cfg(feature = "gecko")]
macro_rules! impl_align_conversions {
    ($name: path) => {
        impl From<u8> for $name {
            fn from(bits: u8) -> $name {
                $name(::values::specified::align::AlignFlags::from_bits(bits)
                      .expect("bits contain valid flag"))
            }
        }

        impl From<$name> for u8 {
            fn from(v: $name) -> u8 {
                v.0.bits()
            }
        }
    };
}

${helpers.predefined_type(
    "z-index",
    "ZIndex",
    "computed::ZIndex::auto()",
    spec="https://www.w3.org/TR/CSS2/visuren.html#z-index",
    flags="CREATES_STACKING_CONTEXT",
    animation_value_type="ComputedValue",
)}

// 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",
                         animation_value_type="discrete",
                         servo_restyle_damage = "reflow")}

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

% 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",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="justify-content",
                              type="JustifyContent",
                              initial_value="specified::JustifyContent(specified::ContentDistribution::normal())",
                              spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
                              extra_prefixes="webkit",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}
% 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",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}

    ${helpers.single_keyword("align-items",
                             "stretch flex-start flex-end center baseline",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="align-content",
                              type="AlignContent",
                              initial_value="specified::AlignContent(specified::ContentDistribution::normal())",
                              spec="https://drafts.csswg.org/css-align/#propdef-align-content",
                              extra_prefixes="webkit",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}

    ${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",
                              animation_value_type="discrete",
                              servo_restyle_damage = "reflow")}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::AlignItems);

    ${helpers.predefined_type(
        name="justify-items",
        type="JustifyItems",
        initial_value="computed::JustifyItems::legacy()",
        spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
        animation_value_type="discrete",
    )}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::JustifyItems);
% endif

// Flex item properties
${helpers.predefined_type("flex-grow", "NonNegativeNumber",
                          "From::from(0.0)",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
                          extra_prefixes="webkit",
                          animation_value_type="NonNegativeNumber",
                          servo_restyle_damage = "reflow")}

${helpers.predefined_type("flex-shrink", "NonNegativeNumber",
                          "From::from(1.0)",
                          spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
                          extra_prefixes="webkit",
                          animation_value_type="NonNegativeNumber",
                          servo_restyle_damage = "reflow")}

// 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",
                             extra_prefixes="webkit",
                             spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
                             animation_value_type="discrete",
                             servo_restyle_damage = "reflow")}
% else:
    ${helpers.predefined_type(name="align-self",
                              type="AlignSelf",
                              initial_value="specified::AlignSelf(specified::SelfAlignment::auto())",
                              spec="https://drafts.csswg.org/css-align/#align-self-property",
                              extra_prefixes="webkit",
                              animation_value_type="discrete")}

    ${helpers.predefined_type(name="justify-self",
                              type="JustifySelf",
                              initial_value="specified::JustifySelf(specified::SelfAlignment::auto())",
                              spec="https://drafts.csswg.org/css-align/#justify-self-property",
                              animation_value_type="discrete")}

    #[cfg(feature = "gecko")]
    impl_align_conversions!(::values::specified::align::SelfAlignment);
% endif

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

${helpers.predefined_type(
    "flex-basis",
    "FlexBasis",
    "computed::FlexBasis::auto()",
    spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
    extra_prefixes="webkit",
    animation_value_type="FlexBasis",
    servo_restyle_damage = "reflow"
)}

% 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"
    %>
    // NOTE: Block-size doesn't support -moz-*-content keywords, since they make
    // no sense on the block axis, but it simplifies things the have that it has
    // the same type as the other properties, since otherwise we'd need to
    // handle logical props where the types are different, which looks like a
    // pain.
    % if product == "gecko":
        <%
            parse_function = "parse" if size != "block-size" else "parse_disallow_keyword"
        %>
        // width, height, block-size, inline-size
        ${helpers.predefined_type(
            size,
            "MozLength",
            "computed::MozLength::auto()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MozLength",
            flags="GETCS_NEEDS_LAYOUT_FLUSH",
            servo_restyle_damage="reflow"
        )}
        // min-width, min-height, min-block-size, min-inline-size,
        ${helpers.predefined_type(
            "min-%s" % size,
            "MozLength",
            "computed::MozLength::auto()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MozLength",
            servo_restyle_damage = "reflow"
        )}
        ${helpers.predefined_type(
            "max-%s" % size,
            "MaxLength",
            "computed::MaxLength::none()",
            parse_function,
            logical=logical,
            allow_quirks=not logical,
            spec=spec % size,
            animation_value_type="MaxLength",
            servo_restyle_damage = "reflow"
        )}
    % else:
        // servo versions (no keyword support)
        ${helpers.predefined_type(size,
                                  "LengthOrPercentageOrAuto",
                                  "computed::LengthOrPercentageOrAuto::Auto",
                                  "parse_non_negative",
                                  spec=spec % size,
                                  allow_quirks=not logical,
                                  animation_value_type="ComputedValue", logical = logical,
                                  servo_restyle_damage = "reflow")}
        ${helpers.predefined_type("min-%s" % size,
                                  "LengthOrPercentage",
                                  "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
                                  "parse_non_negative",
                                  spec=spec % ("min-%s" % size),
                                  animation_value_type="ComputedValue",
                                  logical=logical,
                                  allow_quirks=not logical,
                                  servo_restyle_damage = "reflow")}
        ${helpers.predefined_type("max-%s" % size,
                                  "LengthOrPercentageOrNone",
                                  "computed::LengthOrPercentageOrNone::None",
                                  "parse_non_negative",
                                  spec=spec % ("min-%s" % size),
                                  animation_value_type="ComputedValue",
                                  logical=logical,
                                  allow_quirks=not logical,
                                  servo_restyle_damage = "reflow")}
    % endif
% endfor

${helpers.single_keyword("box-sizing",
                         "content-box border-box",
                         extra_prefixes="moz:layout.css.prefixes.box-sizing webkit",
                         spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
                         gecko_enum_prefix="StyleBoxSizing",
                         custom_consts={ "content-box": "Content", "border-box": "Border" },
                         animation_value_type="discrete",
                         servo_restyle_damage = "reflow")}

${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
                         products="gecko", animation_value_type="discrete",
                         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",
                          animation_value_type="ComputedValue")}

% for kind in ["row", "column"]:
    % for range in ["start", "end"]:
        ${helpers.predefined_type("grid-%s-%s" % (kind, range),
                                  "GridLine",
                                  "Default::default()",
                                  animation_value_type="discrete",
                                  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()",
                              animation_value_type="discrete",
                              spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
                              products="gecko",
                              boxed=True)}

    ${helpers.predefined_type(
        "grid-template-%ss" % kind,
        "GridTemplateComponent",
        "specified::GenericGridTemplateComponent::None",
        products="gecko",
        spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind,
        boxed=True,
        flags="GETCS_NEEDS_LAYOUT_FLUSH",
        animation_value_type="discrete"
    )}

% endfor

${helpers.predefined_type("grid-auto-flow",
                          "GridAutoFlow",
                          initial_value="computed::GridAutoFlow::row()",
                          products="gecko",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow")}

${helpers.predefined_type("grid-template-areas",
                          "GridTemplateAreas",
                          initial_value="computed::GridTemplateAreas::none()",
                          products="gecko",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas")}

${helpers.predefined_type("column-gap",
                          "length::NonNegativeLengthOrPercentageOrNormal",
                          "Either::Second(Normal)",
                          alias="grid-column-gap" if product == "gecko" else "",
                          extra_prefixes="moz",
                          servo_pref="layout.columns.enabled",
                          spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap",
                          animation_value_type="NonNegativeLengthOrPercentageOrNormal",
                          servo_restyle_damage = "reflow")}

// no need for -moz- prefixed alias for this property
${helpers.predefined_type("row-gap",
                          "length::NonNegativeLengthOrPercentageOrNormal",
                          "Either::Second(Normal)",
                          alias="grid-row-gap",
                          products="gecko",
                          spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap",
                          animation_value_type="NonNegativeLengthOrPercentageOrNormal",
                          servo_restyle_damage = "reflow")}
<|endoftext|>


<commit_before>use std::io;
use serialize::hex::ToHex;

use super::logger::RecordInfo;

#[allow(missing_docs)]
mod error {
    use std::io;

    error_chain! {
        types {
            Error, ErrorKind, ChainErr, Result;
        }
        links {}
        foreign_links {
            io::Error, Io, "io error";
        }
        errors {
            Other {
                description("other serialization error")
                    display("other serialization error")
            }
        }
    }
}

pub use self::error::{Error, Result, ErrorKind};

/// Value that can be serialized
///
/// Loggers require values in key-value pairs to
/// implement this trait.
///
pub trait Serialize: Send + Sync {
    /// Serialize self into `Serializer`
    ///
    /// Structs implementing this trait should generally
    /// only call respective methods of `serializer`.
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()>;
}

/// Value that can be serialized and stored
/// in logger itself.
///
/// As Loggers itself must be thread-safe, they can only
/// store values implementing this trait.
pub trait SyncSerialize: Send + Sync + 'static + Serialize {}

/// Serializer
///
/// Drains using `Format` will internally use
/// types implementing this trait.
pub trait Serializer {
    /// Emit bool
    fn emit_bool(&mut self, key: &str, val: bool) -> Result<()>;
    /// Emit `()`
    fn emit_unit(&mut self, key: &str) -> Result<()>;
    /// Emit `None`
    fn emit_none(&mut self, key: &str) -> Result<()>;
    /// Emit char
    fn emit_char(&mut self, key: &str, val: char) -> Result<()>;
    /// Emit bytes
    fn emit_bytes(&mut self, key: &str, val: &[u8]) -> Result<()>;
    /// Emit u8
    fn emit_u8(&mut self, key: &str, val: u8) -> Result<()>;
    /// Emit i8
    fn emit_i8(&mut self, key: &str, val: i8) -> Result<()>;
    /// Emit u16
    fn emit_u16(&mut self, key: &str, val: u16) -> Result<()>;
    /// Emit i16
    fn emit_i16(&mut self, key: &str, val: i16) -> Result<()>;
    /// Emit u32
    fn emit_u32(&mut self, key: &str, val: u32) -> Result<()>;
    /// Emit i32
    fn emit_i32(&mut self, key: &str, val: i32) -> Result<()>;
    /// Emit f32
    fn emit_f32(&mut self, key: &str, val: f32) -> Result<()>;
    /// Emit u64
    fn emit_u64(&mut self, key: &str, val: u64) -> Result<()>;
    /// Emit i64
    fn emit_i64(&mut self, key: &str, val: i64) -> Result<()>;
    /// Emit f64
    fn emit_f64(&mut self, key: &str, val: f64) -> Result<()>;
    /// Emit usize
    fn emit_usize(&mut self, key: &str, val: usize) -> Result<()>;
    /// Emit isize
    fn emit_isize(&mut self, key: &str, val: isize) -> Result<()>;
    /// Emit str
    fn emit_str(&mut self, key: &str, val: &str) -> Result<()>;
}

impl Serialize for str {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self)
    }
}

impl<'a> Serialize for &'a str {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self)
    }
}

impl SyncSerialize for &'static str {}

impl Serialize for [u8] {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_bytes(key, self)
    }
}

impl SyncSerialize for [u8] {}

impl Serialize for Vec<u8> {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_bytes(key, self.as_slice())
    }
}

impl SyncSerialize for Vec<u8> {}

impl<T: Serialize> Serialize for Option<T> {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        match *self {
            Some(ref s) => s.serialize(rinfo, key, serializer),
            None => serializer.emit_none(key),
        }
    }
}

impl<T: Serialize + 'static> SyncSerialize for Option<T> {}

impl Serialize for String {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self.as_str())
    }
}

impl SyncSerialize for String {}

macro_rules! impl_serialize_for{
    ($t:ty, $f:ident) => {
        impl Serialize for $t {
            fn serialize(&self, _rinfo : &RecordInfo, key : &str, serializer : &mut Serializer)
                         -> Result<()> {
                serializer.$f(key, *self)
            }
        }

        impl SyncSerialize for $t where $t : Send+Sync+'static { }
    };
}

impl_serialize_for!(usize, emit_usize);
impl_serialize_for!(isize, emit_isize);
impl_serialize_for!(bool, emit_bool);
impl_serialize_for!(char, emit_char);
impl_serialize_for!(u8, emit_u8);
impl_serialize_for!(i8, emit_i8);
impl_serialize_for!(u16, emit_u16);
impl_serialize_for!(i16, emit_i16);
impl_serialize_for!(u32, emit_u32);
impl_serialize_for!(i32, emit_i32);
impl_serialize_for!(f32, emit_f32);
impl_serialize_for!(u64, emit_u64);
impl_serialize_for!(i64, emit_i64);
impl_serialize_for!(f64, emit_f64);

impl<S: 'static + Serialize, F> Serialize for F
    where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>) -> S {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        (*self)(&rinfo).serialize(rinfo, key, serializer)
    }
}

impl<S: 'static + Serialize, F> SyncSerialize for F
    where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>) -> S
{
}

/// A newtype for non-return based lazy values
///
/// It's more natural for closures used as lazy values to return `Serialize`
/// implementing type, but sometimes that forces an allocation (eg. Strings)
///
/// In some cases it might make sense for another closure form to be used - one
/// taking a serializer as an argument, which avoids lifetimes / allocation issues.
///
/// Unfortunately, as one `struct` can implement many different closure traits,
/// a newtype has to be used to prevent ambiguity.
///
/// Generally this method should be used only if it avoids a big allocation of
/// `Serialize`-implementing type in performance-critical logging statement.
///
/// TODO: Can `PushLazy` be avoided?
pub struct PushLazy<F>(pub F);

/// A handle to `Serializer` for `PushLazy` closure
pub struct ValueSerializer<'a> {
    rinfo : &'a RecordInfo<'a>,
    key : &'a str,
    serializer : &'a mut Serializer,
    done : bool,
}

impl<'a> ValueSerializer<'a> {
    /// Serialize a value
    ///
    /// This consumes `self` to prevent serializing one value multiple times
    pub fn serialize<'b, S: 'b + Serialize>(mut self, s : S) -> Result<()> {
        self.done = true;
        s.serialize(self.rinfo, self.key, self.serializer)
    }
}

impl<'a> Drop for ValueSerializer<'a> {
    fn drop(&mut self) {
        if !self.done {
            // unfortunately this gives no change to return serialization errors
            let _ = self.serializer.emit_unit(self.key);
        }
    }
}

impl<F> Serialize for PushLazy<F>
     where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>, ValueSerializer<'c>) -> Result<()> {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        let ser = ValueSerializer {
            rinfo: rinfo,
            key: key,
            serializer: serializer,
            done: false,
        };
        (self.0)(&rinfo, ser)
    }
}

impl<F> SyncSerialize for PushLazy<F>
     where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>, ValueSerializer<'c>) -> Result<()> {
}

impl<W: io::Write + ?Sized> Serializer for W {
    fn emit_none(&mut self, key: &str) -> Result<()> {
        try!(write!(self, "{}: {}", key, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> Result<()> {
        try!(write!(self, "{}: ()", key, ));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_bytes(&mut self, key: &str, val: &[u8]) -> Result<()> {
        try!(write!(self, "{}: {}", key, val.to_hex()));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
}
<commit_msg>Improve `ser`<commit_after>use std::io;
use serialize::hex::ToHex;
use std;
use std::sync::Arc;
use std::rc::Rc;

use super::logger::RecordInfo;

#[allow(missing_docs)]
mod error {
    use std::io;

    error_chain! {
        types {
            Error, ErrorKind, ChainErr, Result;
        }
        links {}
        foreign_links {
            io::Error, Io, "io error";
        }
        errors {
            Other {
                description("other serialization error")
                    display("other serialization error")
            }
        }
    }
}

pub use self::error::{Error, Result, ErrorKind};

/// Value that can be serialized
///
/// Loggers require values in key-value pairs to
/// implement this trait.
///
pub trait Serialize {
    /// Serialize self into `Serializer`
    ///
    /// Structs implementing this trait should generally
    /// only call respective methods of `serializer`.
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()>;
}

/// Value that can be serialized and stored
/// in logger itself.
///
/// As Loggers itself must be thread-safe, they can only
/// store values implementing this trait.
pub trait SyncSerialize: Send + Sync + 'static + Serialize {}

/// Serializer
///
/// Drains using `Format` will internally use
/// types implementing this trait.
pub trait Serializer {
    /// Emit bool
    fn emit_bool(&mut self, key: &str, val: bool) -> Result<()>;
    /// Emit `()`
    fn emit_unit(&mut self, key: &str) -> Result<()>;
    /// Emit `None`
    fn emit_none(&mut self, key: &str) -> Result<()>;
    /// Emit char
    fn emit_char(&mut self, key: &str, val: char) -> Result<()>;
    /// Emit bytes
    fn emit_bytes(&mut self, key: &str, val: &[u8]) -> Result<()>;
    /// Emit u8
    fn emit_u8(&mut self, key: &str, val: u8) -> Result<()>;
    /// Emit i8
    fn emit_i8(&mut self, key: &str, val: i8) -> Result<()>;
    /// Emit u16
    fn emit_u16(&mut self, key: &str, val: u16) -> Result<()>;
    /// Emit i16
    fn emit_i16(&mut self, key: &str, val: i16) -> Result<()>;
    /// Emit u32
    fn emit_u32(&mut self, key: &str, val: u32) -> Result<()>;
    /// Emit i32
    fn emit_i32(&mut self, key: &str, val: i32) -> Result<()>;
    /// Emit f32
    fn emit_f32(&mut self, key: &str, val: f32) -> Result<()>;
    /// Emit u64
    fn emit_u64(&mut self, key: &str, val: u64) -> Result<()>;
    /// Emit i64
    fn emit_i64(&mut self, key: &str, val: i64) -> Result<()>;
    /// Emit f64
    fn emit_f64(&mut self, key: &str, val: f64) -> Result<()>;
    /// Emit usize
    fn emit_usize(&mut self, key: &str, val: usize) -> Result<()>;
    /// Emit isize
    fn emit_isize(&mut self, key: &str, val: isize) -> Result<()>;
    /// Emit str
    fn emit_str(&mut self, key: &str, val: &str) -> Result<()>;
}

macro_rules! impl_serialize_for{
    ($t:ty, $f:ident) => {
        impl Serialize for $t {
            fn serialize(&self, _rinfo : &RecordInfo, key : &str, serializer : &mut Serializer)
                         -> Result<()> {
                serializer.$f(key, *self)
            }
        }

        impl SyncSerialize for $t where $t : Send+Sync+'static { }
    };
}

impl_serialize_for!(usize, emit_usize);
impl_serialize_for!(isize, emit_isize);
impl_serialize_for!(bool, emit_bool);
impl_serialize_for!(char, emit_char);
impl_serialize_for!(u8, emit_u8);
impl_serialize_for!(i8, emit_i8);
impl_serialize_for!(u16, emit_u16);
impl_serialize_for!(i16, emit_i16);
impl_serialize_for!(u32, emit_u32);
impl_serialize_for!(i32, emit_i32);
impl_serialize_for!(f32, emit_f32);
impl_serialize_for!(u64, emit_u64);
impl_serialize_for!(i64, emit_i64);
impl_serialize_for!(f64, emit_f64);

impl Serialize for str {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self)
    }
}

impl<'a> Serialize for &'a str {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self)
    }
}

impl SyncSerialize for &'static str {}

impl Serialize for String {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_str(key, self.as_str())
    }
}

impl SyncSerialize for String {}

impl<T: Serialize> Serialize for Option<T> {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        match *self {
            Some(ref s) => s.serialize(rinfo, key, serializer),
            None => serializer.emit_none(key),
        }
    }
}

impl<T: Serialize + Send +Sync + 'static> SyncSerialize for Option<T> {}

impl Serialize for [u8] {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_bytes(key, self)
    }
}

impl SyncSerialize for [u8] {}

impl Serialize for Vec<u8> {
    fn serialize(&self, _rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        serializer.emit_bytes(key, self.as_slice())
    }
}

impl SyncSerialize for Vec<u8> {}

impl<T> Serialize for Arc<T> where T: Serialize {
    fn serialize(&self, rinfo : &RecordInfo, key : &str, serializer : &mut Serializer)
                 -> Result<()> {
        (**self).serialize(rinfo, key, serializer)
    }
}

impl<T> SyncSerialize for Arc<T> where T : SyncSerialize { }

impl<T> Serialize for Rc<T> where T: Serialize {
    fn serialize(&self, rinfo : &RecordInfo, key : &str, serializer : &mut Serializer)
                 -> Result<()> {
        (**self).serialize(rinfo, key, serializer)
    }
}

impl<T> Serialize for std::num::Wrapping<T> where T: Serialize {
    fn serialize(&self, rinfo : &RecordInfo, key : &str, serializer : &mut Serializer)
                 -> Result<()> {
        self.0.serialize(rinfo, key, serializer)
    }
}

impl<T> SyncSerialize for std::num::Wrapping<T> where T : SyncSerialize { }

impl<S: 'static + Serialize, F> Serialize for F
    where F: 'static + for<'c, 'd> Fn(&'c RecordInfo<'d>) -> S {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        (*self)(&rinfo).serialize(rinfo, key, serializer)
    }
}

impl<S: 'static + Serialize, F> SyncSerialize for F
    where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>) -> S
{
}

/// A newtype for non-return based lazy values
///
/// It's more natural for closures used as lazy values to return `Serialize`
/// implementing type, but sometimes that forces an allocation (eg. Strings)
///
/// In some cases it might make sense for another closure form to be used - one
/// taking a serializer as an argument, which avoids lifetimes / allocation issues.
///
/// Unfortunately, as one `struct` can implement many different closure traits,
/// a newtype has to be used to prevent ambiguity.
///
/// Generally this method should be used only if it avoids a big allocation of
/// `Serialize`-implementing type in performance-critical logging statement.
///
/// TODO: Can `PushLazy` be avoided?
pub struct PushLazy<F>(pub F);

/// A handle to `Serializer` for `PushLazy` closure
pub struct ValueSerializer<'a> {
    rinfo : &'a RecordInfo<'a>,
    key : &'a str,
    serializer : &'a mut Serializer,
    done : bool,
}

impl<'a> ValueSerializer<'a> {
    /// Serialize a value
    ///
    /// This consumes `self` to prevent serializing one value multiple times
    pub fn serialize<'b, S: 'b + Serialize>(mut self, s : S) -> Result<()> {
        self.done = true;
        s.serialize(self.rinfo, self.key, self.serializer)
    }
}

impl<'a> Drop for ValueSerializer<'a> {
    fn drop(&mut self) {
        if !self.done {
            // unfortunately this gives no change to return serialization errors
            let _ = self.serializer.emit_unit(self.key);
        }
    }
}

impl<F> Serialize for PushLazy<F>
     where F: 'static + for<'c, 'd> Fn(&'c RecordInfo<'d>, ValueSerializer<'c>) -> Result<()> {
    fn serialize(&self, rinfo: &RecordInfo, key: &str, serializer: &mut Serializer) -> Result<()> {
        let ser = ValueSerializer {
            rinfo: rinfo,
            key: key,
            serializer: serializer,
            done: false,
        };
        (self.0)(&rinfo, ser)
    }
}

impl<F> SyncSerialize for PushLazy<F>
     where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c RecordInfo<'d>, ValueSerializer<'c>) -> Result<()> {
}

impl<W: io::Write + ?Sized> Serializer for W {
    fn emit_none(&mut self, key: &str) -> Result<()> {
        try!(write!(self, "{}: {}", key, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> Result<()> {
        try!(write!(self, "{}: ()", key, ));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_bytes(&mut self, key: &str, val: &[u8]) -> Result<()> {
        try!(write!(self, "{}: {}", key, val.to_hex()));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> Result<()> {
        try!(write!(self, "{}: {}", key, val));
        Ok(())
    }
}
<|endoftext|>


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

use analysis;
use analysis::special_functions::Type;
use env::Env;
use super::{function, general, trait_impls};

pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::record::Info) -> Result<()>{
    let type_ = analysis.type_(&env.library);

    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    if let (Some(ref_fn), Some(unref_fn)) = (analysis.specials.get(&Type::Ref),
                                             analysis.specials.get(&Type::Unref)) {
        try!(general::define_shared_type(w, &analysis.name, &type_.c_type, ref_fn, unref_fn));
    } else if let (Some(copy_fn), Some(free_fn)) = (analysis.specials.get(&Type::Copy),
                                                    analysis.specials.get(&Type::Free)) {
        try!(general::define_boxed_type(w, &analysis.name, &type_.c_type, copy_fn, free_fn));
    } else {
        panic!("Missing memory management functions for {}", analysis.full_name);
    }
    try!(writeln!(w, ""));
    try!(writeln!(w, "impl {} {{", analysis.name));

    for func_analysis in &analysis.functions {
        try!(function::generate(w, env, func_analysis, false, false, 1));
    }

    try!(writeln!(w, "}}"));

    try!(trait_impls::generate(w, &analysis.name, &analysis.functions, &analysis.specials));

    Ok(())
}

pub fn generate_reexports(env: &Env, analysis: &analysis::record::Info, module_name: &str,
                          contents: &mut Vec<String>) {
    let cfg_condition = general::cfg_condition_string(&analysis.cfg_condition, false, 0);
    let version_cfg = general::version_condition_string(env, analysis.version, false, 0);
    let mut cfg = String::new();
    if let Some(s) = cfg_condition {
        cfg.push_str(&s);
        cfg.push('\n');
    };
    if let Some(s) = version_cfg {
        cfg.push_str(&s);
        cfg.push('\n');
    };
    contents.push(format!(""));
    contents.push(format!("{}mod {};", cfg, module_name));
    contents.push(format!("{}pub use self::{}::{};", cfg, module_name, analysis.name));
}
<commit_msg>Remove empty in records Impl<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::special_functions::Type;
use env::Env;
use super::{function, general, trait_impls};

pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::record::Info) -> Result<()>{
    let type_ = analysis.type_(&env.library);

    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    if let (Some(ref_fn), Some(unref_fn)) = (analysis.specials.get(&Type::Ref),
                                             analysis.specials.get(&Type::Unref)) {
        try!(general::define_shared_type(w, &analysis.name, &type_.c_type, ref_fn, unref_fn));
    } else if let (Some(copy_fn), Some(free_fn)) = (analysis.specials.get(&Type::Copy),
                                                    analysis.specials.get(&Type::Free)) {
        try!(general::define_boxed_type(w, &analysis.name, &type_.c_type, copy_fn, free_fn));
    } else {
        panic!("Missing memory management functions for {}", analysis.full_name);
    }
    try!(writeln!(w, ""));
    try!(write!(w, "impl {} {{", analysis.name));

    for func_analysis in &analysis.functions {
        try!(function::generate(w, env, func_analysis, false, false, 1));
    }

    try!(writeln!(w, "}}"));

    try!(trait_impls::generate(w, &analysis.name, &analysis.functions, &analysis.specials));

    Ok(())
}

pub fn generate_reexports(env: &Env, analysis: &analysis::record::Info, module_name: &str,
                          contents: &mut Vec<String>) {
    let cfg_condition = general::cfg_condition_string(&analysis.cfg_condition, false, 0);
    let version_cfg = general::version_condition_string(env, analysis.version, false, 0);
    let mut cfg = String::new();
    if let Some(s) = cfg_condition {
        cfg.push_str(&s);
        cfg.push('\n');
    };
    if let Some(s) = version_cfg {
        cfg.push_str(&s);
        cfg.push('\n');
    };
    contents.push(format!(""));
    contents.push(format!("{}mod {};", cfg, module_name));
    contents.push(format!("{}pub use self::{}::{};", cfg, module_name, analysis.name));
}
<|endoftext|>


<commit_before>use std::ops::{Mul,Add};

#[derive(Copy,Clone)]
pub struct Vec3<T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> {
    x: T,
    y: T,
    z: T,
}

impl <T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> Vec3<T> {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_length() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<commit_msg>Remove Copy and Clone trait from Vec3<commit_after>use std::ops::{Mul,Add};

pub struct Vec3<T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> {
    x: T,
    y: T,
    z: T,
}

impl <T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> Vec3<T> {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_length() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<|endoftext|>


<commit_before>//! Amazon EC2 Simple Systems Mananager

include!(concat!(env!("OUT_DIR"), "/ssm.rs"));<commit_msg>fix typo in SSM documentation<commit_after>//! Amazon EC2 Simple Systems Manager

include!(concat!(env!("OUT_DIR"), "/ssm.rs"));<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, Read, Write};
use std::process::{Command, Stdio};
use std::os::unix::fs::PermissionsExt;

use crate::elf::{elf64_get_section, elf64_write};

fn object_to_binary(o_name: &str) -> io::Result<(Vec<u8>, u64)> {
    let mut o_file = File::open(o_name)?;
    let text = elf64_get_section(&mut o_file, b".text")?
        .unwrap();
    let bss = elf64_get_section(&mut o_file, b".bss")?
        .unwrap();
    let bss_offset = (text.sh_size + 0x1000 - 1) & !(0x1000 - 1);
    let bss_size = bss.sh_size;

    let bin = Command::new("ld")
        .arg("--oformat")
        .arg("binary")
        .arg("-Ttext")
        .arg("0x401000")
        .arg("-Tbss")
        .arg(format!("0x{:x}", 0x401000 + bss_offset))
        .arg("-o")
        .arg("/dev/stdout")
        .arg(o_name)
        .output()?
        .stdout;

    Ok((bin, bss_size))
}

pub fn assemble(code: &str, out_name: &str, debug: bool) -> io::Result<Option<i32>> {
    let mut command = Command::new("as");
    if debug {
        command.arg("-g");
    }
    let mut child = command
        .arg("-o")
        .arg(out_name)
        .arg("-") // Standard input
        .stdin(Stdio::piped())
        .spawn()?;

    child
        .stdin
        .take()
        .unwrap()
        .write_all(code.as_bytes())?;

    Ok(child.wait()?.code())
}

pub fn link(o_name: &str, out_name: &str, minimal: bool) -> io::Result<Option<i32>> {
    if minimal {
        let (bin, bss_size) = object_to_binary(&o_name)?;

        let mut file = File::create(out_name)?;
        elf64_write(&mut file, &bin, bss_size)?;
        let mut permissions = file.metadata().unwrap().permissions();
        permissions.set_mode(permissions.mode() | 0o111);
        file.set_permissions(permissions)?;
        Ok(Some(0))
    } else {
        Ok(Command::new("ld")
            .arg("-o")
            .arg(out_name)
            .arg(o_name)
            .spawn()?
            .wait()?
            .code())
    }
}
<commit_msg>Pass '.o' to linker as File<commit_after>use std::fs::File;
use std::io::{self, Write};
use std::process::{Command, Stdio};
use std::os::unix::fs::PermissionsExt;

use crate::elf::{elf64_get_section, elf64_write};

fn object_to_binary(mut o_file: File) -> io::Result<(Vec<u8>, u64)> {
    let text = elf64_get_section(&mut o_file, b".text")?
        .unwrap();
    let bss = elf64_get_section(&mut o_file, b".bss")?
        .unwrap();
    let bss_offset = (text.sh_size + 0x1000 - 1) & !(0x1000 - 1);
    let bss_size = bss.sh_size;

    let bin = Command::new("ld")
        .arg("--oformat")
        .arg("binary")
        .arg("-Ttext")
        .arg("0x401000")
        .arg("-Tbss")
        .arg(format!("0x{:x}", 0x401000 + bss_offset))
        .arg("-o")
        .arg("/dev/stdout")
        .arg("/dev/stdin")
        .stdin(o_file)
        .output()?
        .stdout;

    Ok((bin, bss_size))
}

pub fn assemble(code: &str, out_name: &str, debug: bool) -> io::Result<Option<i32>> {
    let mut command = Command::new("as");
    if debug {
        command.arg("-g");
    }
    let mut child = command
        .arg("-o")
        .arg(out_name)
        .arg("-") // Standard input
        .stdin(Stdio::piped())
        .spawn()?;

    child
        .stdin
        .take()
        .unwrap()
        .write_all(code.as_bytes())?;

    Ok(child.wait()?.code())
}

pub fn link(o_name: &str, out_name: &str, minimal: bool) -> io::Result<Option<i32>> {
    let o_file = File::open(o_name)?;
    if minimal {
        let (bin, bss_size) = object_to_binary(o_file)?;

        let mut file = File::create(out_name)?;
        elf64_write(&mut file, &bin, bss_size)?;
        let mut permissions = file.metadata().unwrap().permissions();
        permissions.set_mode(permissions.mode() | 0o111);
        file.set_permissions(permissions)?;
        Ok(Some(0))
    } else {
        Ok(Command::new("ld")
            .arg("-o")
            .arg(out_name)
            .arg("/dev/stdin")
            .stdin(o_file)
            .spawn()?
            .wait()?
            .code())
    }
}
<|endoftext|>


<commit_before>
use num::traits::One;

use na::{Iso2, Rot2, Vec1, Vec2};
use ncollide::shape::{Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};

use constants::*;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

impl Part {

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

struct Attach {
    location: f64,
    rotation: f64
}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

struct WithDepth<T> {
    depth: usize,
    item: T
}

impl Structure {

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        let mut result = Vec::new();
        for item in self.iter() {
            result.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
        }
        result
    }

}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureContextItem<'a> {
    context: Iso2<f64>,
    structure: &'a Structure
}

struct StructureIter<'a> {
    contexts: Vec<Iso2<f64>>,
    work: Vec<WithDepth<&'a Structure>>
}

impl Structure {
    pub fn iter(&self) -> StructureIter {
        let work = vec!(WithDepth { depth: 0, item: self });
        StructureIter { contexts: vec!(Iso2::one()), work: work }
    }
}

impl<'a> Iterator for StructureIter<'a> {

    type Item = StructureContextItem<'a>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = self.contexts[curr_work.depth];

                match curr_work.item {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_depth = curr_work.depth + 1;
                            if self.contexts.len() < next_depth + 1 {
                                self.contexts.push(next_context);
                            } else {
                                self.contexts[next_depth] = next_context;
                            }
                            self.work.push(WithDepth{depth: next_depth, item: &**attachment});
                        })
                    }
                }

                Some(StructureContextItem { context: context, structure: curr_work.item })

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})),
          (Attach {location: 6.0, rotation: 0.0},
           box part(Part::FuelTank {radius: 1.0, length: 1.5})),
           (Attach {location: 8.0, rotation: 0.0},
            box part(Part::Engine {radius: 1.5, length: 0.5, group: 1}))
           ]);
}
<commit_msg>use fold instead, but probably can make this an iterator instead<commit_after>
use num::traits::One;

use na::{Iso2, Rot2, Vec1, Vec2};
use ncollide::shape::{Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};

use constants::*;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

impl Part {

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

struct Attach {
    location: f64,
    rotation: f64
}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

struct WithDepth<T> {
    depth: usize,
    item: T
}

impl Structure {

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        self.iter().fold(Vec::new(), |mut acc, item| {
            acc.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
            acc
        })
    }

}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureContextItem<'a> {
    context: Iso2<f64>,
    structure: &'a Structure
}

struct StructureIter<'a> {
    contexts: Vec<Iso2<f64>>,
    work: Vec<WithDepth<&'a Structure>>
}

impl Structure {
    pub fn iter(&self) -> StructureIter {
        let work = vec!(WithDepth { depth: 0, item: self });
        StructureIter { contexts: vec!(Iso2::one()), work: work }
    }
}

impl<'a> Iterator for StructureIter<'a> {

    type Item = StructureContextItem<'a>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = self.contexts[curr_work.depth];

                match curr_work.item {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_depth = curr_work.depth + 1;
                            if self.contexts.len() < next_depth + 1 {
                                self.contexts.push(next_context);
                            } else {
                                self.contexts[next_depth] = next_context;
                            }
                            self.work.push(WithDepth{depth: next_depth, item: &**attachment});
                        })
                    }
                }

                Some(StructureContextItem { context: context, structure: curr_work.item })

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})),
          (Attach {location: 6.0, rotation: 0.0},
           box part(Part::FuelTank {radius: 1.0, length: 1.5})),
           (Attach {location: 8.0, rotation: 0.0},
            box part(Part::Engine {radius: 1.5, length: 0.5, group: 1}))
           ]);
}
<|endoftext|>