<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, Location, NamedItem, WithLocation};
mod requireable_field;

use super::FeatureFlags;
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, InlineFragment, LinkedField,
    OperationDefinition, Program, ScalarField, Selection, Transformed, Transformer,
    ValidationMessage, ValidationResult, Value,
};
use interner::Intern;
use interner::StringKey;
use lazy_static::lazy_static;
use requireable_field::{RequireableField, RequiredMetadata};
use std::mem;
use std::sync::Arc;

lazy_static! {
    pub static ref REQUIRED_DIRECTIVE_NAME: StringKey = "required".intern();
    pub static ref ACTION_ARGUMENT: StringKey = "action".intern();
    pub static ref REQUIRED_METADATA_KEY: StringKey = "__required".intern();
    pub static ref PATH_METADATA_ARGUMENT: StringKey = "path".intern();
    static ref THROW_ACTION: StringKey = "THROW".intern();
    static ref LOG_ACTION: StringKey = "LOG".intern();
    static ref NONE_ACTION: StringKey = "NONE".intern();
}

pub fn required_directive(
    program: &Program,
    feature_flags: &FeatureFlags,
) -> ValidationResult<Program> {
    let mut transform =
        RequiredDirective::new(program, feature_flags.enable_required_transform_for_prefix);

    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

// #[derive(Clone)]
struct MaybeRequiredField {
    required: Option<RequiredMetadata>,
    field_name: WithLocation<StringKey>,
}

struct RequiredField {
    required: RequiredMetadata,
    field_name: WithLocation<StringKey>,
}

struct RequiredDirective<'s> {
    program: &'s Program,
    errors: Vec<Diagnostic>,
    path: Vec<&'s str>,
    within_abstract_inline_fragment: bool,
    path_required_map: FnvHashMap<StringKey, MaybeRequiredField>,
    current_node_required_children: FnvHashMap<StringKey, RequiredField>,
    required_children_map: FnvHashMap<StringKey, FnvHashMap<StringKey, RequiredField>>,
    prefix: Option<StringKey>,
    operation_name: Option<StringKey>,
}

impl<'program> RequiredDirective<'program> {
    fn new(program: &'program Program, prefix: Option<StringKey>) -> Self {
        Self {
            program,
            errors: Default::default(),
            path: vec![],
            within_abstract_inline_fragment: false,
            path_required_map: Default::default(),
            current_node_required_children: Default::default(),
            required_children_map: Default::default(),
            prefix,
            operation_name: None,
        }
    }

    fn reset_state(&mut self) {
        self.path_required_map = Default::default();
        self.current_node_required_children = Default::default();
        self.required_children_map = Default::default();
        self.operation_name = Default::default();
    }

    fn assert_not_within_abstract_inline_fragment(&mut self, directive_location: &Location) {
        if self.within_abstract_inline_fragment {
            self.errors.push(Diagnostic::error(
                ValidationMessage::RequiredWithinAbstractInlineFragment,
                // TODO(T70172661): Also referece the location of the inline fragment, once they have a location.
                *directive_location,
            ))
        }
    }

    fn assert_compatible_nullability(&mut self, path: StringKey, current: MaybeRequiredField) {
        if let Some(previous) = self.path_required_map.get(&path) {
            if let Some(previous_metadata) = &previous.required {
                if let Some(current_metadata) = current.required {
                    if previous_metadata.action != current_metadata.action {
                        self.errors.push(
                            Diagnostic::error(
                                ValidationMessage::RequiredActionMismatch {
                                    field_name: current.field_name.item,
                                },
                                previous_metadata.action_location,
                            )
                            .annotate(
                                "should be the same as the `action` declared here",
                                current_metadata.action_location,
                            ),
                        )
                    }
                } else {
                    self.errors.push(
                        Diagnostic::error(
                            ValidationMessage::RequiredFieldMismatch {
                                field_name: current.field_name.item,
                            },
                            previous.field_name.location,
                        )
                        .annotate("but not @required here", current.field_name.location),
                    );
                }
            } else if current.required.is_some() {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldMismatch {
                            field_name: current.field_name.item,
                        },
                        current.field_name.location,
                    )
                    .annotate("but not @required here", previous.field_name.location),
                )
            }
        } else {
            self.path_required_map.insert(path, current);
        }
    }

    fn get_required_metadata<T: RequireableField>(
        &mut self,
        field: &T,
        path_name: StringKey,
    ) -> Option<RequiredMetadata> {
        let maybe_required = match field.required_metadata() {
            Err(err) => {
                self.errors.push(err);
                return None;
            }
            Ok(required) => required,
        };

        let field_name = field.name_with_location(&self.program.schema);

        if let Some(metadata) = maybe_required {
            let supported = match &self.prefix {
                None => false,
                Some(prefix) => self
                    .operation_name
                    // If we're parsing a @required directive, we are inside a fragment.
                    .unwrap()
                    .lookup()
                    .starts_with(prefix.lookup()),
            };
            if !supported {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::RequiredNotSupported,
                    metadata.directive_location,
                ))
            }
            self.assert_not_within_abstract_inline_fragment(&metadata.directive_location);
            self.current_node_required_children.insert(
                path_name,
                RequiredField {
                    field_name,
                    required: metadata,
                },
            );
        }

        self.assert_compatible_nullability(
            path_name,
            MaybeRequiredField {
                required: maybe_required,
                field_name,
            },
        );
        maybe_required
    }

    fn assert_compatible_required_children_severity(
        &mut self,
        required_metadata: RequiredMetadata,
    ) {
        let parent_action = RequiredAction::from(required_metadata.action);
        for required_child in self.current_node_required_children.values() {
            if RequiredAction::from(required_child.required.action) < parent_action {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldInvalidNesting {
                            suggested_action: required_child.required.action,
                        },
                        required_metadata.action_location,
                    )
                    .annotate(
                        "So that it can match its parent",
                        required_child.required.action_location,
                    ),
                );
            }
        }
    }
    fn assert_compatible_required_children<T: RequireableField>(
        &mut self,
        field: &T,
        field_path: StringKey,
    ) {
        let previous_required_children = match self.required_children_map.get(&field_path) {
            Some(it) => it,
            _ => {
                // We haven't seen any other instances of this field, so there's no validaiton to perform.
                return;
            }
        };

        // Check if this field has a required child field which was omitted in a previously encountered parent.
        for (path, required_child) in self.current_node_required_children.iter() {
            if !previous_required_children.contains_key(path) {
                if let Some(other_parent) = self.path_required_map.get(&field_path) {
                    self.errors.push(
                        Diagnostic::error(
                            ValidationMessage::RequiredFieldMissing {
                                field_name: required_child.field_name.item,
                            },
                            required_child.field_name.location,
                        )
                        .annotate("but is missing from", other_parent.field_name.location),
                    )
                } else {
                    // We want to give a location of the other parent which is
                    // missing this field. We expect that we will be able to
                    // find it in `self.path_required_map` since it should
                    // contain data about every visited field in this program
                    // and the other parent _must_ have already been visited.
                    panic!("Could not find other parent node at path \"{}\".", {
                        field_path
                    });
                }
            }
        }

        // Check if a previous reference to this field had a required child field which we are missing.
        for (path, required_child) in previous_required_children.iter() {
            if !self.current_node_required_children.contains_key(path) {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldMissing {
                            field_name: required_child.field_name.item,
                        },
                        required_child.field_name.location,
                    )
                    .annotate(
                        "but is missing from",
                        field.name_with_location(&self.program.schema).location,
                    ),
                )
            }
        }
    }
}

impl<'s> Transformer for RequiredDirective<'s> {
    const NAME: &'static str = "RequiredDirectiveTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.reset_state();
        self.operation_name = Some(fragment.name.item);
        self.default_transform_fragment(fragment)
    }

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.reset_state();
        self.operation_name = Some(operation.name.item);
        self.default_transform_operation(operation)
    }

    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Selection> {
        let name = field.alias_or_name(&self.program.schema).lookup();
        self.path.push(name);
        let path_name = self.path.join(".").intern();
        self.path.pop();

        match self.get_required_metadata(field, path_name) {
            None => Transformed::Keep,
            Some(required_metadata) => {
                Transformed::Replace(Selection::ScalarField(Arc::new(ScalarField {
                    directives: add_metadata_directive(
                        &field.directives,
                        path_name,
                        required_metadata.action,
                    ),
                    ..field.clone()
                })))
            }
        }
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        let name = field.alias_or_name(&self.program.schema).lookup();
        self.path.push(name);
        let path_name = self.path.join(".").intern();

        let maybe_required_metadata = self.get_required_metadata(field, path_name);
        let next_directives = match maybe_required_metadata {
            Some(required_metadata) => {
                add_metadata_directive(&field.directives, path_name, required_metadata.action)
            }
            None => field.directives.clone(),
        };

        // Once we've handled our own directive, take the parent's required
        // children map, leaving behind an empty/default map which our children
        // can populate.
        let parent_node_required_children = mem::take(&mut self.current_node_required_children);

        let previous_abstract_fragment =
            mem::replace(&mut self.within_abstract_inline_fragment, false);

        let selections = self.transform_selections(&field.selections);

        self.assert_compatible_required_children(field, path_name);
        if let Some(required_metadata) = maybe_required_metadata {
            self.assert_compatible_required_children_severity(required_metadata);
        }

        self.within_abstract_inline_fragment = previous_abstract_fragment;

        let required_children = mem::replace(
            &mut self.current_node_required_children,
            parent_node_required_children,
        );

        self.required_children_map
            .insert(path_name, required_children);

        self.path.pop();
        Transformed::Replace(Selection::LinkedField(Arc::new(LinkedField {
            directives: next_directives,
            selections: selections.replace_or_else(|| field.selections.clone()),
            ..field.clone()
        })))
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        let previous = self.within_abstract_inline_fragment;

        if let Some(type_) = fragment.type_condition {
            if self.program.schema.is_abstract_type(type_) {
                self.within_abstract_inline_fragment = true;
            }
        }
        let next_fragment = self.default_transform_inline_fragment(fragment);

        self.within_abstract_inline_fragment = previous;
        next_fragment
    }
}

fn add_metadata_directive(
    directives: &[Directive],
    path_name: StringKey,
    action: StringKey,
) -> Vec<Directive> {
    let mut next_directives: Vec<Directive> = Vec::with_capacity(directives.len() + 1);
    for directive in directives.iter() {
        next_directives.push(directive.clone());
    }

    next_directives.push(Directive {
        name: WithLocation::generated(*REQUIRED_METADATA_KEY),
        arguments: vec![
            Argument {
                name: WithLocation::generated(*ACTION_ARGUMENT),
                value: WithLocation::generated(Value::Constant(ConstantValue::String(action))),
            },
            Argument {
                name: WithLocation::generated(*PATH_METADATA_ARGUMENT),
                value: WithLocation::generated(Value::Constant(ConstantValue::String(path_name))),
            },
        ],
    });
    next_directives
}

// Possible @requried `action` enum values ordered by severity.
#[derive(PartialEq, PartialOrd, Debug)]
pub enum RequiredAction {
    NONE,
    LOG,
    THROW,
}

impl RequiredAction {
    pub fn from_directives(directives: Vec<Directive>) -> Option<Self> {
        directives
            .named(*REQUIRED_METADATA_KEY)
            .map(|required_directive| {
                Self::from(
                    required_directive
                        .arguments
                        .named(*ACTION_ARGUMENT)
                        .unwrap()
                        .value
                        .item
                        .get_string_literal()
                        .unwrap(),
                )
            })
    }
}

impl From<StringKey> for RequiredAction {
    fn from(action: StringKey) -> Self {
        match action {
            _ if action == *THROW_ACTION => Self::THROW,
            _ if action == *LOG_ACTION => Self::LOG,
            _ if action == *NONE_ACTION => Self::NONE,
            // Actions that don't conform to the GraphQL schema should have been filtered out in IR validation.
            _ => unreachable!(),
        }
    }
}
<commit_msg>Allow multiple prefixes separated by |<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Diagnostic, Location, NamedItem, WithLocation};
mod requireable_field;

use super::FeatureFlags;
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, InlineFragment, LinkedField,
    OperationDefinition, Program, ScalarField, Selection, Transformed, Transformer,
    ValidationMessage, ValidationResult, Value,
};
use interner::Intern;
use interner::StringKey;
use lazy_static::lazy_static;
use requireable_field::{RequireableField, RequiredMetadata};
use std::mem;
use std::sync::Arc;

lazy_static! {
    pub static ref REQUIRED_DIRECTIVE_NAME: StringKey = "required".intern();
    pub static ref ACTION_ARGUMENT: StringKey = "action".intern();
    pub static ref REQUIRED_METADATA_KEY: StringKey = "__required".intern();
    pub static ref PATH_METADATA_ARGUMENT: StringKey = "path".intern();
    static ref THROW_ACTION: StringKey = "THROW".intern();
    static ref LOG_ACTION: StringKey = "LOG".intern();
    static ref NONE_ACTION: StringKey = "NONE".intern();
}

pub fn required_directive(
    program: &Program,
    feature_flags: &FeatureFlags,
) -> ValidationResult<Program> {
    let mut transform =
        RequiredDirective::new(program, feature_flags.enable_required_transform_for_prefix);

    let next_program = transform
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transform.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transform.errors)
    }
}

// #[derive(Clone)]
struct MaybeRequiredField {
    required: Option<RequiredMetadata>,
    field_name: WithLocation<StringKey>,
}

struct RequiredField {
    required: RequiredMetadata,
    field_name: WithLocation<StringKey>,
}

struct RequiredDirective<'s> {
    program: &'s Program,
    errors: Vec<Diagnostic>,
    path: Vec<&'s str>,
    within_abstract_inline_fragment: bool,
    path_required_map: FnvHashMap<StringKey, MaybeRequiredField>,
    current_node_required_children: FnvHashMap<StringKey, RequiredField>,
    required_children_map: FnvHashMap<StringKey, FnvHashMap<StringKey, RequiredField>>,
    prefix: Option<StringKey>,
    operation_name: Option<StringKey>,
}

impl<'program> RequiredDirective<'program> {
    fn new(program: &'program Program, prefix: Option<StringKey>) -> Self {
        Self {
            program,
            errors: Default::default(),
            path: vec![],
            within_abstract_inline_fragment: false,
            path_required_map: Default::default(),
            current_node_required_children: Default::default(),
            required_children_map: Default::default(),
            prefix,
            operation_name: None,
        }
    }

    fn reset_state(&mut self) {
        self.path_required_map = Default::default();
        self.current_node_required_children = Default::default();
        self.required_children_map = Default::default();
        self.operation_name = Default::default();
    }

    fn assert_not_within_abstract_inline_fragment(&mut self, directive_location: &Location) {
        if self.within_abstract_inline_fragment {
            self.errors.push(Diagnostic::error(
                ValidationMessage::RequiredWithinAbstractInlineFragment,
                // TODO(T70172661): Also referece the location of the inline fragment, once they have a location.
                *directive_location,
            ))
        }
    }

    fn assert_compatible_nullability(&mut self, path: StringKey, current: MaybeRequiredField) {
        if let Some(previous) = self.path_required_map.get(&path) {
            if let Some(previous_metadata) = &previous.required {
                if let Some(current_metadata) = current.required {
                    if previous_metadata.action != current_metadata.action {
                        self.errors.push(
                            Diagnostic::error(
                                ValidationMessage::RequiredActionMismatch {
                                    field_name: current.field_name.item,
                                },
                                previous_metadata.action_location,
                            )
                            .annotate(
                                "should be the same as the `action` declared here",
                                current_metadata.action_location,
                            ),
                        )
                    }
                } else {
                    self.errors.push(
                        Diagnostic::error(
                            ValidationMessage::RequiredFieldMismatch {
                                field_name: current.field_name.item,
                            },
                            previous.field_name.location,
                        )
                        .annotate("but not @required here", current.field_name.location),
                    );
                }
            } else if current.required.is_some() {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldMismatch {
                            field_name: current.field_name.item,
                        },
                        current.field_name.location,
                    )
                    .annotate("but not @required here", previous.field_name.location),
                )
            }
        } else {
            self.path_required_map.insert(path, current);
        }
    }

    fn get_required_metadata<T: RequireableField>(
        &mut self,
        field: &T,
        path_name: StringKey,
    ) -> Option<RequiredMetadata> {
        let maybe_required = match field.required_metadata() {
            Err(err) => {
                self.errors.push(err);
                return None;
            }
            Ok(required) => required,
        };

        let field_name = field.name_with_location(&self.program.schema);

        if let Some(metadata) = maybe_required {
            let supported = match &self.prefix {
                None => false,
                Some(prefix) => {
                    let operation_name = self
                        .operation_name
                        // If we're parsing a @required directive, we are inside a fragment.
                        .unwrap()
                        .lookup();
                    // TODO(T74397896): Clean up once @required is rolled out
                    prefix
                        .lookup()
                        .split('|')
                        .any(|prefix| operation_name.starts_with(prefix))
                }
            };
            if !supported {
                self.errors.push(Diagnostic::error(
                    ValidationMessage::RequiredNotSupported,
                    metadata.directive_location,
                ))
            }
            self.assert_not_within_abstract_inline_fragment(&metadata.directive_location);
            self.current_node_required_children.insert(
                path_name,
                RequiredField {
                    field_name,
                    required: metadata,
                },
            );
        }

        self.assert_compatible_nullability(
            path_name,
            MaybeRequiredField {
                required: maybe_required,
                field_name,
            },
        );
        maybe_required
    }

    fn assert_compatible_required_children_severity(
        &mut self,
        required_metadata: RequiredMetadata,
    ) {
        let parent_action = RequiredAction::from(required_metadata.action);
        for required_child in self.current_node_required_children.values() {
            if RequiredAction::from(required_child.required.action) < parent_action {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldInvalidNesting {
                            suggested_action: required_child.required.action,
                        },
                        required_metadata.action_location,
                    )
                    .annotate(
                        "So that it can match its parent",
                        required_child.required.action_location,
                    ),
                );
            }
        }
    }
    fn assert_compatible_required_children<T: RequireableField>(
        &mut self,
        field: &T,
        field_path: StringKey,
    ) {
        let previous_required_children = match self.required_children_map.get(&field_path) {
            Some(it) => it,
            _ => {
                // We haven't seen any other instances of this field, so there's no validaiton to perform.
                return;
            }
        };

        // Check if this field has a required child field which was omitted in a previously encountered parent.
        for (path, required_child) in self.current_node_required_children.iter() {
            if !previous_required_children.contains_key(path) {
                if let Some(other_parent) = self.path_required_map.get(&field_path) {
                    self.errors.push(
                        Diagnostic::error(
                            ValidationMessage::RequiredFieldMissing {
                                field_name: required_child.field_name.item,
                            },
                            required_child.field_name.location,
                        )
                        .annotate("but is missing from", other_parent.field_name.location),
                    )
                } else {
                    // We want to give a location of the other parent which is
                    // missing this field. We expect that we will be able to
                    // find it in `self.path_required_map` since it should
                    // contain data about every visited field in this program
                    // and the other parent _must_ have already been visited.
                    panic!("Could not find other parent node at path \"{}\".", {
                        field_path
                    });
                }
            }
        }

        // Check if a previous reference to this field had a required child field which we are missing.
        for (path, required_child) in previous_required_children.iter() {
            if !self.current_node_required_children.contains_key(path) {
                self.errors.push(
                    Diagnostic::error(
                        ValidationMessage::RequiredFieldMissing {
                            field_name: required_child.field_name.item,
                        },
                        required_child.field_name.location,
                    )
                    .annotate(
                        "but is missing from",
                        field.name_with_location(&self.program.schema).location,
                    ),
                )
            }
        }
    }
}

impl<'s> Transformer for RequiredDirective<'s> {
    const NAME: &'static str = "RequiredDirectiveTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.reset_state();
        self.operation_name = Some(fragment.name.item);
        self.default_transform_fragment(fragment)
    }

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.reset_state();
        self.operation_name = Some(operation.name.item);
        self.default_transform_operation(operation)
    }

    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Selection> {
        let name = field.alias_or_name(&self.program.schema).lookup();
        self.path.push(name);
        let path_name = self.path.join(".").intern();
        self.path.pop();

        match self.get_required_metadata(field, path_name) {
            None => Transformed::Keep,
            Some(required_metadata) => {
                Transformed::Replace(Selection::ScalarField(Arc::new(ScalarField {
                    directives: add_metadata_directive(
                        &field.directives,
                        path_name,
                        required_metadata.action,
                    ),
                    ..field.clone()
                })))
            }
        }
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        let name = field.alias_or_name(&self.program.schema).lookup();
        self.path.push(name);
        let path_name = self.path.join(".").intern();

        let maybe_required_metadata = self.get_required_metadata(field, path_name);
        let next_directives = match maybe_required_metadata {
            Some(required_metadata) => {
                add_metadata_directive(&field.directives, path_name, required_metadata.action)
            }
            None => field.directives.clone(),
        };

        // Once we've handled our own directive, take the parent's required
        // children map, leaving behind an empty/default map which our children
        // can populate.
        let parent_node_required_children = mem::take(&mut self.current_node_required_children);

        let previous_abstract_fragment =
            mem::replace(&mut self.within_abstract_inline_fragment, false);

        let selections = self.transform_selections(&field.selections);

        self.assert_compatible_required_children(field, path_name);
        if let Some(required_metadata) = maybe_required_metadata {
            self.assert_compatible_required_children_severity(required_metadata);
        }

        self.within_abstract_inline_fragment = previous_abstract_fragment;

        let required_children = mem::replace(
            &mut self.current_node_required_children,
            parent_node_required_children,
        );

        self.required_children_map
            .insert(path_name, required_children);

        self.path.pop();
        Transformed::Replace(Selection::LinkedField(Arc::new(LinkedField {
            directives: next_directives,
            selections: selections.replace_or_else(|| field.selections.clone()),
            ..field.clone()
        })))
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        let previous = self.within_abstract_inline_fragment;

        if let Some(type_) = fragment.type_condition {
            if self.program.schema.is_abstract_type(type_) {
                self.within_abstract_inline_fragment = true;
            }
        }
        let next_fragment = self.default_transform_inline_fragment(fragment);

        self.within_abstract_inline_fragment = previous;
        next_fragment
    }
}

fn add_metadata_directive(
    directives: &[Directive],
    path_name: StringKey,
    action: StringKey,
) -> Vec<Directive> {
    let mut next_directives: Vec<Directive> = Vec::with_capacity(directives.len() + 1);
    for directive in directives.iter() {
        next_directives.push(directive.clone());
    }

    next_directives.push(Directive {
        name: WithLocation::generated(*REQUIRED_METADATA_KEY),
        arguments: vec![
            Argument {
                name: WithLocation::generated(*ACTION_ARGUMENT),
                value: WithLocation::generated(Value::Constant(ConstantValue::String(action))),
            },
            Argument {
                name: WithLocation::generated(*PATH_METADATA_ARGUMENT),
                value: WithLocation::generated(Value::Constant(ConstantValue::String(path_name))),
            },
        ],
    });
    next_directives
}

// Possible @required `action` enum values ordered by severity.
#[derive(PartialEq, PartialOrd, Debug)]
pub enum RequiredAction {
    NONE,
    LOG,
    THROW,
}

impl RequiredAction {
    pub fn from_directives(directives: Vec<Directive>) -> Option<Self> {
        directives
            .named(*REQUIRED_METADATA_KEY)
            .map(|required_directive| {
                Self::from(
                    required_directive
                        .arguments
                        .named(*ACTION_ARGUMENT)
                        .unwrap()
                        .value
                        .item
                        .get_string_literal()
                        .unwrap(),
                )
            })
    }
}

impl From<StringKey> for RequiredAction {
    fn from(action: StringKey) -> Self {
        match action {
            _ if action == *THROW_ACTION => Self::THROW,
            _ if action == *LOG_ACTION => Self::LOG,
            _ if action == *NONE_ACTION => Self::NONE,
            // Actions that don't conform to the GraphQL schema should have been filtered out in IR validation.
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use test::{black_box, Bencher};

#[bench]
fn bench_new(b: &mut Bencher) {
    b.iter(|| {
        let ring: VecDeque<i32> = VecDeque::new();
        black_box(ring);
    })
}

#[bench]
fn bench_grow_1025(b: &mut Bencher) {
    b.iter(|| {
        let mut deq = VecDeque::new();
        for i in 0..1025 {
            deq.push_front(i);
        }
        black_box(deq);
    })
}

#[bench]
fn bench_iter_1000(b: &mut Bencher) {
    let ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| {
        let mut sum = 0;
        for &i in &ring {
            sum += i;
        }
        black_box(sum);
    })
}

#[bench]
fn bench_mut_iter_1000(b: &mut Bencher) {
    let mut ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| {
        let mut sum = 0;
        for i in &mut ring {
            sum += *i;
        }
        black_box(sum);
    })
}

#[bench]
fn bench_try_fold(b: &mut Bencher) {
    let ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b))))
}
<commit_msg>add benchmark for From<[T; N]> in VecDeque<commit_after>use std::collections::VecDeque;
use test::{black_box, Bencher};

#[bench]
fn bench_new(b: &mut Bencher) {
    b.iter(|| {
        let ring: VecDeque<i32> = VecDeque::new();
        black_box(ring);
    })
}

#[bench]
fn bench_grow_1025(b: &mut Bencher) {
    b.iter(|| {
        let mut deq = VecDeque::new();
        for i in 0..1025 {
            deq.push_front(i);
        }
        black_box(deq);
    })
}

#[bench]
fn bench_iter_1000(b: &mut Bencher) {
    let ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| {
        let mut sum = 0;
        for &i in &ring {
            sum += i;
        }
        black_box(sum);
    })
}

#[bench]
fn bench_mut_iter_1000(b: &mut Bencher) {
    let mut ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| {
        let mut sum = 0;
        for i in &mut ring {
            sum += *i;
        }
        black_box(sum);
    })
}

#[bench]
fn bench_try_fold(b: &mut Bencher) {
    let ring: VecDeque<_> = (0..1000).collect();

    b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b))))
}

#[bench]
fn bench_from_array_1000(b: &mut Bencher) {
    const N: usize = 1000;
    let mut array: [usize; N] = [0; N];

    for i in 0..N {
        array[i] = i;
    }

    b.iter(|| {
        let deq: VecDeque<_> = array.into();
        black_box(deq);
    })
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        $crate::connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        $crate::connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        $crate::connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.stream().clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        // TODO: remove any use of Fragile when gio callbacks stop requiring Send.
        let stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None::<&gio::Cancellable>, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None::<&gio::Cancellable>, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None::<&gio::Cancellable>, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None::<&gio::Cancellable>, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<commit_msg>fix `connect` documentation<commit_after>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$dst_component` when the `$message` is received on `$src_component`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        $crate::connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        $crate::connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        $crate::connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.stream().clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        // TODO: remove any use of Fragile when gio callbacks stop requiring Send.
        let stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None::<&gio::Cancellable>, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None::<&gio::Cancellable>, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None::<&gio::Cancellable>, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None::<&gio::Cancellable>, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = $crate::Fragile::new($relm.stream().clone());
        let fail_event_stream = $crate::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<|endoftext|>


<commit_before>macro_rules! commands {
    ($($cmd:ident),* $(,)*) => {
        $(
            mod $cmd;
            pub use self::$cmd::*;
        )*
    }
}

macro_rules! command {
    ( $(#[$attr:meta])* ) => {
        #[derive(Command)]
        $(#[$attr])*
        struct _DummyCommand;
    }
}

/// Splice an array of arguments into another term
///
/// `args` is a macro that’s used to splice a number of arguments into another term. This is
/// useful when you want to call a variadic term such as [branch](commands/trait.Branch.html) with a set of arguments produced at
/// runtime.
///
/// *Note* that args evaluates all its arguments before passing them into the parent term, even if
/// the parent term otherwise allows lazy evaluation.
///
/// # Example
///
/// Get Alice and Bob from the table `people`.
///
/// ```
/// # #[macro_use] extern crate reql;
/// # use reql::commands::*;
/// # use reql::commands::run::Dummy;
/// # use reql::r;
/// # fn main() {
/// let x = 10;
/// r.branch(args!(x > 5, "big", "small")).run::<String>();
/// # }
/// ```
#[macro_export]
macro_rules! args {
    ( $($arg:expr),* $(,)* ) => {{
        use $crate::{ToArg, Command, Term};

        let mut term = Term::new();
        __process_args!(term, $(($arg))*);
        Command::new(term)
    }};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __process_args {
    ( $term:ident, ) => { };

    ( $term:ident, ({ $($key:ident; $($val:tt)+),* $(,)* }) ) => {{
        $(
            let key = stringify!($key);
            let val = args!($($val)+);
            let temp_pair = Command::create_term_pair(key, val);
            $term.mut_optargs().push(temp_pair);
         )*
    }};

    ( $term:ident, ({ $($key:ident; $($val:tt)+),* $(,)* }) $($tail:tt)+ ) => {{
        let mut arg = Term::new();
        $(
            let key = stringify!($key);
            let val = args!($($val)+);
            let temp_pair = Command::create_term_pair(key, val);
            arg.mut_optargs().push(temp_pair);
         )*
        $term.mut_args().push(arg);
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident, ([ $($val:expr),* $(,)* ]) $($tail:tt)* ) => {{
        let mut arg = Term::new();
        $(
            arg.mut_args().push(args!($val).to_arg());
        )*
        $term.mut_args().push(arg);
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident, (| $($arg:ident),* $(,)* | { $body:tt }) $($tail:tt)* ) => {{
        unimplemented!();
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident, ($arg:expr) $($tail:tt)* ) => {{
        $term.mut_args().push($arg.to_arg());
        __process_args!($term, $($tail)*);
    }};
}
<commit_msg>args: make trailing commas optional<commit_after>macro_rules! commands {
    ($($cmd:ident),* $(,)*) => {
        $(
            mod $cmd;
            pub use self::$cmd::*;
        )*
    }
}

macro_rules! command {
    ( $(#[$attr:meta])* ) => {
        #[derive(Command)]
        $(#[$attr])*
        struct _DummyCommand;
    }
}

/// Splice an array of arguments into another term
///
/// `args` is a macro that’s used to splice a number of arguments into another term. This is
/// useful when you want to call a variadic term such as [branch](commands/trait.Branch.html) with a set of arguments produced at
/// runtime.
///
/// *Note* that args evaluates all its arguments before passing them into the parent term, even if
/// the parent term otherwise allows lazy evaluation.
///
/// # Example
///
/// Get Alice and Bob from the table `people`.
///
/// ```
/// # #[macro_use] extern crate reql;
/// # use reql::commands::*;
/// # use reql::commands::run::Dummy;
/// # use reql::r;
/// # fn main() {
/// let x = 10;
/// r.branch(args!(x > 5, "big", "small")).run::<String>();
/// # }
/// ```
#[macro_export]
macro_rules! args {
    ( $($arg:tt)* ) => {{
        use $crate::{ToArg, Command, Term};

        let mut term = Term::new();
        __process_args!(term, $($arg)*);
        Command::new(term)
    }};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __process_args {
    ( $term:ident, ) => { };

    ( $term:ident,  $(,)* { $($key:ident: $($val:tt)+),* $(,)* } $(,)* ) => {{
        $(
            let key = stringify!($key);
            let mut val = Term::new();
            __process_args!(val, $($val)+);
            let temp_pair = Command::create_term_pair(key, val);
            $term.mut_optargs().push(temp_pair);
         )*
    }};

    ( $term:ident,  $(,)* { $($key:ident: $($val:tt)+),* $(,)* } $($tail:tt)* ) => {{
        let mut arg = Term::new();
        $(
            let key = stringify!($key);
            let mut val = Term::new();
            __process_args!(val, $($val)+);
            let temp_pair = Command::create_term_pair(key, val);
            arg.mut_optargs().push(temp_pair);
         )*
        $term.mut_args().push(arg);
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident,  $(,)* [ $($val:expr),* ] $($tail:tt)* ) => {{
        let mut arg = Term::new();
        $(
            let mut val = Term::new();
            __process_args!(val, $val);
            arg.mut_args().push(val);
        )*
        $term.mut_args().push(arg);
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident,  $(,)* | $($arg:ident),* $(,)* | $body:tt $($tail:tt)* ) => {{
        unimplemented!();
        __process_args!($term, $($tail)*);
    }};

    ( $term:ident,  $(,)* $arg:expr, $($tail:tt)+ ) => {{
        $term.mut_args().push($arg.to_arg());
        __process_args!($term, $($tail)+);
    }};

    ( $term:ident,  $(,)* $arg:expr $(,)* ) => {{
        $term.mut_args().push($arg.to_arg());
    }};
}
<|endoftext|>


<commit_before><commit_msg>Implement + - * / for Number<commit_after><|endoftext|>


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

use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::element::Element;
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
use dom::node::Node;
use dom::window::Window;
use util::str::DOMString;

#[dom_struct]
pub struct HTMLFormControlsCollection {
    collection: HTMLCollection,
}

impl HTMLFormControlsCollection {
    fn new_inherited(root: &Node, filter: Box<CollectionFilter + 'static>) -> HTMLFormControlsCollection {
        HTMLFormControlsCollection {
            collection: HTMLCollection::new_inherited(root, filter)
        }
    }

    pub fn new(window: &Window, root: &Node, filter: Box<CollectionFilter + 'static>)
        -> Root<HTMLFormControlsCollection>
    {
        reflect_dom_object(box HTMLFormControlsCollection::new_inherited(root, filter),
                           GlobalRef::Window(window),
                           HTMLFormControlsCollectionBinding::Wrap)
    }

    // FIXME: This shouldn't need to be implemented here since HTMLCollection (the parent of
    // HTMLFormControlsCollection) implements Length
    pub fn Length(&self) -> u32 {
        self.collection.Length()
    }
}

impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
    // https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<Root<Element>> {
        self.collection.NamedGetter(name, found)
    }

    // https://html.spec.whatwg.org/multipage/#the-htmlformcontrolscollection-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        self.collection.SupportedPropertyNames()
    }

    // FIXME: This shouldn't need to be implemented here since HTMLCollection (the parent of
    // HTMLFormControlsCollection) implements IndexedGetter
    //
    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Root<Element>> {
        self.collection.IndexedGetter(index, found)
    }
}
<commit_msg>Auto merge of #9266 - frewsxcv:redundant-getter-tracking-issue, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding;
use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::element::Element;
use dom::htmlcollection::{CollectionFilter, HTMLCollection};
use dom::node::Node;
use dom::window::Window;
use util::str::DOMString;

#[dom_struct]
pub struct HTMLFormControlsCollection {
    collection: HTMLCollection,
}

impl HTMLFormControlsCollection {
    fn new_inherited(root: &Node, filter: Box<CollectionFilter + 'static>) -> HTMLFormControlsCollection {
        HTMLFormControlsCollection {
            collection: HTMLCollection::new_inherited(root, filter)
        }
    }

    pub fn new(window: &Window, root: &Node, filter: Box<CollectionFilter + 'static>)
        -> Root<HTMLFormControlsCollection>
    {
        reflect_dom_object(box HTMLFormControlsCollection::new_inherited(root, filter),
                           GlobalRef::Window(window),
                           HTMLFormControlsCollectionBinding::Wrap)
    }

    // FIXME: This shouldn't need to be implemented here since HTMLCollection (the parent of
    // HTMLFormControlsCollection) implements Length
    pub fn Length(&self) -> u32 {
        self.collection.Length()
    }
}

impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
    // https://html.spec.whatwg.org/multipage/#dom-htmlformcontrolscollection-nameditem
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<Root<Element>> {
        self.collection.NamedGetter(name, found)
    }

    // https://html.spec.whatwg.org/multipage/#the-htmlformcontrolscollection-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        self.collection.SupportedPropertyNames()
    }

    // FIXME: This shouldn't need to be implemented here since HTMLCollection (the parent of
    // HTMLFormControlsCollection) implements IndexedGetter.
    // https://github.com/servo/servo/issues/5875
    //
    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Root<Element>> {
        self.collection.IndexedGetter(index, found)
    }
}
<|endoftext|>


<commit_before><commit_msg>Extract parsing of body of rules to use in mixins too<commit_after><|endoftext|>


<commit_before><commit_msg>flesh out tokenizer<commit_after><|endoftext|>


<commit_before>use std::env;
use std::fs::{File, read_dir};
use std::io::Write;
use std::path::PathBuf;
use std::result::Result;
use serde::{Deserialize, Serialize};
use serde_json::ser::Serializer;
use serde_protobuf::descriptor::{Descriptors, MessageDescriptor};
use serde_protobuf::de::Deserializer;
use serde_protobuf::error::{Error, ErrorKind};
use serde_value::Value;
use protobuf::{CodedInputStream, parse_from_reader};
use protobuf::error::ProtobufError;

pub enum PqrsError {
    EofError(String),
    SerdeError(String),
    ProtobufError(String),
}

pub fn process_single(data: &[u8], msg_type: &str, out: &mut Write) -> Result<(), PqrsError> {
    match msg_type {
        "guess" => return guess_message(data, out),
        _ => return named_message(data, msg_type, out),
    }
}

fn named_message(data: &[u8], msg_type: &str, out: &mut Write) -> Result<(), PqrsError> {
    let mut loc_msg_type = String::new();
    let ch = msg_type.chars().nth(0).unwrap();
    if ch != '.' {
        loc_msg_type.push('.');
    }
    loc_msg_type.push_str(msg_type);

    let (descriptors, _) = get_descriptors(false);

    let stream = CodedInputStream::from_bytes(data);
    let mut deserializer = Deserializer::for_named_message(&descriptors, &loc_msg_type, stream).unwrap();
    let mut serializer = Serializer::new(out);
    match deser(&mut deserializer) {
        Ok(value) => value.serialize(&mut serializer).unwrap(),
        Err(e) => return Err(e),
    }
    Ok(())
}

fn guess_message(data: &[u8], out: &mut Write) -> Result<(), PqrsError> {
    let (descriptors, message_descriptors) = get_descriptors(true);

    let mut serializer = Serializer::new(out);
    let mut contenders = Vec::new();
    for md in message_descriptors {
        let stream = CodedInputStream::from_bytes(data);
        let mut deserializer = Deserializer::new(&descriptors, &md, stream);
        match deser(&mut deserializer) {
            Ok(Value::Map(value)) => {
                let mut unknowns_found = 0;
                for (_, v) in &value {
                    match v {
                        &Value::Unit => unknowns_found += 1,
                        _ => continue,
                    }
                }
                if unknowns_found == 0 {
                    contenders.push(value);
                }
            },
            Ok(_) => continue,
            Err(e) => return Err(e),
        }
    }
    let contender_max = contenders.iter().max_by_key(|x| x.len());
    contender_max.serialize(&mut serializer).unwrap();
    Ok(())
}

fn deser(deserializer: &mut Deserializer) -> Result<Value, PqrsError> {
    match Value::deserialize(deserializer) {
        Ok(x) => return Ok(x),
        Err(Error(ErrorKind::Protobuf(ProtobufError::WireError(msg)), _)) => {
            if msg == "unexpected EOF" {
                return Err(PqrsError::EofError(msg));
            }
            return Err(PqrsError::ProtobufError(msg));
        },
        Err(e) => return Err(PqrsError::SerdeError(String::from(e.description()))),
    };
}

fn get_descriptors(with_message_descriptors: bool) -> (Descriptors, Vec<MessageDescriptor>) {
    let mut descriptors = Descriptors::new();
    let mut message_descriptors = Vec::new();

    for fdset_path in discover_fdsets() {
        let mut fdset_file = File::open(fdset_path.as_path()).unwrap();
        let fdset_proto = parse_from_reader(&mut fdset_file).unwrap();
        descriptors.add_file_set_proto(&fdset_proto);
        if with_message_descriptors {
            for file_proto in fdset_proto.get_file().iter() {
                for message_proto in file_proto.get_message_type().iter() {
                    message_descriptors.push(MessageDescriptor::from_proto(&fdset_path.to_string_lossy().into_owned().as_str(), message_proto));
                }
            }
        }
    }
    descriptors.resolve_refs();
    (descriptors, message_descriptors)
}

fn discover_fdsets() -> Vec<PathBuf> {
    let mut home = env::home_dir().expect("Could not find $HOME");
    home.push(".pq");

    read_dir(home.as_path()).unwrap()
        .map(|x| {
            x.unwrap().path()
        })
        .collect::<Vec<_>>()
}
<commit_msg>Continue on Err in guess mode, and check for contenders empty<commit_after>use std::env;
use std::fs::{File, read_dir};
use std::io::Write;
use std::path::PathBuf;
use std::result::Result;
use serde::{Deserialize, Serialize};
use serde_json::ser::Serializer;
use serde_protobuf::descriptor::{Descriptors, MessageDescriptor};
use serde_protobuf::de::Deserializer;
use serde_protobuf::error::{Error, ErrorKind};
use serde_value::Value;
use protobuf::{CodedInputStream, parse_from_reader};
use protobuf::error::ProtobufError;

pub enum PqrsError {
    EofError(String),
    SerdeError(String),
    ProtobufError(String),
}

pub fn process_single(data: &[u8], msg_type: &str, out: &mut Write) -> Result<(), PqrsError> {
    match msg_type {
        "guess" => return guess_message(data, out),
        _ => return named_message(data, msg_type, out),
    }
}

fn named_message(data: &[u8], msg_type: &str, out: &mut Write) -> Result<(), PqrsError> {
    let mut loc_msg_type = String::new();
    let ch = msg_type.chars().nth(0).unwrap();
    if ch != '.' {
        loc_msg_type.push('.');
    }
    loc_msg_type.push_str(msg_type);

    let (descriptors, _) = get_descriptors(false);

    let stream = CodedInputStream::from_bytes(data);
    let mut deserializer = Deserializer::for_named_message(&descriptors, &loc_msg_type, stream).unwrap();
    let mut serializer = Serializer::new(out);
    match deser(&mut deserializer) {
        Ok(value) => value.serialize(&mut serializer).unwrap(),
        Err(e) => return Err(e),
    }
    Ok(())
}

fn guess_message(data: &[u8], out: &mut Write) -> Result<(), PqrsError> {
    let (descriptors, message_descriptors) = get_descriptors(true);

    let mut serializer = Serializer::new(out);
    let mut contenders = Vec::new();
    for md in message_descriptors {
        let stream = CodedInputStream::from_bytes(data);
        let mut deserializer = Deserializer::new(&descriptors, &md, stream);
        match deser(&mut deserializer) {
            Ok(Value::Map(value)) => {
                let mut unknowns_found = 0;
                for (_, v) in &value {
                    match v {
                        &Value::Unit => unknowns_found += 1,
                        _ => continue,
                    }
                }
                if unknowns_found == 0 {
                    contenders.push(value);
                }
            },
            Ok(_) => continue,
            Err(_) => continue,
        }
    }
    if !contenders.is_empty() {
        let contender_max = contenders.iter().max_by_key(|x| x.len());
        contender_max.serialize(&mut serializer).unwrap();
    }
    Ok(())
}

fn deser(deserializer: &mut Deserializer) -> Result<Value, PqrsError> {
    match Value::deserialize(deserializer) {
        Ok(x) => return Ok(x),
        Err(Error(ErrorKind::Protobuf(ProtobufError::WireError(msg)), _)) => {
            if msg == "unexpected EOF" {
                return Err(PqrsError::EofError(msg));
            }
            return Err(PqrsError::ProtobufError(msg));
        },
        Err(e) => return Err(PqrsError::SerdeError(String::from(e.description()))),
    };
}

fn get_descriptors(with_message_descriptors: bool) -> (Descriptors, Vec<MessageDescriptor>) {
    let mut descriptors = Descriptors::new();
    let mut message_descriptors = Vec::new();

    for fdset_path in discover_fdsets() {
        let mut fdset_file = File::open(fdset_path.as_path()).unwrap();
        let fdset_proto = parse_from_reader(&mut fdset_file).unwrap();
        descriptors.add_file_set_proto(&fdset_proto);
        if with_message_descriptors {
            for file_proto in fdset_proto.get_file().iter() {
                for message_proto in file_proto.get_message_type().iter() {
                    message_descriptors.push(MessageDescriptor::from_proto(&fdset_path.to_string_lossy().into_owned().as_str(), message_proto));
                }
            }
        }
    }
    descriptors.resolve_refs();
    (descriptors, message_descriptors)
}

fn discover_fdsets() -> Vec<PathBuf> {
    let mut home = env::home_dir().expect("Could not find $HOME");
    home.push(".pq");

    read_dir(home.as_path()).unwrap()
        .map(|x| {
            x.unwrap().path()
        })
        .collect::<Vec<_>>()
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
extern crate docopt;

use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;
use std::time::Duration;

use docopt::Docopt;

use rpsrtsrs::state::{WorldState, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<WorldState>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    // Get exclusive world access
                    let mut world_lock = world.lock().unwrap();

                    // Get next free ID. This assumes the players list is
                    // sorted ascending by ID.
                    let id = world_lock.game.players.last()
                                                    .map_or(0, |player| player.id.0 + 1);

                    // Create new player for the newly connected client
                    let mut player = Player::new(id);

                    // Create four initial units for the player
                    player.units.push(Unit::new_random([ 50,  50]));
                    player.units.push(Unit::new_random([ 50, 100]));
                    player.units.push(Unit::new_random([100,  50]));
                    player.units.push(Unit::new_random([100, 100]));

                    // Add player to the world
                    let player_id = player.id;
                    world_lock.game.players.push(player);

                    // Send ServerHello message
                    let encoded: Vec<u8> = encode(
                        &Message::ServerHello(player_id, world_lock.clone()),
                        SizeLimit::Infinite
                    ).unwrap();
                    stream.write(&encoded).unwrap();
                },
                Message::ClientReconnect(id) => {
                    // Get exclusive world access
                    let world_lock = world.lock().unwrap();

                    // Find player with specified id
                    match world_lock.game.players.iter().find(|player| player.id == id) {
                        Some(_) => {
                            println!("Found you :)");

                            // Send ServerHello message
                            let encoded: Vec<u8> = encode(
                                &Message::ServerHello(id, world_lock.clone()),
                                SizeLimit::Infinite
                            ).unwrap();
                            stream.write(&encoded).unwrap();
                        },
                        None => {
                            println!("Reconnect to id {} not possible", id);

                            // Send Error message
                            let encoded: Vec<u8> = encode(
                                &Message::Error,
                                SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                            return  // Don't enter game loop
                        }
                    }
                },
                _ => {
                    println!("Did not receive ClientHello: {:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return  // Don't enter game loop
                }
            }
        }
        Err(e) => {
            println!("Error: {:?}", e);
            return  // Don't enter game loop
        }
    }

    let mut command_stream = stream.try_clone().unwrap();
    // Command receiver loop
    thread::spawn(move || {
        loop {
            let client_message: DecodingResult<Message> = decode_from(&mut command_stream, SizeLimit::Bounded(128));
            match client_message {
                Ok(message) => {
                    match message {
                        Message::Command(command) => {
                            println!("Did receive command {:?}", command);
                        },
                        _ => {
                            println!("Did receive unexpected message: {:?}", message);
                            let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                            command_stream.write(&encoded).unwrap();
                            return
                        },
                    }
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                    return;
                }
            };
        }
    });

    // GameState loop
    loop {
        let encoded: Vec<u8> = {
            let world_lock = world.lock().unwrap();
            encode(&world_lock.game, SizeLimit::Infinite).unwrap()
        };
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ => thread::sleep(Duration::from_millis(1000)),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                    println!("{:?}", unit);
                }
            }
        }
        thread::sleep(Duration::from_millis(500));
    }
}

static USAGE: &'static str = "
Usage: server [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 8080].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
    -r ID    Reconnect with the given ID
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    let tcp_listener = TcpListener::bind((host.deref(),port)).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world = Arc::new(Mutex::new(WorldState::new(800, 600)));
    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<commit_msg>server: Debug print whole player state instead of every single unit<commit_after>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
extern crate docopt;

use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;
use std::time::Duration;

use docopt::Docopt;

use rpsrtsrs::state::{WorldState, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<WorldState>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    // Get exclusive world access
                    let mut world_lock = world.lock().unwrap();

                    // Get next free ID. This assumes the players list is
                    // sorted ascending by ID.
                    let id = world_lock.game.players.last()
                                                    .map_or(0, |player| player.id.0 + 1);

                    // Create new player for the newly connected client
                    let mut player = Player::new(id);

                    // Create four initial units for the player
                    player.units.push(Unit::new_random([ 50,  50]));
                    player.units.push(Unit::new_random([ 50, 100]));
                    player.units.push(Unit::new_random([100,  50]));
                    player.units.push(Unit::new_random([100, 100]));

                    // Add player to the world
                    let player_id = player.id;
                    world_lock.game.players.push(player);

                    // Send ServerHello message
                    let encoded: Vec<u8> = encode(
                        &Message::ServerHello(player_id, world_lock.clone()),
                        SizeLimit::Infinite
                    ).unwrap();
                    stream.write(&encoded).unwrap();
                },
                Message::ClientReconnect(id) => {
                    // Get exclusive world access
                    let world_lock = world.lock().unwrap();

                    // Find player with specified id
                    match world_lock.game.players.iter().find(|player| player.id == id) {
                        Some(_) => {
                            println!("Found you :)");

                            // Send ServerHello message
                            let encoded: Vec<u8> = encode(
                                &Message::ServerHello(id, world_lock.clone()),
                                SizeLimit::Infinite
                            ).unwrap();
                            stream.write(&encoded).unwrap();
                        },
                        None => {
                            println!("Reconnect to id {} not possible", id);

                            // Send Error message
                            let encoded: Vec<u8> = encode(
                                &Message::Error,
                                SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                            return  // Don't enter game loop
                        }
                    }
                },
                _ => {
                    println!("Did not receive ClientHello: {:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return  // Don't enter game loop
                }
            }
        }
        Err(e) => {
            println!("Error: {:?}", e);
            return  // Don't enter game loop
        }
    }

    let mut command_stream = stream.try_clone().unwrap();
    // Command receiver loop
    thread::spawn(move || {
        loop {
            let client_message: DecodingResult<Message> = decode_from(&mut command_stream, SizeLimit::Bounded(128));
            match client_message {
                Ok(message) => {
                    match message {
                        Message::Command(command) => {
                            println!("Did receive command {:?}", command);
                        },
                        _ => {
                            println!("Did receive unexpected message: {:?}", message);
                            let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                            command_stream.write(&encoded).unwrap();
                            return
                        },
                    }
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                    return;
                }
            };
        }
    });

    // GameState loop
    loop {
        let encoded: Vec<u8> = {
            let world_lock = world.lock().unwrap();
            encode(&world_lock.game, SizeLimit::Infinite).unwrap()
        };
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ => thread::sleep(Duration::from_millis(1000)),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                }
                println!("{:?}", player);
            }
        }
        thread::sleep(Duration::from_millis(500));
    }
}

static USAGE: &'static str = "
Usage: server [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 8080].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
    -r ID    Reconnect with the given ID
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    let tcp_listener = TcpListener::bind((host.deref(),port)).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world = Arc::new(Mutex::new(WorldState::new(800, 600)));
    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<|endoftext|>