<commit_before>use crate::grammar::ast::{eq::ASTEq, Block, Conditional, Expression};
use crate::grammar::model::{Fragment, HasFragment};
use crate::grammar::parsers::whitespace::token_delimiter;
use crate::grammar::parsers::with_input;
use nom::bytes::complete::tag;
use nom::combinator::{map, opt};
use nom::multi::many0;
use nom::sequence::{delimited, pair, preceded, separated_pair, terminated, tuple};
use nom::IResult;

impl<'s> Conditional<'s> {
    /// `if` token in source code. This constant is unlikely to change.
    pub const IF: &'static str = "if";

    /// `else` token in source code. This constant is unlikely to change.
    pub const ELSE: &'static str = "else";

    // parse an expression followed by a block.
    fn parse_branch(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        separated_pair(Expression::parse, token_delimiter, Block::parse)(input)
    }

    // discards the output of the prefix (T is never used)
    fn parse_branch_prefixed<T>(
        prefix: impl Fn(Fragment<'s>) -> IResult<Fragment<'s>, T>,
    ) -> impl Fn(Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        preceded(prefix, Self::parse_branch)
    }

    // parse the if branch of a conditional expression.
    fn parse_if(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        Self::parse_branch_prefixed(pair(tag(Self::IF), token_delimiter))(input)
    }

    // parse an `else if` branch of a conditional expression.
    fn parse_elif(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        Self::parse_branch_prefixed(pair(
            tag(Self::IF),
            delimited(token_delimiter, tag(Self::ELSE), token_delimiter),
        ))(input)
    }

    // parse all the elifs in a conditional statement
    fn parse_elifs(input: Fragment<'s>) -> IResult<Fragment<'s>, Vec<(Expression<'s>, Block<'s>)>> {
        many0(preceded(token_delimiter, Self::parse_elif))(input)
    }

    // parse the else branch.
    fn parse_else(input: Fragment<'s>) -> IResult<Fragment<'s>, Block<'s>> {
        preceded(pair(tag(Self::ELSE), token_delimiter), Block::parse)(input)
    }

    /// Parse a conditional expression in source code.
    pub fn parse(input: Fragment<'s>) -> IResult<Fragment<'s>, Self> {
        map(
            with_input(tuple((
                Self::parse_if,
                Self::parse_elifs,
                preceded(token_delimiter, opt(Self::parse_else)),
            ))),
            |(consumed, ((pa, pb), elifs, terminal))| Self {
                frag: consumed,
                primary: (Box::new(pa), pb),
                elifs,
                default: terminal,
            },
        )(input)
    }
}

impl<'s> HasFragment<'s> for Conditional<'s> {
    fn get_fragment(&self) -> Fragment<'s> {
        self.frag
    }
}

impl<'s> ASTEq for Conditional<'s> {
    fn ast_eq(fst: &Self, snd: &Self) -> bool {
        ASTEq::ast_eq(&fst.default, &snd.default)
            && ASTEq::ast_eq(&fst.elifs, &snd.elifs)
            && ASTEq::ast_eq(&fst.primary, &snd.primary)
    }
}
<commit_msg>fix unused import<commit_after>use crate::grammar::ast::{eq::ASTEq, Block, Conditional, Expression};
use crate::grammar::model::{Fragment, HasFragment};
use crate::grammar::parsers::whitespace::token_delimiter;
use crate::grammar::parsers::with_input;
use nom::bytes::complete::tag;
use nom::combinator::{map, opt};
use nom::multi::many0;
use nom::sequence::{delimited, pair, preceded, separated_pair, tuple};
use nom::IResult;

impl<'s> Conditional<'s> {
    /// `if` token in source code. This constant is unlikely to change.
    pub const IF: &'static str = "if";

    /// `else` token in source code. This constant is unlikely to change.
    pub const ELSE: &'static str = "else";

    // parse an expression followed by a block.
    fn parse_branch(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        separated_pair(Expression::parse, token_delimiter, Block::parse)(input)
    }

    // discards the output of the prefix (T is never used)
    fn parse_branch_prefixed<T>(
        prefix: impl Fn(Fragment<'s>) -> IResult<Fragment<'s>, T>,
    ) -> impl Fn(Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        preceded(prefix, Self::parse_branch)
    }

    // parse the if branch of a conditional expression.
    fn parse_if(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        Self::parse_branch_prefixed(pair(tag(Self::IF), token_delimiter))(input)
    }

    // parse an `else if` branch of a conditional expression.
    fn parse_elif(input: Fragment<'s>) -> IResult<Fragment<'s>, (Expression<'s>, Block<'s>)> {
        Self::parse_branch_prefixed(pair(
            tag(Self::IF),
            delimited(token_delimiter, tag(Self::ELSE), token_delimiter),
        ))(input)
    }

    // parse all the elifs in a conditional statement
    fn parse_elifs(input: Fragment<'s>) -> IResult<Fragment<'s>, Vec<(Expression<'s>, Block<'s>)>> {
        many0(preceded(token_delimiter, Self::parse_elif))(input)
    }

    // parse the else branch.
    fn parse_else(input: Fragment<'s>) -> IResult<Fragment<'s>, Block<'s>> {
        preceded(pair(tag(Self::ELSE), token_delimiter), Block::parse)(input)
    }

    /// Parse a conditional expression in source code.
    pub fn parse(input: Fragment<'s>) -> IResult<Fragment<'s>, Self> {
        map(
            with_input(tuple((
                Self::parse_if,
                Self::parse_elifs,
                preceded(token_delimiter, opt(Self::parse_else)),
            ))),
            |(consumed, ((pa, pb), elifs, terminal))| Self {
                frag: consumed,
                primary: (Box::new(pa), pb),
                elifs,
                default: terminal,
            },
        )(input)
    }
}

impl<'s> HasFragment<'s> for Conditional<'s> {
    fn get_fragment(&self) -> Fragment<'s> {
        self.frag
    }
}

impl<'s> ASTEq for Conditional<'s> {
    fn ast_eq(fst: &Self, snd: &Self) -> bool {
        ASTEq::ast_eq(&fst.default, &snd.default)
            && ASTEq::ast_eq(&fst.elifs, &snd.elifs)
            && ASTEq::ast_eq(&fst.primary, &snd.primary)
    }
}
<|endoftext|>


<commit_before>//! Reexports of crates, that are part of the public api, for convenience

pub use calloop;
#[cfg(feature = "dbus")]
pub use dbus;
#[cfg(feature = "backend_drm")]
pub use drm;
#[cfg(feature = "backend_drm_gbm")]
pub use gbm;
#[cfg(feature = "backend_drm_gbm")]
pub use image;
#[cfg(feature = "backend_libinput")]
pub use input;
#[cfg(any(feature = "backend_udev", feature = "backend_drm"))]
pub use nix;
#[cfg(feature = "backend_udev")]
pub use udev;
#[cfg(feature = "wayland_frontend")]
pub use wayland_commons;
#[cfg(feature = "wayland_frontend")]
pub use wayland_protocols;
#[cfg(feature = "wayland_frontend")]
pub use wayland_server;
#[cfg(feature = "backend_winit")]
pub use winit;
<commit_msg>reexports: fixup gbm, remove unused image dependency<commit_after>//! Reexports of crates, that are part of the public api, for convenience

pub use calloop;
#[cfg(feature = "dbus")]
pub use dbus;
#[cfg(feature = "backend_drm")]
pub use drm;
#[cfg(feature = "backend_gbm")]
pub use gbm;
#[cfg(feature = "backend_libinput")]
pub use input;
#[cfg(any(feature = "backend_udev", feature = "backend_drm"))]
pub use nix;
#[cfg(feature = "backend_udev")]
pub use udev;
#[cfg(feature = "wayland_frontend")]
pub use wayland_commons;
#[cfg(feature = "wayland_frontend")]
pub use wayland_protocols;
#[cfg(feature = "wayland_frontend")]
pub use wayland_server;
#[cfg(feature = "backend_winit")]
pub use winit;
<|endoftext|>


<commit_before>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod parser;

use std::vec::Vec;
use tokens::*;
use lexer::*;
use parser::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let min_index = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        if index < min_index
        {
            continue;
        }

        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (string, unused) = class_to_plp(&tokens, index);
        }
        /*else if token.name == "type" // || token.type == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }*/
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }
}

fn class_to_plp(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    for (index, token) in tokens.iter().enumerate()
    {
        current_index = index;
    }

    (current_index + 1, plp_string)
}

fn remove_meta(tokens: &mut Vec<Token>)
{
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Ignore all modifiers (public, private, volatile, transient, static, etc.)
        else if token.name.starts_with("mod")
        {
            invalid_indecies.push(index);
        }
        else if token.name == "special.package"
        {
            invalid_indecies.push(index);
            min_index = find_next_semicolon(tokens, index) + 1;
        }
    }

    for (count, index) in invalid_indecies.iter().enumerate()
    {
        tokens.remove(index - count);
    }
}

fn find_next_semicolon(tokens: &Vec<Token>, start: usize) -> usize
{
    for (index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == ";" { return index + start; }
    }

    return 0;
}
<commit_msg>Add documentation<commit_after>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod parser;

use std::vec::Vec;
use tokens::*;
use lexer::*;
use parser::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let min_index = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        if index < min_index
        {
            continue;
        }

        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (string, unused) = class_to_plp(&tokens, index);
        }
        /*else if token.name == "type" // || token.type == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }*/
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }
}

fn class_to_plp(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    for (index, token) in tokens.iter().enumerate()
    {
        current_index = index;
    }

    (current_index + 1, plp_string)
}

fn remove_meta(tokens: &mut Vec<Token>)
{
    // Indecies of tokens vector to be removed
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        // Allow forward skipping (by setting min_index)
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        // Remove imports
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        // Remove comments
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Remove all modifiers (public, private, volatile, transient, static, etc.)
        else if token.name.starts_with("mod")
        {
            invalid_indecies.push(index);
        }
        // Remove package declarations
        else if token.name == "special.package"
        {
            invalid_indecies.push(index);
            min_index = find_next_semicolon(tokens, index) + 1;
        }
    }

    // count := how many indecies have already been removed
    // index := the index in the original tokens vector that should be removed
    for (count, index) in invalid_indecies.iter().enumerate()
    {
        // "index" refers to the index before any others were removed. Therefore, it must be offset by the number of removed tokens
        tokens.remove(index - count);
    }
}

fn find_next_semicolon(tokens: &Vec<Token>, start: usize) -> usize
{
    for (index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == ";" { return index + start; }
    }

    return 0;
}
<|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 https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="AnimatedRGBA",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color",
)}

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="LineHeight",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

${helpers.predefined_type(
    "text-transform",
    "TextTransform",
    "computed::TextTransform::none()",
    engines="gecko servo-2013",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "hyphens",
    "manual none auto",
    engines="gecko",
    gecko_enum_prefix="StyleHyphens",
    animation_value_type="discrete",
    extra_prefixes="moz",
    spec="https://drafts.csswg.org/css-text/#propdef-hyphens",
)}

// TODO: Support <percentage>
${helpers.single_keyword(
    "-moz-text-size-adjust",
    "auto none",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
    gecko_ffi_name="mTextSizeAdjust",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
    alias="-webkit-text-size-adjust",
)}

${helpers.predefined_type(
    "text-indent",
    "LengthPercentage",
    "computed::LengthPercentage::zero()",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
    allow_quirks="Yes",
    servo_restyle_damage = "reflow",
)}

// Also known as "word-wrap" (which is more popular because of IE), but this is
// the preferred name per CSS-TEXT 6.2.
${helpers.predefined_type(
    "overflow-wrap",
    "OverflowWrap",
    "computed::OverflowWrap::Normal",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
    alias="word-wrap",
    needs_context=False,
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-break",
    "WordBreak",
    "computed::WordBreak::Normal",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-word-break",
    needs_context=False,
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if engine == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    has_effect_on_gecko_scrollbars="False"
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if engine == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword(
    "text-align-last",
    "auto start end left right center justify",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align-last",
)}

// TODO make this a shorthand and implement text-align-last/text-align-all
${helpers.predefined_type(
    "text-align",
    "TextAlign",
    "computed::TextAlign::Start",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align",
    servo_restyle_damage = "reflow",
)}

${helpers.predefined_type(
    "letter-spacing",
    "LetterSpacing",
    "computed::LetterSpacing::normal()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-spacing",
    "WordSpacing",
    "computed::WordSpacing::zero()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    extra_gecko_values="break-spaces -moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if engine in ["servo-2013", "servo-2020"]:
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    engines="gecko servo-2013",
    vector=True,
    vector_animation_type="with_zero",
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    simple_vector_bindings=True,
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    engines="gecko",
    initial_specified_value="SpecifiedValue::None",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    engines="gecko",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    engines="gecko",
    initial_specified_value="specified::Color::currentcolor()",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "NonNegativeLengthOrNumber",
    "generics::length::LengthOrNumber::Number(From::from(8.0))",
    engines="gecko",
    animation_value_type="LengthOrNumber",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

${helpers.predefined_type(
    "line-break",
    "LineBreak",
    "computed::LineBreak::Auto",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-3/#line-break-property",
    needs_context=False,
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    engines="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    engines="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-width",
    "BorderSideWidth",
    "crate::values::computed::NonNegativeLength::new(0.)",
    engines="gecko",
    initial_specified_value="specified::BorderSideWidth::zero()",
    computed_type="crate::values::computed::NonNegativeLength",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
    animation_value_type="discrete",
)}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword(
    "ruby-align",
    "space-around start center space-between",
    engines="gecko",
    animation_value_type="discrete",
    gecko_enum_prefix="StyleRubyAlign",
    spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}

${helpers.single_keyword(
    "ruby-position",
    "over under",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
)}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword(
    "text-combine-upright",
    "none all",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright",
)}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "text-rendering",
    "auto optimizespeed optimizelegibility geometricprecision",
    engines="gecko servo-2013 servo-2020",
    gecko_enum_prefix="StyleTextRendering",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
    servo_restyle_damage="rebuild_and_reflow",
)}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword(
    "-moz-control-character-visibility",
    "hidden visible",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
    animation_value_type="none",
    gecko_ffi_name="mControlCharacterVisibility",
    spec="Nonstandard",
)}

// text underline offset
${helpers.predefined_type(
    "text-underline-offset",
    "TextDecorationLength",
    "generics::text::GenericTextDecorationLength::Auto",
    engines="gecko",
    animation_value_type="ComputedValue",
    gecko_pref="layout.css.text-underline-offset.enabled",
    has_effect_on_gecko_scrollbars=False,
    spec="https://drafts.csswg.org/css-text-decor-4/#underline-offset",
)}

// text decoration skip ink
${helpers.predefined_type(
    "text-decoration-skip-ink",
    "TextDecorationSkipInk",
    "computed::TextDecorationSkipInk::Auto",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    gecko_pref="layout.css.text-decoration-skip-ink.enabled",
    has_effect_on_gecko_scrollbars=False,
    spec="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property",
)}
<commit_msg>style: convert NS_STYLE_TEXT_SIZE_ADJUST_* to an enum class in nsStyleConsts.h<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 https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="AnimatedRGBA",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color",
)}

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="LineHeight",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

${helpers.predefined_type(
    "text-transform",
    "TextTransform",
    "computed::TextTransform::none()",
    engines="gecko servo-2013",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "hyphens",
    "manual none auto",
    engines="gecko",
    gecko_enum_prefix="StyleHyphens",
    animation_value_type="discrete",
    extra_prefixes="moz",
    spec="https://drafts.csswg.org/css-text/#propdef-hyphens",
)}

// TODO: Support <percentage>
${helpers.single_keyword(
    "-moz-text-size-adjust",
    "auto none",
    engines="gecko",
    gecko_enum_prefix="StyleTextSizeAdjust",
    gecko_ffi_name="mTextSizeAdjust",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
    alias="-webkit-text-size-adjust",
)}

${helpers.predefined_type(
    "text-indent",
    "LengthPercentage",
    "computed::LengthPercentage::zero()",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
    allow_quirks="Yes",
    servo_restyle_damage = "reflow",
)}

// Also known as "word-wrap" (which is more popular because of IE), but this is
// the preferred name per CSS-TEXT 6.2.
${helpers.predefined_type(
    "overflow-wrap",
    "OverflowWrap",
    "computed::OverflowWrap::Normal",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
    alias="word-wrap",
    needs_context=False,
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-break",
    "WordBreak",
    "computed::WordBreak::Normal",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-word-break",
    needs_context=False,
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if engine == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    has_effect_on_gecko_scrollbars="False"
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if engine == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword(
    "text-align-last",
    "auto start end left right center justify",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align-last",
)}

// TODO make this a shorthand and implement text-align-last/text-align-all
${helpers.predefined_type(
    "text-align",
    "TextAlign",
    "computed::TextAlign::Start",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align",
    servo_restyle_damage = "reflow",
)}

${helpers.predefined_type(
    "letter-spacing",
    "LetterSpacing",
    "computed::LetterSpacing::normal()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-spacing",
    "WordSpacing",
    "computed::WordSpacing::zero()",
    engines="gecko servo-2013 servo-2020",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    extra_gecko_values="break-spaces -moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if engine in ["servo-2013", "servo-2020"]:
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    engines="gecko servo-2013",
    vector=True,
    vector_animation_type="with_zero",
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    simple_vector_bindings=True,
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    engines="gecko",
    initial_specified_value="SpecifiedValue::None",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    engines="gecko",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    engines="gecko",
    initial_specified_value="specified::Color::currentcolor()",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "NonNegativeLengthOrNumber",
    "generics::length::LengthOrNumber::Number(From::from(8.0))",
    engines="gecko",
    animation_value_type="LengthOrNumber",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

${helpers.predefined_type(
    "line-break",
    "LineBreak",
    "computed::LineBreak::Auto",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-3/#line-break-property",
    needs_context=False,
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    engines="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    engines="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-width",
    "BorderSideWidth",
    "crate::values::computed::NonNegativeLength::new(0.)",
    engines="gecko",
    initial_specified_value="specified::BorderSideWidth::zero()",
    computed_type="crate::values::computed::NonNegativeLength",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
    animation_value_type="discrete",
)}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword(
    "ruby-align",
    "space-around start center space-between",
    engines="gecko",
    animation_value_type="discrete",
    gecko_enum_prefix="StyleRubyAlign",
    spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}

${helpers.single_keyword(
    "ruby-position",
    "over under",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
)}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword(
    "text-combine-upright",
    "none all",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright",
)}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "text-rendering",
    "auto optimizespeed optimizelegibility geometricprecision",
    engines="gecko servo-2013 servo-2020",
    gecko_enum_prefix="StyleTextRendering",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
    servo_restyle_damage="rebuild_and_reflow",
)}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword(
    "-moz-control-character-visibility",
    "hidden visible",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
    animation_value_type="none",
    gecko_ffi_name="mControlCharacterVisibility",
    spec="Nonstandard",
)}

// text underline offset
${helpers.predefined_type(
    "text-underline-offset",
    "TextDecorationLength",
    "generics::text::GenericTextDecorationLength::Auto",
    engines="gecko",
    animation_value_type="ComputedValue",
    gecko_pref="layout.css.text-underline-offset.enabled",
    has_effect_on_gecko_scrollbars=False,
    spec="https://drafts.csswg.org/css-text-decor-4/#underline-offset",
)}

// text decoration skip ink
${helpers.predefined_type(
    "text-decoration-skip-ink",
    "TextDecorationSkipInk",
    "computed::TextDecorationSkipInk::Auto",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    gecko_pref="layout.css.text-decoration-skip-ink.enabled",
    has_effect_on_gecko_scrollbars=False,
    spec="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property",
)}
<|endoftext|>


<commit_before>// Copyright 2017-2018 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Roughtime server
//!
//! # Configuration
//! The `roughenough` server is configured via a YAML config file. See the documentation
//! for [FileConfig](struct.FileConfig.html) for details.
//!
//! To run the server:
//!
//! ```bash
//! $ cargo run --release --bin server /path/to/config.file
//! ```
//!

extern crate byteorder;
extern crate ctrlc;
extern crate hex;
#[macro_use]
extern crate log;
extern crate mio;
extern crate mio_extras;
extern crate ring;
extern crate roughenough;
extern crate simple_logger;
extern crate time;
extern crate untrusted;
extern crate yaml_rust;

use std::env;
use std::io::ErrorKind;
use std::process;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;

use mio::net::UdpSocket;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::timer::Timer;

use byteorder::{LittleEndian, WriteBytesExt};

use roughenough::config;
use roughenough::config::ServerConfig;
use roughenough::kms;
use roughenough::key::{LongTermKey, OnlineKey};
use roughenough::merkle::MerkleTree;
use roughenough::{Error, RtMessage, Tag};
use roughenough::{MIN_REQUEST_LENGTH, VERSION};

const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);

fn make_response(srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
    let mut index = [0; 4];
    (&mut index as &mut [u8])
        .write_u32::<LittleEndian>(idx)
        .unwrap();

    let sig_bytes = srep.get_field(Tag::SIG).unwrap();
    let srep_bytes = srep.get_field(Tag::SREP).unwrap();

    let mut response = RtMessage::new(5);
    response.add_field(Tag::SIG, sig_bytes).unwrap();
    response.add_field(Tag::PATH, path).unwrap();
    response.add_field(Tag::SREP, srep_bytes).unwrap();
    response.add_field(Tag::CERT, cert_bytes).unwrap();
    response.add_field(Tag::INDX, &index).unwrap();

    response
}

// extract the client's nonce from its request
fn nonce_from_request(buf: &[u8], num_bytes: usize) -> Result<&[u8], Error> {
    if num_bytes < MIN_REQUEST_LENGTH as usize {
        return Err(Error::RequestTooShort);
    }

    let tag_count = &buf[..4];
    let expected_nonc = &buf[8..12];
    let expected_pad = &buf[12..16];

    let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
    let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
    let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

    if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
        Ok(&buf[0x10..0x50])
    } else {
        Err(Error::InvalidRequest)
    }
}

fn polling_loop(config: &Box<ServerConfig>, online_key: &mut OnlineKey, cert_bytes: &[u8]) {
    let response_counter = AtomicUsize::new(0);
    let keep_running = Arc::new(AtomicBool::new(true));
    let kr = keep_running.clone();

    ctrlc::set_handler(move || kr.store(false, Ordering::Release))
        .expect("failed setting Ctrl-C handler");

    let sock_addr = config.socket_addr().expect("");
    let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");
    let poll_duration = Some(Duration::from_millis(100));

    let mut timer: Timer<()> = Timer::default();
    timer.set_timeout(config.status_interval(), ());

    let mut buf = [0u8; 65_536];
    let mut events = Events::with_capacity(32);
    let mut num_bad_requests = 0u64;

    let poll = Poll::new().unwrap();
    poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
        .unwrap();
    poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
        .unwrap();

    let mut merkle = MerkleTree::new();
    let mut requests = Vec::with_capacity(config.batch_size() as usize);

    macro_rules! check_ctrlc {
        () => {
            if !keep_running.load(Ordering::Acquire) {
                warn!("Ctrl-C caught, exiting...");
                return;
            }
        };
    }

    loop {
        check_ctrlc!();

        poll.poll(&mut events, poll_duration).expect("poll failed");

        for event in events.iter() {
            match event.token() {
                MESSAGE => {
                    let mut done = false;

                    'process_batch: loop {
                        check_ctrlc!();

                        merkle.reset();
                        requests.clear();

                        let resp_start = response_counter.load(Ordering::SeqCst);

                        for i in 0..config.batch_size() {
                            match socket.recv_from(&mut buf) {
                                Ok((num_bytes, src_addr)) => {
                                    if let Ok(nonce) = nonce_from_request(&buf, num_bytes) {
                                        requests.push((Vec::from(nonce), src_addr));
                                        merkle.push_leaf(nonce);
                                    } else {
                                        num_bad_requests += 1;
                                        info!(
                                            "Invalid request ({} bytes) from {} (#{} in batch, resp #{})",
                                            num_bytes, src_addr, i, resp_start + i as usize
                                        );
                                    }
                                }
                                Err(e) => match e.kind() {
                                    ErrorKind::WouldBlock => {
                                        done = true;
                                        break;
                                    }
                                    _ => {
                                        error!(
                                            "Error receiving from socket: {:?}: {:?}",
                                            e.kind(),
                                            e
                                        );
                                        break;
                                    }
                                },
                            };
                        }

                        if requests.is_empty() {
                            break 'process_batch;
                        }

                        let merkle_root = merkle.compute_root();
                        let srep = online_key.make_srep(time::get_time(), &merkle_root);

                        for (i, &(ref nonce, ref src_addr)) in requests.iter().enumerate() {
                            let paths = merkle.get_paths(i);

                            let resp = make_response(&srep, cert_bytes, &paths, i as u32);
                            let resp_bytes = resp.encode().unwrap();

                            let bytes_sent = socket
                                .send_to(&resp_bytes, &src_addr)
                                .expect("send_to failed");
                            let num_responses = response_counter.fetch_add(1, Ordering::SeqCst);

                            info!(
                                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                                bytes_sent,
                                src_addr,
                                hex::encode(&nonce[0..4]),
                                i,
                                num_responses
                            );
                        }
                        if done {
                            break 'process_batch;
                        }
                    }
                }

                STATUS => {
                    info!(
                        "responses {}, invalid requests {}",
                        response_counter.load(Ordering::SeqCst),
                        num_bad_requests
                    );

                    timer.set_timeout(config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
    }
}

fn kms_support_str() -> &'static str {
    if cfg!(feature = "awskms") {
        " (+AWS KMS)"
    } else if cfg!(feature = "gcpkms") {
        " (+GCP KMS)"
    } else {
        ""
    }
}

pub fn main() {
    use log::Level;

    simple_logger::init_with_level(Level::Info).unwrap();

    info!("Roughenough server v{}{} starting", VERSION, kms_support_str());

    let mut args = env::args();
    if args.len() != 2 {
        error!("Usage: server <ENV|/path/to/config.yaml>");
        process::exit(1);
    }

    let arg1 = args.nth(1).unwrap();
    let config = match config::make_config(&arg1) {
        Err(e) => {
            error!("{:?}", e);
            process::exit(1)
        }
        Ok(ref cfg) if !config::is_valid_config(&cfg) => process::exit(1),
        Ok(cfg) => cfg,
    };

    let mut online_key = OnlineKey::new();
    let public_key: String;

    let cert_bytes = {
        let seed = match kms::load_seed(&config) {
            Ok(seed) => seed,
            Err(e) => {
                error!("Failed to load seed: {:#?}", e);
                process::exit(1);
            }
        };
        let mut long_term_key = LongTermKey::new(&seed);
        public_key = hex::encode(long_term_key.public_key());

        long_term_key.make_cert(&online_key).encode().unwrap()
    };

    info!("Long-term public key    : {}", public_key);
    info!("Online public key       : {}", online_key);
    info!("Max response batch size : {}", config.batch_size());
    info!("Status updates every    : {} seconds", config.status_interval().as_secs());
    info!("Server listening on     : {}:{}", config.interface(), config.port());

    polling_loop(&config, &mut online_key, &cert_bytes);

    info!("Done.");
    process::exit(0);
}
<commit_msg>Exact code into Server struct<commit_after>// Copyright 2017-2018 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Roughtime server
//!
//! # Configuration
//! The `roughenough` server is configured via a YAML config file. See the documentation
//! for [FileConfig](struct.FileConfig.html) for details.
//!
//! To run the server:
//!
//! ```bash
//! $ cargo run --release --bin server /path/to/config.file
//! ```
//!

extern crate byteorder;
extern crate ctrlc;
extern crate hex;
#[macro_use]
extern crate log;
extern crate mio;
extern crate mio_extras;
extern crate ring;
extern crate roughenough;
extern crate simple_logger;
extern crate time;
extern crate untrusted;
extern crate yaml_rust;

use std::env;
use std::io::ErrorKind;
use std::process;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::net::SocketAddr;

use mio::net::UdpSocket;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::timer::Timer;

use byteorder::{LittleEndian, WriteBytesExt};

use roughenough::config;
use roughenough::config::ServerConfig;
use roughenough::kms;
use roughenough::key::{LongTermKey, OnlineKey};
use roughenough::merkle::MerkleTree;
use roughenough::{Error, RtMessage, Tag};
use roughenough::{MIN_REQUEST_LENGTH, VERSION};

macro_rules! check_ctrlc {
    ($keep_running:expr) => {
        if !$keep_running.load(Ordering::Acquire) {
            warn!("Ctrl-C caught, exiting...");
            return true;
        }
    }
}

const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);

fn make_response(srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
    let mut index = [0; 4];
    (&mut index as &mut [u8])
        .write_u32::<LittleEndian>(idx)
        .unwrap();

    let sig_bytes = srep.get_field(Tag::SIG).unwrap();
    let srep_bytes = srep.get_field(Tag::SREP).unwrap();

    let mut response = RtMessage::new(5);
    response.add_field(Tag::SIG, sig_bytes).unwrap();
    response.add_field(Tag::PATH, path).unwrap();
    response.add_field(Tag::SREP, srep_bytes).unwrap();
    response.add_field(Tag::CERT, cert_bytes).unwrap();
    response.add_field(Tag::INDX, &index).unwrap();

    response
}

// extract the client's nonce from its request
fn nonce_from_request(buf: &[u8], num_bytes: usize) -> Result<&[u8], Error> {
    if num_bytes < MIN_REQUEST_LENGTH as usize {
        return Err(Error::RequestTooShort);
    }

    let tag_count = &buf[..4];
    let expected_nonc = &buf[8..12];
    let expected_pad = &buf[12..16];

    let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
    let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
    let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

    if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
        Ok(&buf[0x10..0x50])
    } else {
        Err(Error::InvalidRequest)
    }
}

struct Server {
    config: Box<ServerConfig>,
    online_key: OnlineKey,
    cert_bytes: Vec<u8>,

    response_counter: AtomicUsize,
    num_bad_requests: u64,

    socket: UdpSocket,
    keep_running: Arc<AtomicBool>,
    poll_duration: Option<Duration>,
    timer: Timer<()>,
    poll: Poll,
    events: Events,
    merkle: MerkleTree,
    requests: Vec<(Vec<u8>, SocketAddr)>,
    buf: [u8; 65_536],

}

impl Server {
    pub fn new(config: Box<ServerConfig>, online_key: OnlineKey, cert_bytes: Vec<u8>) -> Server {
        let response_counter = AtomicUsize::new(0);
        let keep_running = Arc::new(AtomicBool::new(true));

        let sock_addr = config.socket_addr().expect("");
        let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");
        let poll_duration = Some(Duration::from_millis(100));

        let mut timer: Timer<()> = Timer::default();
        timer.set_timeout(config.status_interval(), ());

        let poll = Poll::new().unwrap();
        poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
            .unwrap();
        poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
            .unwrap();

        let mut merkle = MerkleTree::new();
        let mut requests = Vec::with_capacity(config.batch_size() as usize);

        Server {
            config,
            online_key,
            cert_bytes,

            response_counter,
            num_bad_requests: 0,
            socket,
            keep_running,
            poll_duration,
            timer,
            poll,
            events: Events::with_capacity(32),
            merkle,
            requests,
            buf: [0u8; 65_536]
        }

    }

    fn get_keep_running(&self) -> Arc<AtomicBool> {
        return self.keep_running.clone()
    }

    fn process_events(&mut self) -> bool {
        self.poll.poll(&mut self.events, self.poll_duration).expect("poll failed");

        for event in self.events.iter() {
            match event.token() {
                MESSAGE => {
                    let mut done = false;

                    'process_batch: loop {
                        check_ctrlc!(self.keep_running);

                        self.merkle.reset();
                        self.requests.clear();

                        let resp_start = self.response_counter.load(Ordering::SeqCst);

                        for i in 0..self.config.batch_size() {
                            match self.socket.recv_from(&mut self.buf) {
                                Ok((num_bytes, src_addr)) => {
                                    if let Ok(nonce) = nonce_from_request(&self.buf, num_bytes) {
                                        self.requests.push((Vec::from(nonce), src_addr));
                                        self.merkle.push_leaf(nonce);
                                    } else {
                                        self.num_bad_requests += 1;
                                        info!(
                                            "Invalid request ({} bytes) from {} (#{} in batch, resp #{})",
                                            num_bytes, src_addr, i, resp_start + i as usize
                                        );
                                    }
                                }
                                Err(e) => match e.kind() {
                                    ErrorKind::WouldBlock => {
                                        done = true;
                                        break;
                                    }
                                    _ => {
                                        error!(
                                            "Error receiving from socket: {:?}: {:?}",
                                            e.kind(),
                                            e
                                        );
                                        break;
                                    }
                                },
                            };
                        }

                        if self.requests.is_empty() {
                            break 'process_batch;
                        }

                        let merkle_root = self.merkle.compute_root();
                        let srep = self.online_key.make_srep(time::get_time(), &merkle_root);

                        for (i, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() {
                            let paths = self.merkle.get_paths(i);

                            let resp = make_response(&srep, &self.cert_bytes, &paths, i as u32);
                            let resp_bytes = resp.encode().unwrap();

                            let bytes_sent = self.socket
                                .send_to(&resp_bytes, &src_addr)
                                .expect("send_to failed");
                            let num_responses = self.response_counter.fetch_add(1, Ordering::SeqCst);

                            info!(
                                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                                bytes_sent,
                                src_addr,
                                hex::encode(&nonce[0..4]),
                                i,
                                num_responses
                            );
                        }
                        if done {
                            break 'process_batch;
                        }
                    }
                }

                STATUS => {
                    info!(
                        "responses {}, invalid requests {}",
                        self.response_counter.load(Ordering::SeqCst),
                        self.num_bad_requests
                    );

                    self.timer.set_timeout(self.config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
        false
    }
}

fn polling_loop(config: Box<ServerConfig>, online_key: OnlineKey, cert_bytes: Vec<u8>) -> bool {
/*    let response_counter = AtomicUsize::new(0);
    let keep_running = Arc::new(AtomicBool::new(true));
    let kr = keep_running.clone();

    ctrlc::set_handler(move || kr.store(false, Ordering::Release))
        .expect("failed setting Ctrl-C handler");

    let sock_addr = config.socket_addr().expect("");
    let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");
    let poll_duration = Some(Duration::from_millis(100));

    let mut timer: Timer<()> = Timer::default();
    timer.set_timeout(config.status_interval(), ());

    let mut buf = [0u8; 65_536];
    let mut events = Events::with_capacity(32);
    let mut num_bad_requests = 0u64;

    let poll = Poll::new().unwrap();
    poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
        .unwrap();
    poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
        .unwrap();

    let mut merkle = MerkleTree::new();
    let mut requests = Vec::with_capacity(config.batch_size() as usize);*/

    let mut server = Server::new(config, online_key, cert_bytes);
    let kr = server.get_keep_running();
    let kr_new = kr.clone();

    ctrlc::set_handler(move || kr.store(false, Ordering::Release))
        .expect("failed setting Ctrl-C handler");

    loop {
        check_ctrlc!(kr_new);
        if server.process_events() {
            return true;
        }

    }
}

fn kms_support_str() -> &'static str {
    if cfg!(feature = "awskms") {
        " (+AWS KMS)"
    } else if cfg!(feature = "gcpkms") {
        " (+GCP KMS)"
    } else {
        ""
    }
}

pub fn main() {
    use log::Level;

    simple_logger::init_with_level(Level::Info).unwrap();

    info!("Roughenough server v{}{} starting", VERSION, kms_support_str());

    let mut args = env::args();
    if args.len() != 2 {
        error!("Usage: server <ENV|/path/to/config.yaml>");
        process::exit(1);
    }

    let arg1 = args.nth(1).unwrap();
    let config = match config::make_config(&arg1) {
        Err(e) => {
            error!("{:?}", e);
            process::exit(1)
        }
        Ok(ref cfg) if !config::is_valid_config(&cfg) => process::exit(1),
        Ok(cfg) => cfg,
    };

    let mut online_key = OnlineKey::new();
    let public_key: String;

    let cert_bytes = {
        let seed = match kms::load_seed(&config) {
            Ok(seed) => seed,
            Err(e) => {
                error!("Failed to load seed: {:#?}", e);
                process::exit(1);
            }
        };
        let mut long_term_key = LongTermKey::new(&seed);
        public_key = hex::encode(long_term_key.public_key());

        long_term_key.make_cert(&online_key).encode().unwrap()
    };

    info!("Long-term public key    : {}", public_key);
    info!("Online public key       : {}", online_key);
    info!("Max response batch size : {}", config.batch_size());
    info!("Status updates every    : {} seconds", config.status_interval().as_secs());
    info!("Server listening on     : {}:{}", config.interface(), config.port());

    polling_loop(config, online_key, cert_bytes);

    info!("Done.");
    process::exit(0);
}
<|endoftext|>


<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        arcs[a][b].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
    }

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;

            println(fmt!("start at (%i,%i)",c,d));

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                   println(fmt!("(%i,%i) : (%i,%i)",c,d,x,y));
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut newvertex = false;
                            let mut uncolored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color < 0 {
                                    uncolored = true; }
                            }
                            if uncolored {
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        do shared_arcs[y][x].read |src| {
                                            dest.color = src.color;
                                        }
                                        newvertex = true;
                                    }
                                }
                            }
                            if newvertex { // then we have a new vertex
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                    Some(e) => {
//                        println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        // not in any tree
                        let coord = (e.dest.x,e.dest.y);
//                        println(fmt!("before runtime error? %?",coord));
                        if !visited.contains_key(&coord){
 // use visited hashmap to figure out if we're at a new vertex.
                            visited.insert(coord,true);
                            x = e.dest.x;
                            y = e.dest.y;
                            newvisit = true;
//                            println(fmt!("%? %f",coord,e.cost));
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

        }
    }
}
<commit_msg>colors seem to fix some of the problems.<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        do arcs[a][b].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
    }

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;

            println(fmt!("start at (%i,%i)",c,d));

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                   println(fmt!("(%i,%i) : (%i,%i)",c,d,x,y));
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut newvertex = false;
                            let mut uncolored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color < 0 {
                                    uncolored = true; }
                            }
                            if uncolored {
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        do shared_arcs[y][x].read |src| {
                                            dest.color = src.color;
                                        }
                                        newvertex = true;
                                    }
                                }
                            }
                            if newvertex { // then we have a new vertex
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                    Some(e) => {
//                        println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        // not in any tree
                        let coord = (e.dest.x,e.dest.y);
//                        println(fmt!("before runtime error? %?",coord));
                        if !visited.contains_key(&coord){
 // use visited hashmap to figure out if we're at a new vertex.
                            visited.insert(coord,true);
                            x = e.dest.x;
                            y = e.dest.y;
                            newvisit = true;
//                            println(fmt!("%? %f",coord,e.cost));
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

        }
    }
}
<|endoftext|>


<commit_before>use git2::Repository;
use std::{error, fs, io, path, result};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Setup CaSILE config file(s) on new repository
pub fn run(path: path::PathBuf) -> Result<()> {
    crate::header("setup-header");
    let metadata = fs::metadata(&path)?;
    match metadata.is_dir() {
        true => match Repository::open(path) {
            Ok(_repo) => Ok(()),
            Err(_error) => Err(Box::new(io::Error::new(
                io::ErrorKind::InvalidInput,
                "", // config.locale.translate("setup-error-not-git", None),
            ))),
        },
        false => Err(Box::new(io::Error::new(
            io::ErrorKind::InvalidInput,
            "", // config.locale.translate("setup-error-not-dir", None),
        ))),
    }
}
<commit_msg>chore(i18n): Use new LocalText interface for error messages<commit_after>use crate::i18n::LocalText;
use git2::Repository;
use std::{error, fs, io, path, result};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Setup CaSILE config file(s) on new repository
pub fn run(path: path::PathBuf) -> Result<()> {
    crate::header("setup-header");
    let metadata = fs::metadata(&path)?;
    match metadata.is_dir() {
        true => match Repository::open(path) {
            Ok(_repo) => Ok(()),
            Err(_error) => {
                let error_text = LocalText::new("setup-error-not-git");
                Err(Box::new(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    error_text.fmt(None),
                )))
            }
        },
        false => {
            let error_text = LocalText::new("setup-error-not-dir");
            Err(Box::new(io::Error::new(
                io::ErrorKind::InvalidInput,
                error_text.fmt(None),
            )))
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sort"]
#![feature(macro_rules)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;

use std::io::{print, File, BufferedReader};
use std::io::stdio::stdin_raw;
use std::str::Chars;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "sort";
static VERSION:  &'static str = "0.0.1";

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].as_slice();
    let opts = [
        getopts::optflag("n", "numeric-sort", "compare according to string numerical value"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("Usage: {0} [OPTION]... [FILE]...", program);
        println!("Write the sorted concatenation of all FILE(s) to standard output.");
        println!("");
        print(getopts::usage("Mandatory arguments for long options are mandatory for short options too.", &opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }

    if matches.opt_present("version") {
        println!("sort 1.0.0");
        return 0;
    }

    let mut numeric = false;
    if matches.opt_present("numeric-sort") {
        numeric = true;
    }

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_string());
    }

    exec(files, numeric);

    0
}

fn exec(files: Vec<String>, numeric: bool) {
    for path in files.iter() {
        let (reader, _) = match open(path.as_slice()) {
            Some(x) => x,
            None => continue,
        };

        let mut buf_reader = BufferedReader::new(reader);
        let mut lines = Vec::new();

        for line in buf_reader.lines() {
            match line {
                Ok(n) => {
                    lines.push(n);
                },
                _ => break
            }
        }

        if numeric {
            lines.sort_by(frac_compare);
        } else {
            lines.sort();
        }
        for line in lines.iter() {
            print!("{}", line)
        }
    }
}

fn skip_zeros(mut char_a: char, char_iter: &mut Chars, ret: Ordering) -> Ordering {
    char_a = match char_iter.next() { None => 0 as char, Some(t) => t };
    while char_a == '0' {
        char_a = match char_iter.next() { None => return Equal, Some(t) => t };
    }
    if char_a.is_digit(10) { ret } else { Equal }
}

/// Compares two decimal fractions as strings (n < 1)
/// This requires the strings to start with a decimal, otherwise it's treated as 0
fn frac_compare(a: &String, b: &String) -> Ordering {
    let a_chars = &mut a.as_slice().chars();
    let b_chars = &mut b.as_slice().chars();

    let mut char_a = match a_chars.next() { None => 0 as char, Some(t) => t };
    let mut char_b = match b_chars.next() { None => 0 as char, Some(t) => t };

    if char_a == DECIMAL_PT && char_b == DECIMAL_PT {
        while char_a == char_b {
            char_a = match a_chars.next() { None => 0 as char, Some(t) => t };
            char_b = match b_chars.next() { None => 0 as char, Some(t) => t };
            // hit the end at the same time, they are equal
            if !char_a.is_digit(10) {
                return Equal;
            }
        }
        if char_a.is_digit(10) && char_b.is_digit(10) {
            (char_a as int).cmp(&(char_b as int))
        } else if char_a.is_digit(10) {
            skip_zeros(char_a, a_chars, Greater)
        } else if char_b.is_digit(10) {
            skip_zeros(char_b, b_chars, Less)
        } else { Equal }
    } else if char_a == DECIMAL_PT {
        skip_zeros(char_a, a_chars, Greater)
    } else if char_b == DECIMAL_PT {
        skip_zeros(char_b, b_chars, Less)
    } else { Equal }
}

// from cat.rs
fn open<'a>(path: &str) -> Option<(Box<Reader + 'a>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}

<commit_msg>sort: implement --reverse<commit_after>#![crate_name = "sort"]
#![feature(macro_rules)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;

use std::fmt::Show;
use std::io::{print, File, BufferedReader};
use std::io::stdio::stdin_raw;
use std::str::Chars;

#[path = "../common/util.rs"]
mod util;

static NAME: &'static str = "sort";
static VERSION:  &'static str = "0.0.1";

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].as_slice();
    let opts = [
        getopts::optflag("n", "numeric-sort", "compare according to string numerical value"),
        getopts::optflag("r", "reverse", "reverse the output"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("Usage: {0} [OPTION]... [FILE]...", program);
        println!("Write the sorted concatenation of all FILE(s) to standard output.");
        println!("");
        print(getopts::usage("Mandatory arguments for long options are mandatory for short options too.", &opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }

    if matches.opt_present("version") {
        println!("sort 1.0.0");
        return 0;
    }

    let numeric = matches.opt_present("numeric-sort");
    let reverse = matches.opt_present("reverse");

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_string());
    }

    exec(files, numeric, reverse);

    0
}

fn exec(files: Vec<String>, numeric: bool, reverse: bool) {
    for path in files.iter() {
        let (reader, _) = match open(path.as_slice()) {
            Some(x) => x,
            None => continue,
        };

        let mut buf_reader = BufferedReader::new(reader);
        let mut lines = Vec::new();

        for line in buf_reader.lines() {
            match line {
                Ok(n) => {
                    lines.push(n);
                },
                _ => break
            }
        }

        if numeric {
            lines.sort_by(frac_compare);
        } else {
            lines.sort();
        }

        let iter = lines.iter();
        if reverse {
            print_sorted(iter.rev());
        } else {
            print_sorted(iter)
        };
    }
}

fn skip_zeros(mut char_a: char, char_iter: &mut Chars, ret: Ordering) -> Ordering {
    char_a = match char_iter.next() { None => 0 as char, Some(t) => t };
    while char_a == '0' {
        char_a = match char_iter.next() { None => return Equal, Some(t) => t };
    }
    if char_a.is_digit(10) { ret } else { Equal }
}

/// Compares two decimal fractions as strings (n < 1)
/// This requires the strings to start with a decimal, otherwise it's treated as 0
fn frac_compare(a: &String, b: &String) -> Ordering {
    let a_chars = &mut a.as_slice().chars();
    let b_chars = &mut b.as_slice().chars();

    let mut char_a = match a_chars.next() { None => 0 as char, Some(t) => t };
    let mut char_b = match b_chars.next() { None => 0 as char, Some(t) => t };

    if char_a == DECIMAL_PT && char_b == DECIMAL_PT {
        while char_a == char_b {
            char_a = match a_chars.next() { None => 0 as char, Some(t) => t };
            char_b = match b_chars.next() { None => 0 as char, Some(t) => t };
            // hit the end at the same time, they are equal
            if !char_a.is_digit(10) {
                return Equal;
            }
        }
        if char_a.is_digit(10) && char_b.is_digit(10) {
            (char_a as int).cmp(&(char_b as int))
        } else if char_a.is_digit(10) {
            skip_zeros(char_a, a_chars, Greater)
        } else if char_b.is_digit(10) {
            skip_zeros(char_b, b_chars, Less)
        } else { Equal }
    } else if char_a == DECIMAL_PT {
        skip_zeros(char_a, a_chars, Greater)
    } else if char_b == DECIMAL_PT {
        skip_zeros(char_b, b_chars, Less)
    } else { Equal }
}

#[inline(always)]
fn print_sorted<T: Iterator<S>, S: Show>(mut iter: T) {
    for line in iter {
        print!("{}", line);
    }
}

// from cat.rs
fn open<'a>(path: &str) -> Option<(Box<Reader + 'a>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}

<|endoftext|>