<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 crate::ir::*;
use crate::program::Program;
use common::WithLocation;
use std::sync::Arc;

pub trait Transformer {
    const NAME: &'static str;
    const VISIT_ARGUMENTS: bool;
    const VISIT_DIRECTIVES: bool;

    fn transform_program<'s>(&mut self, program: &Program<'s>) -> TransformedValue<Program<'s>> {
        self.default_transform_program(program)
    }

    fn default_transform_program<'s>(
        &mut self,
        program: &Program<'s>,
    ) -> TransformedValue<Program<'s>> {
        let mut next_program = Program::new(program.schema());
        let mut has_changes = false;
        for operation in program.operations() {
            match self.transform_operation(operation) {
                Transformed::Delete => has_changes = true,
                Transformed::Keep => next_program.insert_operation(Arc::clone(operation)),
                Transformed::Replace(replacement) => {
                    has_changes = true;
                    next_program.insert_operation(Arc::new(replacement))
                }
            }
        }
        for fragment in program.fragments() {
            match self.transform_fragment(fragment) {
                Transformed::Delete => has_changes = true,
                Transformed::Keep => next_program.insert_fragment(Arc::clone(fragment)),
                Transformed::Replace(replacement) => {
                    has_changes = true;
                    next_program.insert_fragment(Arc::new(replacement))
                }
            }
        }
        if has_changes {
            TransformedValue::Replace(next_program)
        } else {
            TransformedValue::Keep
        }
    }

    // Fragment Definition
    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.default_transform_fragment(fragment)
    }

    fn default_transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        // Special-case for empty selections
        let selections = self.transform_selections(&fragment.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&fragment.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(FragmentDefinition {
            directives: directives.replace_or_else(|| fragment.directives.clone()),
            selections: selections.replace_or_else(|| fragment.selections.clone()),
            ..fragment.clone()
        })
    }

    // Operation Definition
    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.default_transform_operation(operation)
    }

    fn default_transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        let selections = self.transform_selections(&operation.selections);
        // Special-case for empty selections
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&operation.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(OperationDefinition {
            directives: directives.replace_or_else(|| operation.directives.clone()),
            selections: selections.replace_or_else(|| operation.selections.clone()),
            ..operation.clone()
        })
    }

    // Selection
    fn transform_selections(
        &mut self,
        selections: &[Selection],
    ) -> TransformedValue<Vec<Selection>> {
        self.transform_list(selections, Self::transform_selection)
    }

    fn transform_selection(&mut self, selection: &Selection) -> Transformed<Selection> {
        self.default_transform_selection(selection)
    }

    fn default_transform_selection(&mut self, selection: &Selection) -> Transformed<Selection> {
        match selection {
            Selection::FragmentSpread(selection) => self
                .transform_fragment_spread(selection)
                .map(Selection::FragmentSpread),
            Selection::InlineFragment(selection) => self
                .transform_inline_fragment(selection)
                .map(Selection::InlineFragment),
            Selection::LinkedField(selection) => self
                .transform_linked_field(selection)
                .map(Selection::LinkedField),
            Selection::ScalarField(selection) => self
                .transform_scalar_field(selection)
                .map(Selection::ScalarField),
            Selection::Condition(selection) => self
                .transform_condition(selection)
                .map(Selection::Condition),
        }
    }

    // Selection Kinds
    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Arc<ScalarField>> {
        self.default_transform_scalar_field(field)
    }

    fn default_transform_scalar_field(
        &mut self,
        field: &ScalarField,
    ) -> Transformed<Arc<ScalarField>> {
        let arguments = self.transform_arguments(&field.arguments);
        let directives = self.transform_directives(&field.directives);
        if arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(ScalarField {
            arguments: arguments.replace_or_else(|| field.arguments.clone()),
            directives: directives.replace_or_else(|| field.directives.clone()),
            ..field.clone()
        }))
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Arc<LinkedField>> {
        self.default_transform_linked_field(field)
    }

    fn default_transform_linked_field(
        &mut self,
        field: &LinkedField,
    ) -> Transformed<Arc<LinkedField>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&field.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let arguments = self.transform_arguments(&field.arguments);
        let directives = self.transform_directives(&field.directives);
        if selections.should_keep() && arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(LinkedField {
            arguments: arguments.replace_or_else(|| field.arguments.clone()),
            directives: directives.replace_or_else(|| field.directives.clone()),
            selections: selections.replace_or_else(|| field.selections.clone()),
            ..field.clone()
        }))
    }

    fn transform_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> Transformed<Arc<InlineFragment>> {
        self.default_transform_inline_fragment(fragment)
    }

    fn default_transform_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> Transformed<Arc<InlineFragment>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&fragment.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&fragment.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(InlineFragment {
            directives: directives.replace_or_else(|| fragment.directives.clone()),
            selections: selections.replace_or_else(|| fragment.selections.clone()),
            ..fragment.clone()
        }))
    }

    fn transform_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> Transformed<Arc<FragmentSpread>> {
        self.default_transform_fragment_spread(spread)
    }
    fn default_transform_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> Transformed<Arc<FragmentSpread>> {
        let arguments = self.transform_arguments(&spread.arguments);
        let directives = self.transform_directives(&spread.directives);
        if arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(FragmentSpread {
            arguments: arguments.replace_or_else(|| spread.arguments.clone()),
            directives: directives.replace_or_else(|| spread.directives.clone()),
            ..spread.clone()
        }))
    }

    // Conditions
    fn transform_condition(&mut self, condition: &Condition) -> Transformed<Arc<Condition>> {
        self.default_transform_condition(condition)
    }

    fn default_transform_condition(
        &mut self,
        condition: &Condition,
    ) -> Transformed<Arc<Condition>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&condition.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let condition_value = self.transform_condition_value(&condition.value);
        if selections.should_keep() && condition_value.should_keep() {
            Transformed::Keep
        } else {
            Transformed::Replace(Arc::new(Condition {
                value: condition_value.replace_or_else(|| condition.value.clone()),
                selections: selections.replace_or_else(|| condition.selections.clone()),
                ..condition.clone()
            }))
        }
    }

    fn transform_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> TransformedValue<ConditionValue> {
        if Self::VISIT_ARGUMENTS {
            self.default_transform_condition_value(condition_value)
        } else {
            TransformedValue::Keep
        }
    }

    fn default_transform_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> TransformedValue<ConditionValue> {
        match condition_value {
            ConditionValue::Variable(variable) => match self.transform_variable(variable) {
                TransformedValue::Replace(next_variable) => {
                    TransformedValue::Replace(ConditionValue::Variable(next_variable))
                }
                TransformedValue::Keep => TransformedValue::Keep,
            },
            ConditionValue::Constant(_) => TransformedValue::Keep,
        }
    }

    // Directives
    fn transform_directives(
        &mut self,
        directives: &[Directive],
    ) -> TransformedValue<Vec<Directive>> {
        if Self::VISIT_DIRECTIVES {
            self.transform_list(directives, Self::transform_directive)
        } else {
            TransformedValue::Keep
        }
    }

    fn transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        self.default_transform_directive(directive)
    }

    fn default_transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        let arguments = self.transform_arguments(&directive.arguments);
        match arguments {
            TransformedValue::Keep => Transformed::Keep,
            TransformedValue::Replace(replacement) => Transformed::Replace(Directive {
                arguments: replacement,
                ..directive.clone()
            }),
        }
    }

    // Arguments
    fn transform_arguments(&mut self, arguments: &[Argument]) -> TransformedValue<Vec<Argument>> {
        if Self::VISIT_ARGUMENTS {
            self.transform_list(arguments, Self::transform_argument)
        } else {
            TransformedValue::Keep
        }
    }

    fn transform_argument(&mut self, argument: &Argument) -> Transformed<Argument> {
        self.default_transform_argument(argument)
    }

    fn default_transform_argument(&mut self, argument: &Argument) -> Transformed<Argument> {
        match self.transform_value(&argument.value.item) {
            Transformed::Delete => Transformed::Delete,
            Transformed::Keep => Transformed::Keep,
            Transformed::Replace(replacement) => Transformed::Replace(Argument {
                value: WithLocation::new(argument.value.location, replacement),
                ..argument.clone()
            }),
        }
    }

    // Values
    fn transform_value(&mut self, value: &Value) -> Transformed<Value> {
        self.default_transform_value(value)
    }

    fn default_transform_value(&mut self, value: &Value) -> Transformed<Value> {
        match value {
            Value::Variable(variable) => match self.transform_variable(variable) {
                TransformedValue::Keep => Transformed::Keep,
                TransformedValue::Replace(replacement) => {
                    Transformed::Replace(Value::Variable(replacement))
                }
            },
            Value::Constant(_) => Transformed::Keep,
            Value::List(items) => match self.transform_list(items, Self::transform_value) {
                TransformedValue::Keep => Transformed::Keep,
                TransformedValue::Replace(replacement) => {
                    Transformed::Replace(Value::List(replacement))
                }
            },
            Value::Object(arguments) => match self.transform_arguments(arguments) {
                TransformedValue::Keep => Transformed::Keep,
                TransformedValue::Replace(replacement) => {
                    Transformed::Replace(Value::Object(replacement))
                }
            },
        }
    }

    fn transform_variable(&mut self, _variable: &Variable) -> TransformedValue<Variable> {
        TransformedValue::Keep
    }

    // Helpers
    fn transform_list<F, T>(&mut self, list: &[T], f: F) -> TransformedValue<Vec<T>>
    where
        F: Fn(&mut Self, &T) -> Transformed<T>,
        T: Clone,
    {
        if list.is_empty() {
            return TransformedValue::Keep;
        }
        let mut result = Vec::new();
        let mut has_changes = false;
        for (index, prev_item) in list.iter().enumerate() {
            let next_item = f(self, prev_item);
            match next_item {
                Transformed::Keep => {
                    if has_changes {
                        result.push(prev_item.clone());
                    }
                }
                Transformed::Delete => {
                    if !has_changes {
                        debug_assert!(result.capacity() == 0);
                        // assume most items won't be skipped and allocate space for all items
                        result.reserve(list.len());
                        result.extend(list.iter().take(index).cloned());
                    }
                    has_changes = true;
                }
                Transformed::Replace(next_item) => {
                    if !has_changes {
                        debug_assert!(result.capacity() == 0);
                        // assume most items won't be skipped and allocate space for all items
                        result.reserve(list.len());
                        result.extend(list.iter().take(index).cloned());
                    }
                    result.push(next_item);
                    has_changes = true;
                }
            }
        }
        if has_changes {
            // Note that result can be empty if the input was empty and all items were skipped
            TransformedValue::Replace(result)
        } else {
            TransformedValue::Keep
        }
    }
}

#[derive(Clone)]
pub enum Transformed<T> {
    Delete,
    Keep,
    Replace(T),
}

impl<T> Transformed<T> {
    pub fn map<F, U>(self, f: F) -> Transformed<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Transformed::Delete => Transformed::Delete,
            Transformed::Keep => Transformed::Keep,
            Transformed::Replace(replacement) => Transformed::Replace(f(replacement)),
        }
    }
}

#[derive(Clone, Debug)]
pub enum TransformedValue<T> {
    Keep,
    Replace(T),
}

impl<T> TransformedValue<T> {
    pub fn should_keep(&self) -> bool {
        match self {
            TransformedValue::Keep => true,
            TransformedValue::Replace(_) => false,
        }
    }

    pub fn replace_or_else<F>(self, f: F) -> T
    where
        F: FnOnce() -> T,
    {
        match self {
            TransformedValue::Keep => f(),
            TransformedValue::Replace(next_value) => next_value,
        }
    }
}
<commit_msg>Transformer::transform_value now returns TransformedValue<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 crate::ir::*;
use crate::program::Program;
use common::WithLocation;
use std::sync::Arc;

pub trait Transformer {
    const NAME: &'static str;
    const VISIT_ARGUMENTS: bool;
    const VISIT_DIRECTIVES: bool;

    fn transform_program<'s>(&mut self, program: &Program<'s>) -> TransformedValue<Program<'s>> {
        self.default_transform_program(program)
    }

    fn default_transform_program<'s>(
        &mut self,
        program: &Program<'s>,
    ) -> TransformedValue<Program<'s>> {
        let mut next_program = Program::new(program.schema());
        let mut has_changes = false;
        for operation in program.operations() {
            match self.transform_operation(operation) {
                Transformed::Delete => has_changes = true,
                Transformed::Keep => next_program.insert_operation(Arc::clone(operation)),
                Transformed::Replace(replacement) => {
                    has_changes = true;
                    next_program.insert_operation(Arc::new(replacement))
                }
            }
        }
        for fragment in program.fragments() {
            match self.transform_fragment(fragment) {
                Transformed::Delete => has_changes = true,
                Transformed::Keep => next_program.insert_fragment(Arc::clone(fragment)),
                Transformed::Replace(replacement) => {
                    has_changes = true;
                    next_program.insert_fragment(Arc::new(replacement))
                }
            }
        }
        if has_changes {
            TransformedValue::Replace(next_program)
        } else {
            TransformedValue::Keep
        }
    }

    // Fragment Definition
    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        self.default_transform_fragment(fragment)
    }

    fn default_transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        // Special-case for empty selections
        let selections = self.transform_selections(&fragment.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&fragment.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(FragmentDefinition {
            directives: directives.replace_or_else(|| fragment.directives.clone()),
            selections: selections.replace_or_else(|| fragment.selections.clone()),
            ..fragment.clone()
        })
    }

    // Operation Definition
    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        self.default_transform_operation(operation)
    }

    fn default_transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        let selections = self.transform_selections(&operation.selections);
        // Special-case for empty selections
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&operation.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(OperationDefinition {
            directives: directives.replace_or_else(|| operation.directives.clone()),
            selections: selections.replace_or_else(|| operation.selections.clone()),
            ..operation.clone()
        })
    }

    // Selection
    fn transform_selections(
        &mut self,
        selections: &[Selection],
    ) -> TransformedValue<Vec<Selection>> {
        self.transform_list(selections, Self::transform_selection)
    }

    fn transform_selection(&mut self, selection: &Selection) -> Transformed<Selection> {
        self.default_transform_selection(selection)
    }

    fn default_transform_selection(&mut self, selection: &Selection) -> Transformed<Selection> {
        match selection {
            Selection::FragmentSpread(selection) => self
                .transform_fragment_spread(selection)
                .map(Selection::FragmentSpread),
            Selection::InlineFragment(selection) => self
                .transform_inline_fragment(selection)
                .map(Selection::InlineFragment),
            Selection::LinkedField(selection) => self
                .transform_linked_field(selection)
                .map(Selection::LinkedField),
            Selection::ScalarField(selection) => self
                .transform_scalar_field(selection)
                .map(Selection::ScalarField),
            Selection::Condition(selection) => self
                .transform_condition(selection)
                .map(Selection::Condition),
        }
    }

    // Selection Kinds
    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Arc<ScalarField>> {
        self.default_transform_scalar_field(field)
    }

    fn default_transform_scalar_field(
        &mut self,
        field: &ScalarField,
    ) -> Transformed<Arc<ScalarField>> {
        let arguments = self.transform_arguments(&field.arguments);
        let directives = self.transform_directives(&field.directives);
        if arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(ScalarField {
            arguments: arguments.replace_or_else(|| field.arguments.clone()),
            directives: directives.replace_or_else(|| field.directives.clone()),
            ..field.clone()
        }))
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Arc<LinkedField>> {
        self.default_transform_linked_field(field)
    }

    fn default_transform_linked_field(
        &mut self,
        field: &LinkedField,
    ) -> Transformed<Arc<LinkedField>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&field.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let arguments = self.transform_arguments(&field.arguments);
        let directives = self.transform_directives(&field.directives);
        if selections.should_keep() && arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(LinkedField {
            arguments: arguments.replace_or_else(|| field.arguments.clone()),
            directives: directives.replace_or_else(|| field.directives.clone()),
            selections: selections.replace_or_else(|| field.selections.clone()),
            ..field.clone()
        }))
    }

    fn transform_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> Transformed<Arc<InlineFragment>> {
        self.default_transform_inline_fragment(fragment)
    }

    fn default_transform_inline_fragment(
        &mut self,
        fragment: &InlineFragment,
    ) -> Transformed<Arc<InlineFragment>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&fragment.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let directives = self.transform_directives(&fragment.directives);
        if selections.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(InlineFragment {
            directives: directives.replace_or_else(|| fragment.directives.clone()),
            selections: selections.replace_or_else(|| fragment.selections.clone()),
            ..fragment.clone()
        }))
    }

    fn transform_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> Transformed<Arc<FragmentSpread>> {
        self.default_transform_fragment_spread(spread)
    }
    fn default_transform_fragment_spread(
        &mut self,
        spread: &FragmentSpread,
    ) -> Transformed<Arc<FragmentSpread>> {
        let arguments = self.transform_arguments(&spread.arguments);
        let directives = self.transform_directives(&spread.directives);
        if arguments.should_keep() && directives.should_keep() {
            return Transformed::Keep;
        }
        Transformed::Replace(Arc::new(FragmentSpread {
            arguments: arguments.replace_or_else(|| spread.arguments.clone()),
            directives: directives.replace_or_else(|| spread.directives.clone()),
            ..spread.clone()
        }))
    }

    // Conditions
    fn transform_condition(&mut self, condition: &Condition) -> Transformed<Arc<Condition>> {
        self.default_transform_condition(condition)
    }

    fn default_transform_condition(
        &mut self,
        condition: &Condition,
    ) -> Transformed<Arc<Condition>> {
        // Special-case for empty selections
        let selections = self.transform_selections(&condition.selections);
        if let TransformedValue::Replace(selections) = &selections {
            if selections.is_empty() {
                return Transformed::Delete;
            }
        }
        let condition_value = self.transform_condition_value(&condition.value);
        if selections.should_keep() && condition_value.should_keep() {
            Transformed::Keep
        } else {
            Transformed::Replace(Arc::new(Condition {
                value: condition_value.replace_or_else(|| condition.value.clone()),
                selections: selections.replace_or_else(|| condition.selections.clone()),
                ..condition.clone()
            }))
        }
    }

    fn transform_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> TransformedValue<ConditionValue> {
        if Self::VISIT_ARGUMENTS {
            self.default_transform_condition_value(condition_value)
        } else {
            TransformedValue::Keep
        }
    }

    fn default_transform_condition_value(
        &mut self,
        condition_value: &ConditionValue,
    ) -> TransformedValue<ConditionValue> {
        match condition_value {
            ConditionValue::Variable(variable) => self
                .transform_variable(variable)
                .map(ConditionValue::Variable),
            ConditionValue::Constant(_) => TransformedValue::Keep,
        }
    }

    // Directives
    fn transform_directives(
        &mut self,
        directives: &[Directive],
    ) -> TransformedValue<Vec<Directive>> {
        if Self::VISIT_DIRECTIVES {
            self.transform_list(directives, Self::transform_directive)
        } else {
            TransformedValue::Keep
        }
    }

    fn transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        self.default_transform_directive(directive)
    }

    fn default_transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        let arguments = self.transform_arguments(&directive.arguments);
        match arguments {
            TransformedValue::Keep => Transformed::Keep,
            TransformedValue::Replace(replacement) => Transformed::Replace(Directive {
                arguments: replacement,
                ..directive.clone()
            }),
        }
    }

    // Arguments
    fn transform_arguments(&mut self, arguments: &[Argument]) -> TransformedValue<Vec<Argument>> {
        if Self::VISIT_ARGUMENTS {
            self.transform_list(arguments, Self::transform_argument)
        } else {
            TransformedValue::Keep
        }
    }

    fn transform_argument(&mut self, argument: &Argument) -> Transformed<Argument> {
        self.default_transform_argument(argument)
    }

    fn default_transform_argument(&mut self, argument: &Argument) -> Transformed<Argument> {
        match self.transform_value(&argument.value.item) {
            TransformedValue::Keep => Transformed::Keep,
            TransformedValue::Replace(replacement) => Transformed::Replace(Argument {
                value: WithLocation::new(argument.value.location, replacement),
                ..argument.clone()
            }),
        }
    }

    // Values
    fn transform_value(&mut self, value: &Value) -> TransformedValue<Value> {
        self.default_transform_value(value)
    }

    fn default_transform_value(&mut self, value: &Value) -> TransformedValue<Value> {
        match value {
            Value::Variable(variable) => self.transform_variable(variable).map(Value::Variable),
            Value::Constant(_) => TransformedValue::Keep,
            Value::List(items) => self
                .transform_list(items, Self::transform_value)
                .map(Value::List),
            Value::Object(arguments) => self.transform_arguments(arguments).map(Value::Object),
        }
    }

    fn transform_variable(&mut self, _variable: &Variable) -> TransformedValue<Variable> {
        TransformedValue::Keep
    }

    // Helpers
    fn transform_list<T, F, R>(&mut self, list: &[T], f: F) -> TransformedValue<Vec<T>>
    where
        T: Clone,
        F: Fn(&mut Self, &T) -> R,
        R: Into<Transformed<T>>,
    {
        let mut result = Vec::new();
        let mut has_changes = false;
        for (index, prev_item) in list.iter().enumerate() {
            let next_item: Transformed<_> = f(self, prev_item).into();
            match next_item {
                Transformed::Keep => {
                    if has_changes {
                        result.push(prev_item.clone());
                    }
                }
                Transformed::Delete => {
                    if !has_changes {
                        debug_assert!(result.capacity() == 0);
                        // assume most items won't be skipped and allocate space for all items
                        result.reserve(list.len());
                        result.extend(list.iter().take(index).cloned());
                    }
                    has_changes = true;
                }
                Transformed::Replace(next_item) => {
                    if !has_changes {
                        debug_assert!(result.capacity() == 0);
                        // assume most items won't be skipped and allocate space for all items
                        result.reserve(list.len());
                        result.extend(list.iter().take(index).cloned());
                    }
                    result.push(next_item);
                    has_changes = true;
                }
            }
        }
        if has_changes {
            // Note that result can be empty if the input was empty and all items were skipped
            TransformedValue::Replace(result)
        } else {
            TransformedValue::Keep
        }
    }
}

#[derive(Clone)]
pub enum Transformed<T> {
    Delete,
    Keep,
    Replace(T),
}

impl<T> Transformed<T> {
    pub fn map<F, U>(self, f: F) -> Transformed<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Transformed::Delete => Transformed::Delete,
            Transformed::Keep => Transformed::Keep,
            Transformed::Replace(replacement) => Transformed::Replace(f(replacement)),
        }
    }
}

#[derive(Clone, Debug)]
pub enum TransformedValue<T> {
    Keep,
    Replace(T),
}

impl<T> TransformedValue<T> {
    pub fn should_keep(&self) -> bool {
        match self {
            TransformedValue::Keep => true,
            TransformedValue::Replace(_) => false,
        }
    }

    pub fn replace_or_else<F>(self, f: F) -> T
    where
        F: FnOnce() -> T,
    {
        match self {
            TransformedValue::Keep => f(),
            TransformedValue::Replace(next_value) => next_value,
        }
    }

    pub fn map<F, U>(self, f: F) -> TransformedValue<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            TransformedValue::Keep => TransformedValue::Keep,
            TransformedValue::Replace(replacement) => TransformedValue::Replace(f(replacement)),
        }
    }
}

impl<T> Into<Transformed<T>> for TransformedValue<T> {
    fn into(self) -> Transformed<T> {
        match self {
            TransformedValue::Keep => Transformed::Keep,
            TransformedValue::Replace(replacement) => Transformed::Replace(replacement),
        }
    }
}
<|endoftext|>


<commit_before>use decoders::Image;

pub fn gamma(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];

  let g: f32 = 1.0 / 2.4;
  let f: f32 = 0.055;
  let min: f32 = 0.0031308;
  let mul: f32 = 12.92;

  let mut pos = 0;
  for val in inb {
    out[pos] = if *val <= min {
      mul * val
    } else {
      ((1.0+f) * val).powf(g) - f
    };

    pos += 1;
  }

  out
}
<commit_msg>gamma: use rec709 gamma constants for PPM<commit_after>use decoders::Image;

pub fn gamma(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];

  let g: f32 = 0.45;
  let f: f32 = 0.099;
  let min: f32 = 0.018;
  let mul: f32 = 4.5;

  let mut pos = 0;
  for val in inb {
    out[pos] = if *val <= min {
      mul * val
    } else {
      ((1.0+f) * val).powf(g) - f
    };

    pos += 1;
  }

  out
}
<|endoftext|>


<commit_before>/* Simple getopt alternative. Construct a vector of options, either by using
 * reqopt, optopt, and optflag or by building them from components yourself,
 * and pass them to getopts, along with a vector of actual arguments (not
 * including argv[0]). You'll either get a failure code back, or a match.
 * You'll have to verify whether the amount of 'free' arguments in the match
 * is what you expect. Use opt_* accessors (bottom of the file) to get
 * argument values out of the match object.
 */

import option::some;
import option::none;

export opt;

export reqopt;
export optopt;
export optflag;
export optmulti;

export getopts;

export result;
export success;
export failure;

export match;

export fail_;
export fail_str;

export opt_present;
export opt_str;
export opt_strs;
export opt_maybe_str;

tag name { long(str); short(char); }
tag hasarg { yes; no; maybe; }
tag occur { req; optional; multi; }

type opt = rec(name name, hasarg hasarg, occur occur);

fn mkname(str nm) -> name {
    ret if (str::char_len(nm) == 1u) {
        short(str::char_at(nm, 0u))
    } else {
        long(nm)
    };
}
fn reqopt(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=req);
}
fn optopt(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=optional);
}
fn optflag(str name) -> opt {
    ret rec(name=mkname(name), hasarg=no, occur=optional);
}
fn optmulti(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=multi);
}

tag optval {
    val(str);
    given;
}

type match = rec(vec[opt] opts, vec[mutable vec[optval]] vals, vec[str] free);

fn is_arg(str arg) -> bool {
    ret str::byte_len(arg) > 1u && arg.(0) == '-' as u8;
}
fn name_str(name nm) -> str {
    ret alt (nm) {
        case (short(?ch)) {str::from_char(ch)}
        case (long(?s)) {s}
    };
}

// FIXME rustboot workaround
fn name_eq(name a, name b) -> bool {
    ret alt (a) {
        case (long(?a)) {
            alt (b) {
                case (long(?b)) { str::eq(a, b) }
                case (_) { false }
            }
        }
        case (_) { if (a == b) { true } else { false } }
    };
}
fn find_opt(vec[opt] opts, name nm) -> option::t[uint] {
    auto i = 0u;
    auto l = vec::len[opt](opts);
    while (i < l) {
        if (name_eq(opts.(i).name, nm)) { ret some[uint](i); }
        i += 1u;
    }
    ret none[uint];
}

tag fail_ {
    argument_missing(str);
    unrecognized_option(str);
    option_missing(str);
    option_duplicated(str);
    unexpected_argument(str);
}

fn fail_str(fail_ f) -> str {
    ret alt (f) {
        case (argument_missing(?nm)) {
            "Argument to option '" + nm + "' missing."
        }
        case (unrecognized_option(?nm)) {
            "Unrecognized option: '" + nm + "'."
        }
        case (option_missing(?nm)) {
            "Required option '" + nm + "' missing."
        }
        case (option_duplicated(?nm)) {
            "Option '" + nm + "' given more than once."
        }
        case (unexpected_argument(?nm)) {
            "Option " + nm + " does not take an argument."
        }
    };
}

tag result {
    success(match);
    failure(fail_);
}

fn getopts(vec[str] args, vec[opt] opts) -> result {
    auto n_opts = vec::len[opt](opts);
    fn empty_(uint x) -> vec[optval]{ret vec::empty[optval]();}
    auto f = empty_;
    auto vals = vec::init_fn_mut[vec[optval]](f, n_opts);
    let vec[str] free = [];

    auto l = vec::len[str](args);
    auto i = 0u;
    while (i < l) {
        auto cur = args.(i);
        auto curlen = str::byte_len(cur);
        if (!is_arg(cur)) {
            vec::push[str](free, cur);
        } else if (str::eq(cur, "--")) {
            free += vec::slice[str](args, i + 1u, l);
            break;
        } else {
            auto names;
            auto i_arg = option::none[str];
            if (cur.(1) == '-' as u8) {
                auto tail = str::slice(cur, 2u, curlen);
                auto eq = str::index(tail, '=' as u8);
                if (eq == -1) {
                    names = [long(tail)];
                } else {
                    names = [long(str::slice(tail, 0u, eq as uint))];
                    i_arg = option::some[str]
                        (str::slice(tail, (eq as uint) + 1u, curlen - 2u));
                }
            } else {
                auto j = 1u;
                names = [];
                while (j < curlen) {
                    auto range = str::char_range_at(cur, j);
                    vec::push[name](names, short(range._0));
                    j = range._1;
                }
            }
            auto name_pos = 0u;
            for (name nm in names) {
                name_pos += 1u;
                auto optid;
                alt (find_opt(opts, nm)) {
                    case (some(?id)) {optid = id;}
                    case (none) {
                        ret failure(unrecognized_option(name_str(nm)));
                    }
                }
                alt (opts.(optid).hasarg) {
                    case (no) {
                        if (!option::is_none[str](i_arg)) {
                            ret failure(unexpected_argument(name_str(nm)));
                        }
                        vec::push[optval](vals.(optid), given);
                    }
                    case (maybe) {
                        if (!option::is_none[str](i_arg)) {
                            vec::push[optval](vals.(optid),
                                              val(option::get[str](i_arg)));
                        } else if (name_pos < vec::len[name](names) ||
                                   i + 1u == l || is_arg(args.(i + 1u))) {
                            vec::push[optval](vals.(optid), given);
                        } else {
                            i += 1u;
                            vec::push[optval](vals.(optid), val(args.(i)));
                        }
                    }
                    case (yes) {
                        if (!option::is_none[str](i_arg)) {
                            vec::push[optval](vals.(optid),
                                              val(option::get[str](i_arg)));
                        } else if (i + 1u == l) {
                            ret failure(argument_missing(name_str(nm)));
                        } else {
                            i += 1u;
                            vec::push[optval](vals.(optid), val(args.(i)));
                        }
                    }
                }
            }
        }
        i += 1u;
    }

    i = 0u;
    while (i < n_opts) {
        auto n = vec::len[optval](vals.(i));
        auto occ = opts.(i).occur;
        if (occ == req) {if (n == 0u) {
            ret failure(option_missing(name_str(opts.(i).name)));
        }}
        if (occ != multi) {if (n > 1u) {
            ret failure(option_duplicated(name_str(opts.(i).name)));
        }}
        i += 1u;
    }

    ret success(rec(opts=opts, vals=vals, free=free));
}

fn opt_vals(match m, str nm) -> vec[optval] {
    ret alt (find_opt(m.opts, mkname(nm))) {
        case (some(?id)) { m.vals.(id) }
        case (none) {
            log_err "No option '" + nm + "' defined.";
            fail
        }
    };
}
fn opt_val(match m, str nm) -> optval {
    ret opt_vals(m, nm).(0);
}
fn opt_present(match m, str nm) -> bool {
    ret vec::len[optval](opt_vals(m, nm)) > 0u;
}
fn opt_str(match m, str nm) -> str {
    ret alt (opt_val(m, nm)) {
        case (val(?s)) { s }
        case (_) { fail }
    };
}
fn opt_strs(match m, str nm) -> vec[str] {
    let vec[str] acc = [];
    for (optval v in opt_vals(m, nm)) {
        alt (v) {
            case (val(?s)) { vec::push[str](acc, s); }
            case (_) {}
        }
    }
    ret acc;
}
fn opt_maybe_str(match m, str nm) -> option::t[str] {
    auto vals = opt_vals(m, nm);
    if (vec::len[optval](vals) == 0u) { ret none[str]; }
    ret alt (vals.(0)) {
        case (val(?s)) { some[str](s) }
        case (_) { none[str] }
    };
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Add some functions to getopts to deal with optional arguments more easily<commit_after>/* Simple getopt alternative. Construct a vector of options, either by using
 * reqopt, optopt, and optflag or by building them from components yourself,
 * and pass them to getopts, along with a vector of actual arguments (not
 * including argv[0]). You'll either get a failure code back, or a match.
 * You'll have to verify whether the amount of 'free' arguments in the match
 * is what you expect. Use opt_* accessors (bottom of the file) to get
 * argument values out of the match object.
 */

import option::some;
import option::none;

export opt;

export reqopt;
export optopt;
export optflag;
export optflagopt;
export optmulti;

export getopts;

export result;
export success;
export failure;

export match;

export fail_;
export fail_str;

export opt_present;
export opt_str;
export opt_strs;
export opt_maybe_str;
export opt_default;

tag name { long(str); short(char); }
tag hasarg { yes; no; maybe; }
tag occur { req; optional; multi; }

type opt = rec(name name, hasarg hasarg, occur occur);

fn mkname(str nm) -> name {
    ret if (str::char_len(nm) == 1u) {
        short(str::char_at(nm, 0u))
    } else {
        long(nm)
    };
}
fn reqopt(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=req);
}
fn optopt(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=optional);
}
fn optflag(str name) -> opt {
    ret rec(name=mkname(name), hasarg=no, occur=optional);
}
fn optflagopt(str name) -> opt {
    ret rec(name=mkname(name), hasarg=maybe, occur=optional);
}
fn optmulti(str name) -> opt {
    ret rec(name=mkname(name), hasarg=yes, occur=multi);
}

tag optval {
    val(str);
    given;
}

type match = rec(vec[opt] opts, vec[mutable vec[optval]] vals, vec[str] free);

fn is_arg(str arg) -> bool {
    ret str::byte_len(arg) > 1u && arg.(0) == '-' as u8;
}
fn name_str(name nm) -> str {
    ret alt (nm) {
        case (short(?ch)) {str::from_char(ch)}
        case (long(?s)) {s}
    };
}

// FIXME rustboot workaround
fn name_eq(name a, name b) -> bool {
    ret alt (a) {
        case (long(?a)) {
            alt (b) {
                case (long(?b)) { str::eq(a, b) }
                case (_) { false }
            }
        }
        case (_) { if (a == b) { true } else { false } }
    };
}
fn find_opt(vec[opt] opts, name nm) -> option::t[uint] {
    auto i = 0u;
    auto l = vec::len[opt](opts);
    while (i < l) {
        if (name_eq(opts.(i).name, nm)) { ret some[uint](i); }
        i += 1u;
    }
    ret none[uint];
}

tag fail_ {
    argument_missing(str);
    unrecognized_option(str);
    option_missing(str);
    option_duplicated(str);
    unexpected_argument(str);
}

fn fail_str(fail_ f) -> str {
    ret alt (f) {
        case (argument_missing(?nm)) {
            "Argument to option '" + nm + "' missing."
        }
        case (unrecognized_option(?nm)) {
            "Unrecognized option: '" + nm + "'."
        }
        case (option_missing(?nm)) {
            "Required option '" + nm + "' missing."
        }
        case (option_duplicated(?nm)) {
            "Option '" + nm + "' given more than once."
        }
        case (unexpected_argument(?nm)) {
            "Option " + nm + " does not take an argument."
        }
    };
}

tag result {
    success(match);
    failure(fail_);
}

fn getopts(vec[str] args, vec[opt] opts) -> result {
    auto n_opts = vec::len[opt](opts);
    fn empty_(uint x) -> vec[optval]{ret vec::empty[optval]();}
    auto f = empty_;
    auto vals = vec::init_fn_mut[vec[optval]](f, n_opts);
    let vec[str] free = [];

    auto l = vec::len[str](args);
    auto i = 0u;
    while (i < l) {
        auto cur = args.(i);
        auto curlen = str::byte_len(cur);
        if (!is_arg(cur)) {
            vec::push[str](free, cur);
        } else if (str::eq(cur, "--")) {
            free += vec::slice[str](args, i + 1u, l);
            break;
        } else {
            auto names;
            auto i_arg = option::none[str];
            if (cur.(1) == '-' as u8) {
                auto tail = str::slice(cur, 2u, curlen);
                auto eq = str::index(tail, '=' as u8);
                if (eq == -1) {
                    names = [long(tail)];
                } else {
                    names = [long(str::slice(tail, 0u, eq as uint))];
                    i_arg = option::some[str]
                        (str::slice(tail, (eq as uint) + 1u, curlen - 2u));
                }
            } else {
                auto j = 1u;
                names = [];
                while (j < curlen) {
                    auto range = str::char_range_at(cur, j);
                    vec::push[name](names, short(range._0));
                    j = range._1;
                }
            }
            auto name_pos = 0u;
            for (name nm in names) {
                name_pos += 1u;
                auto optid;
                alt (find_opt(opts, nm)) {
                    case (some(?id)) {optid = id;}
                    case (none) {
                        ret failure(unrecognized_option(name_str(nm)));
                    }
                }
                alt (opts.(optid).hasarg) {
                    case (no) {
                        if (!option::is_none[str](i_arg)) {
                            ret failure(unexpected_argument(name_str(nm)));
                        }
                        vec::push[optval](vals.(optid), given);
                    }
                    case (maybe) {
                        if (!option::is_none[str](i_arg)) {
                            vec::push[optval](vals.(optid),
                                              val(option::get[str](i_arg)));
                        } else if (name_pos < vec::len[name](names) ||
                                   i + 1u == l || is_arg(args.(i + 1u))) {
                            vec::push[optval](vals.(optid), given);
                        } else {
                            i += 1u;
                            vec::push[optval](vals.(optid), val(args.(i)));
                        }
                    }
                    case (yes) {
                        if (!option::is_none[str](i_arg)) {
                            vec::push[optval](vals.(optid),
                                              val(option::get[str](i_arg)));
                        } else if (i + 1u == l) {
                            ret failure(argument_missing(name_str(nm)));
                        } else {
                            i += 1u;
                            vec::push[optval](vals.(optid), val(args.(i)));
                        }
                    }
                }
            }
        }
        i += 1u;
    }

    i = 0u;
    while (i < n_opts) {
        auto n = vec::len[optval](vals.(i));
        auto occ = opts.(i).occur;
        if (occ == req) {if (n == 0u) {
            ret failure(option_missing(name_str(opts.(i).name)));
        }}
        if (occ != multi) {if (n > 1u) {
            ret failure(option_duplicated(name_str(opts.(i).name)));
        }}
        i += 1u;
    }

    ret success(rec(opts=opts, vals=vals, free=free));
}

fn opt_vals(match m, str nm) -> vec[optval] {
    ret alt (find_opt(m.opts, mkname(nm))) {
        case (some(?id)) { m.vals.(id) }
        case (none) {
            log_err "No option '" + nm + "' defined.";
            fail
        }
    };
}
fn opt_val(match m, str nm) -> optval {
    ret opt_vals(m, nm).(0);
}
fn opt_present(match m, str nm) -> bool {
    ret vec::len[optval](opt_vals(m, nm)) > 0u;
}
fn opt_str(match m, str nm) -> str {
    ret alt (opt_val(m, nm)) {
        case (val(?s)) { s }
        case (_) { fail }
    };
}
fn opt_strs(match m, str nm) -> vec[str] {
    let vec[str] acc = [];
    for (optval v in opt_vals(m, nm)) {
        alt (v) {
            case (val(?s)) { vec::push[str](acc, s); }
            case (_) {}
        }
    }
    ret acc;
}
fn opt_maybe_str(match m, str nm) -> option::t[str] {
    auto vals = opt_vals(m, nm);
    if (vec::len[optval](vals) == 0u) { ret none[str]; }
    ret alt (vals.(0)) {
        case (val(?s)) { some[str](s) }
        case (_) { none[str] }
    };
}

/// Returns none if the option was not present, `def` if the option was
/// present but no argument was provided, and the argument if the option was
/// present and an argument was provided.
fn opt_default(match m, str nm, str def) -> option::t[str] {
    auto vals = opt_vals(m, nm);
    if (vec::len[optval](vals) == 0u) { ret none[str]; }
    ret alt (vals.(0)) {
        case (val(?s)) { some[str](s) }
        case (_) { some[str](def) }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>//! Types which pin data to its location in memory
//!
//! It is sometimes useful to have objects that are guaranteed to not move,
//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
//! A prime example of such a scenario would be building self-referential structs,
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
//! moving the values they contain. In order to prevent objects from moving, they must
//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
//! Doing this prohibits moving the value behind the pointer.
//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
//! but the value behind it cannot.
//!
//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! changing the location of the underlying data, [`Pin`] prohibits accessing the
//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
//! functions will move the pointed-to value. This allows for the creation of
//! self-references and other special behaviors that are only possible for unmovable
//! values.
//!
//! However, these restrictions are usually not necessary. Many types are always freely
//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect
//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
//! `Pin<&mut T>` and `&mut T`.
//!
//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
//! are always freely movable, even if the data they point to isn't.
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
//! [`swap`]: ../../std/mem/fn.swap.html
//! [`Box`]: ../../std/boxed/struct.Box.html
//!
//! # Examples
//!
//! ```rust
//! use std::pin::Pin;
//! use std::marker::PhantomPinned;
//! use std::ptr::NonNull;
//!
//! // This is a self-referential struct since the slice field points to the data field.
//! // We cannot inform the compiler about that with a normal reference,
//! // since this pattern cannot be described with the usual borrowing rules.
//! // Instead we use a raw pointer, though one which is known to not be null,
//! // since we know it's pointing at the string.
//! struct Unmovable {
//!     data: String,
//!     slice: NonNull<String>,
//!     _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
//!     // To ensure the data doesn't move when the function returns,
//!     // we place it in the heap where it will stay for the lifetime of the object,
//!     // and the only way to access it would be through a pointer to it.
//!     fn new(data: String) -> Pin<Box<Self>> {
//!         let res = Unmovable {
//!             data,
//!             // we only create the pointer once the data is in place
//!             // otherwise it will have already moved before we even started
//!             slice: NonNull::dangling(),
//!             _pin: PhantomPinned,
//!         };
//!         let mut boxed = Box::pin(res);
//!
//!         let slice = NonNull::from(&boxed.data);
//!         // we know this is safe because modifying a field doesn't move the whole struct
//!         unsafe {
//!             let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
//!             Pin::get_unchecked_mut(mut_ref).slice = slice;
//!         }
//!         boxed
//!     }
//! }
//!
//! let unmoved = Unmovable::new("hello".to_string());
//! // The pointer should point to the correct location,
//! // so long as the struct hasn't moved.
//! // Meanwhile, we are free to move the pointer around.
//! # #[allow(unused_mut)]
//! let mut still_unmoved = unmoved;
//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
//!
//! // Since our type doesn't implement Unpin, this will fail to compile:
//! // let new_unmoved = Unmovable::new("world".to_string());
//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
//! ```

#![stable(feature = "pin", since = "1.33.0")]

use fmt;
use marker::{Sized, Unpin};
use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};

/// A pinned pointer.
///
/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
/// See the [`pin` module] documentation for further explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
// Note: the derives below are allowed because they all only use `&P`, so they
// cannot move the value behind `pointer`.
#[stable(feature = "pin", since = "1.33.0")]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pin
 {
    pointer: P,
}

impl
 Pin

where
    P::Target: Unpin,
{
    /// Construct a new `Pin` around a pointer to some data of a type that
    /// implements `Unpin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn new(pointer: P) -> Pin
 {
        // Safety: the value pointed to is `Unpin`, and so has no requirements
        // around pinning.
        unsafe { Pin::new_unchecked(pointer) }
    }
}

impl
 Pin
 {
    /// Construct a new `Pin` around a reference to some data of a type that
    /// may or may not implement `Unpin`.
    ///
    /// # Safety
    ///
    /// This constructor is unsafe because we cannot guarantee that the data
    /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
    /// not guarantee that the data `P` points to is pinned, constructing a
    /// `Pin<P>` is undefined behavior.
    ///
    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn new_unchecked(pointer: P) -> Pin
 {
        Pin { pointer }
    }

    /// Get a pinned shared reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_ref(self: &Pin
) -> Pin<&P::Target> {
        unsafe { Pin::new_unchecked(&*self.pointer) }
    }
}

impl
 Pin
 {
    /// Get a pinned mutable reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_mut(self: &mut Pin
) -> Pin<&mut P::Target> {
        unsafe { Pin::new_unchecked(&mut *self.pointer) }
    }

    /// Assign a new value to the memory behind the pinned reference.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn set(mut self: Pin
, value: P::Target)
    where
        P::Target: Sized,
    {
        *self.pointer = value;
    }
}

impl<'a, T: ?Sized> Pin<&'a T> {
    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
        F: FnOnce(&T) -> &U,
    {
        let pointer = &*self.pointer;
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }

    /// Get a shared reference out of a pin.
    ///
    /// Note: `Pin` also implements `Deref` to the target, which can be used
    /// to access the inner value. However, `Deref` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_ref(self: Pin<&'a T>) -> &'a T {
        self.pointer
    }
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
    /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
        Pin { pointer: self.pointer }
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// This requires that the data inside this `Pin` is `Unpin`.
    ///
    /// Note: `Pin` also implements `DerefMut` to the data, which can be used
    /// to access the inner value. However, `DerefMut` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
        where T: Unpin,
    {
        self.pointer
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that you will never move
    /// the data out of the mutable reference you receive when you call this
    /// function, so that the invariants on the `Pin` type can be upheld.
    ///
    /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
        self.pointer
    }

    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
        F: FnOnce(&mut T) -> &mut U,
    {
        let pointer = Pin::get_unchecked_mut(self);
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 Deref for Pin
 {
    type Target = P::Target;
    fn deref(&self) -> &P::Target {
        Pin::get_ref(Pin::as_ref(self))
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 DerefMut for Pin

where
    P::Target: Unpin
{
    fn deref_mut(&mut self) -> &mut P::Target {
        Pin::get_mut(Pin::as_mut(self))
    }
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl
 Receiver for Pin
 {}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Debug for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Display for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Pointer for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&self.pointer, f)
    }
}

// Note: this means that any impl of `CoerceUnsized` that allows coercing from
// a type that impls `Deref<Target=impl !Unpin>` to a type that impls
// `Deref<Target=Unpin>` is unsound. Any such impl would probably be unsound
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[stable(feature = "pin", since = "1.33.0")]
impl
 CoerceUnsized<Pin> for Pin

where
    P: CoerceUnsized,
{}

#[stable(feature = "pin", since = "1.33.0")]
impl<'a, P, U> DispatchFromDyn<Pin> for Pin

where
    P: DispatchFromDyn,
{}
<commit_msg>Auto merge of #57419 - cramertj:pin-set, r=withouboats<commit_after>//! Types which pin data to its location in memory
//!
//! It is sometimes useful to have objects that are guaranteed to not move,
//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
//! A prime example of such a scenario would be building self-referential structs,
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
//! moving the values they contain. In order to prevent objects from moving, they must
//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
//! Doing this prohibits moving the value behind the pointer.
//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
//! but the value behind it cannot.
//!
//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! changing the location of the underlying data, [`Pin`] prohibits accessing the
//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
//! functions will move the pointed-to value. This allows for the creation of
//! self-references and other special behaviors that are only possible for unmovable
//! values.
//!
//! However, these restrictions are usually not necessary. Many types are always freely
//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect
//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
//! `Pin<&mut T>` and `&mut T`.
//!
//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
//! are always freely movable, even if the data they point to isn't.
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
//! [`swap`]: ../../std/mem/fn.swap.html
//! [`Box`]: ../../std/boxed/struct.Box.html
//!
//! # Examples
//!
//! ```rust
//! use std::pin::Pin;
//! use std::marker::PhantomPinned;
//! use std::ptr::NonNull;
//!
//! // This is a self-referential struct since the slice field points to the data field.
//! // We cannot inform the compiler about that with a normal reference,
//! // since this pattern cannot be described with the usual borrowing rules.
//! // Instead we use a raw pointer, though one which is known to not be null,
//! // since we know it's pointing at the string.
//! struct Unmovable {
//!     data: String,
//!     slice: NonNull<String>,
//!     _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
//!     // To ensure the data doesn't move when the function returns,
//!     // we place it in the heap where it will stay for the lifetime of the object,
//!     // and the only way to access it would be through a pointer to it.
//!     fn new(data: String) -> Pin<Box<Self>> {
//!         let res = Unmovable {
//!             data,
//!             // we only create the pointer once the data is in place
//!             // otherwise it will have already moved before we even started
//!             slice: NonNull::dangling(),
//!             _pin: PhantomPinned,
//!         };
//!         let mut boxed = Box::pin(res);
//!
//!         let slice = NonNull::from(&boxed.data);
//!         // we know this is safe because modifying a field doesn't move the whole struct
//!         unsafe {
//!             let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
//!             Pin::get_unchecked_mut(mut_ref).slice = slice;
//!         }
//!         boxed
//!     }
//! }
//!
//! let unmoved = Unmovable::new("hello".to_string());
//! // The pointer should point to the correct location,
//! // so long as the struct hasn't moved.
//! // Meanwhile, we are free to move the pointer around.
//! # #[allow(unused_mut)]
//! let mut still_unmoved = unmoved;
//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
//!
//! // Since our type doesn't implement Unpin, this will fail to compile:
//! // let new_unmoved = Unmovable::new("world".to_string());
//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
//! ```

#![stable(feature = "pin", since = "1.33.0")]

use fmt;
use marker::{Sized, Unpin};
use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};

/// A pinned pointer.
///
/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
/// See the [`pin` module] documentation for further explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
// Note: the derives below are allowed because they all only use `&P`, so they
// cannot move the value behind `pointer`.
#[stable(feature = "pin", since = "1.33.0")]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pin
 {
    pointer: P,
}

impl
 Pin

where
    P::Target: Unpin,
{
    /// Construct a new `Pin` around a pointer to some data of a type that
    /// implements `Unpin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn new(pointer: P) -> Pin
 {
        // Safety: the value pointed to is `Unpin`, and so has no requirements
        // around pinning.
        unsafe { Pin::new_unchecked(pointer) }
    }
}

impl
 Pin
 {
    /// Construct a new `Pin` around a reference to some data of a type that
    /// may or may not implement `Unpin`.
    ///
    /// # Safety
    ///
    /// This constructor is unsafe because we cannot guarantee that the data
    /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
    /// not guarantee that the data `P` points to is pinned, constructing a
    /// `Pin<P>` is undefined behavior.
    ///
    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn new_unchecked(pointer: P) -> Pin
 {
        Pin { pointer }
    }

    /// Get a pinned shared reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_ref(self: &Pin
) -> Pin<&P::Target> {
        unsafe { Pin::new_unchecked(&*self.pointer) }
    }
}

impl
 Pin
 {
    /// Get a pinned mutable reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_mut(self: &mut Pin
) -> Pin<&mut P::Target> {
        unsafe { Pin::new_unchecked(&mut *self.pointer) }
    }

    /// Assign a new value to the memory behind the pinned reference.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn set(self: &mut Pin
, value: P::Target)
    where
        P::Target: Sized,
    {
        *(self.pointer) = value;
    }
}

impl<'a, T: ?Sized> Pin<&'a T> {
    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
        F: FnOnce(&T) -> &U,
    {
        let pointer = &*self.pointer;
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }

    /// Get a shared reference out of a pin.
    ///
    /// Note: `Pin` also implements `Deref` to the target, which can be used
    /// to access the inner value. However, `Deref` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_ref(self: Pin<&'a T>) -> &'a T {
        self.pointer
    }
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
    /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
        Pin { pointer: self.pointer }
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// This requires that the data inside this `Pin` is `Unpin`.
    ///
    /// Note: `Pin` also implements `DerefMut` to the data, which can be used
    /// to access the inner value. However, `DerefMut` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
        where T: Unpin,
    {
        self.pointer
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that you will never move
    /// the data out of the mutable reference you receive when you call this
    /// function, so that the invariants on the `Pin` type can be upheld.
    ///
    /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
        self.pointer
    }

    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
        F: FnOnce(&mut T) -> &mut U,
    {
        let pointer = Pin::get_unchecked_mut(self);
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 Deref for Pin
 {
    type Target = P::Target;
    fn deref(&self) -> &P::Target {
        Pin::get_ref(Pin::as_ref(self))
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 DerefMut for Pin

where
    P::Target: Unpin
{
    fn deref_mut(&mut self) -> &mut P::Target {
        Pin::get_mut(Pin::as_mut(self))
    }
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl
 Receiver for Pin
 {}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Debug for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Display for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Pointer for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&self.pointer, f)
    }
}

// Note: this means that any impl of `CoerceUnsized` that allows coercing from
// a type that impls `Deref<Target=impl !Unpin>` to a type that impls
// `Deref<Target=Unpin>` is unsound. Any such impl would probably be unsound
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[stable(feature = "pin", since = "1.33.0")]
impl
 CoerceUnsized<Pin> for Pin

where
    P: CoerceUnsized,
{}

#[stable(feature = "pin", since = "1.33.0")]
impl<'a, P, U> DispatchFromDyn<Pin> for Pin

where
    P: DispatchFromDyn,
{}
<|endoftext|>


<commit_before>extern crate irc;

use std::default::Default;
use std::thread::spawn;
use irc::client::prelude::*;

fn main() {
    let config = Config {
        nickname: Some("pickles".to_owned()),
        server: Some("irc.fyrechat.net".to_owned()),
        channels: Some(vec!["#vana".to_owned()]),
        ..Default::default()
    };
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();
    let server = server.clone();
    let _ = spawn(move || for msg in server.iter() {
        print!("{}", msg.unwrap());
    }).join(); // You might not want to join here for actual multi-threading.
}
<commit_msg>Made the multithreaded example actually do something.<commit_after>extern crate irc;

use std::default::Default;
use std::thread::spawn;
use irc::client::prelude::*;

fn main() {
    let config = Config {
        nickname: Some("pickles".to_owned()),
        server: Some("irc.fyrechat.net".to_owned()),
        channels: Some(vec!["#vana".to_owned()]),
        ..Default::default()
    };
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();
    let server = server.clone();
    let _ = spawn(move || for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        print!("{}", message);
        match message.command {
            Command::PRIVMSG(ref target, ref msg) => {
                if msg.contains("pickles") {
                    server.send_privmsg(target, "Hi!").unwrap();
                }
            }
            _ => (),
        }
    }).join(); // You might not want to join here for actual multi-threading.
}
<|endoftext|>


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

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate gfx_device_gl;
extern crate glutin;

use gfx::traits::FactoryExt;
use gfx::Device;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_vertex_struct!(Vertex {
    pos: [f32; 2] = "a_Pos",
    color: [f32; 3] = "a_Color",
});

gfx_pipeline!(pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    out: gfx::RenderTarget<ColorFormat> = "Target0",
});

const TRIANGLE: [Vertex; 3] = [
    Vertex { pos: [ -0.5, -0.5 ], color: [1.0, 0.0, 0.0] },
    Vertex { pos: [  0.5, -0.5 ], color: [0.0, 1.0, 0.0] },
    Vertex { pos: [  0.0,  0.5 ], color: [0.0, 0.0, 1.0] }
];

const CLEAR_COLOR: [f32; 4] = [0.1, 0.2, 0.3, 1.0];

pub fn main() {
    let builder = glutin::WindowBuilder::new()
        .with_title("Triangle example".to_string())
        .with_dimensions(1024, 768)
        .with_vsync();
    let (window, mut device, mut factory, main_color, _main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
    let pso = factory.create_pipeline_simple(
        include_bytes!("shader/triangle_150.glslv"),
        include_bytes!("shader/triangle_150.glslf"),
        gfx::state::CullFace::Nothing,
        pipe::new()
    ).unwrap();
    let (vertex_buffer, slice) = factory.create_vertex_buffer(&TRIANGLE);
    let data = pipe::Data {
        vbuf: vertex_buffer,
        out: main_color
    };

    'main: loop {
        // loop over events
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }
        // draw a frame
        encoder.clear(&data.out, CLEAR_COLOR);
        encoder.draw(&slice, &pso, &data);
        window.swap_buffers().unwrap();
        device.cleanup();
        encoder.flush(&mut device);
    }
}
<commit_msg>Put flush call in the right place<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate gfx_device_gl;
extern crate glutin;

use gfx::traits::FactoryExt;
use gfx::Device;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_vertex_struct!(Vertex {
    pos: [f32; 2] = "a_Pos",
    color: [f32; 3] = "a_Color",
});

gfx_pipeline!(pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    out: gfx::RenderTarget<ColorFormat> = "Target0",
});

const TRIANGLE: [Vertex; 3] = [
    Vertex { pos: [ -0.5, -0.5 ], color: [1.0, 0.0, 0.0] },
    Vertex { pos: [  0.5, -0.5 ], color: [0.0, 1.0, 0.0] },
    Vertex { pos: [  0.0,  0.5 ], color: [0.0, 0.0, 1.0] }
];

const CLEAR_COLOR: [f32; 4] = [0.1, 0.2, 0.3, 1.0];

pub fn main() {
    let builder = glutin::WindowBuilder::new()
        .with_title("Triangle example".to_string())
        .with_dimensions(1024, 768)
        .with_vsync();
    let (window, mut device, mut factory, main_color, _main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
    let pso = factory.create_pipeline_simple(
        include_bytes!("shader/triangle_150.glslv"),
        include_bytes!("shader/triangle_150.glslf"),
        gfx::state::CullFace::Nothing,
        pipe::new()
    ).unwrap();
    let (vertex_buffer, slice) = factory.create_vertex_buffer(&TRIANGLE);
    let data = pipe::Data {
        vbuf: vertex_buffer,
        out: main_color
    };

    'main: loop {
        // loop over events
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }
        // draw a frame
        encoder.clear(&data.out, CLEAR_COLOR);
        encoder.draw(&slice, &pso, &data);
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate failure;

use failure::Error;
use std::{fs, path::Path};

#[derive(Debug, Fail)]
enum FileAccessError {
    #[fail(display = "File not found: {}", file_name)]
    FileNotFoundError { file_name: String },

    #[fail(display = "Error reading file: {}", file_name)]
    FileReadError { file_name: String },
}

pub struct Flags {
    print_line_number: bool,
    print_file_name: bool,
    use_caseinsensitive_comparison: bool,
    use_inverted_comparison: bool,
    match_entire_line: bool,
}

impl Flags {
    pub fn new(flags: &[&str]) -> Self {
        Flags {
            print_line_number: flags.contains(&"-n"),
            print_file_name: flags.contains(&"-l"),
            use_caseinsensitive_comparison: flags.contains(&"-i"),
            use_inverted_comparison: flags.contains(&"-v"),
            match_entire_line: flags.contains(&"-x"),
        }
    }
}

fn get_file_lines(file_name: &str) -> Result<Vec<String>, FileAccessError> {
    let file_path = Path::new(file_name);

    if !file_path.exists() {
        return Err(FileAccessError::FileNotFoundError {
            file_name: String::from(file_name),
        });
    }

    if let Ok(content) = fs::read_to_string(file_path) {
        Ok(content.split("\n").map(|line| line.to_string()).collect())
    } else {
        Err(FileAccessError::FileReadError {
            file_name: String::from(file_name),
        })
    }
}

pub fn grep(pattern: &str, flags: &Flags, files: &[&str]) -> Result<Vec<String>, Error> {
    let mut grep_result = vec![];

    let is_multiple_file_search = files.len() > 1;

    for file_name in files {
        let file_lines = get_file_lines(file_name)?;

        grep_result.extend(
            file_lines
                .iter()
                .enumerate()
                .filter(|&(_, line)| {
                    let mut inner_line = line.clone();

                    let mut inner_pattern = String::from(pattern);

                    if flags.use_caseinsensitive_comparison {
                        inner_line = inner_line.to_lowercase().to_string();

                        inner_pattern = inner_pattern.to_lowercase().to_string();
                    }

                    let mut is_filtered = inner_line.contains(&inner_pattern);

                    if flags.match_entire_line {
                        is_filtered = inner_line == inner_pattern;
                    }

                    if flags.use_inverted_comparison {
                        is_filtered = !inner_line.contains(&inner_pattern);
                    }

                    is_filtered
                })
                .filter(|(_, line)| !line.is_empty())
                .map(|(line_number, line)| {
                    let mut result = line.to_owned();

                    if flags.print_line_number {
                        result.insert_str(0, &format!("{}:", line_number + 1));
                    }

                    if is_multiple_file_search {
                        result.insert_str(0, &format!("{}:", file_name))
                    }

                    if flags.print_file_name {
                        result = file_name.to_owned().to_owned();
                    }

                    result
                }),
        );
    }

    grep_result.dedup_by(|a, b| (*a).eq(b));

    Ok(grep_result)
}
<commit_msg>grep: Collapse `is_filtered` into one `if`/`else` expression<commit_after>#[macro_use]
extern crate failure;

use failure::Error;
use std::{fs, path::Path};

#[derive(Debug, Fail)]
enum FileAccessError {
    #[fail(display = "File not found: {}", file_name)]
    FileNotFoundError { file_name: String },

    #[fail(display = "Error reading file: {}", file_name)]
    FileReadError { file_name: String },
}

pub struct Flags {
    print_line_number: bool,
    print_file_name: bool,
    use_caseinsensitive_comparison: bool,
    use_inverted_comparison: bool,
    match_entire_line: bool,
}

impl Flags {
    pub fn new(flags: &[&str]) -> Self {
        Flags {
            print_line_number: flags.contains(&"-n"),
            print_file_name: flags.contains(&"-l"),
            use_caseinsensitive_comparison: flags.contains(&"-i"),
            use_inverted_comparison: flags.contains(&"-v"),
            match_entire_line: flags.contains(&"-x"),
        }
    }
}

fn get_file_lines(file_name: &str) -> Result<Vec<String>, FileAccessError> {
    let file_path = Path::new(file_name);

    if !file_path.exists() {
        return Err(FileAccessError::FileNotFoundError {
            file_name: String::from(file_name),
        });
    }

    if let Ok(content) = fs::read_to_string(file_path) {
        Ok(content.split("\n").map(|line| line.to_string()).collect())
    } else {
        Err(FileAccessError::FileReadError {
            file_name: String::from(file_name),
        })
    }
}

pub fn grep(pattern: &str, flags: &Flags, files: &[&str]) -> Result<Vec<String>, Error> {
    let mut grep_result = vec![];

    let is_multiple_file_search = files.len() > 1;

    for file_name in files {
        let file_lines = get_file_lines(file_name)?;

        grep_result.extend(
            file_lines
                .iter()
                .enumerate()
                .filter(|&(_, line)| {
                    let mut inner_line = line.clone();

                    let mut inner_pattern = String::from(pattern);

                    if flags.use_caseinsensitive_comparison {
                        inner_line = inner_line.to_lowercase().to_string();

                        inner_pattern = inner_pattern.to_lowercase().to_string();
                    }

                    if flags.use_inverted_comparison {
                        !inner_line.contains(&inner_pattern)
                    } else if flags.match_entire_line {
                        inner_line == inner_pattern
                    } else {
                        inner_line.contains(&inner_pattern)
                    }
                })
                .filter(|(_, line)| !line.is_empty())
                .map(|(line_number, line)| {
                    let mut result = line.to_owned();

                    if flags.print_line_number {
                        result.insert_str(0, &format!("{}:", line_number + 1));
                    }

                    if is_multiple_file_search {
                        result.insert_str(0, &format!("{}:", file_name))
                    }

                    if flags.print_file_name {
                        result = file_name.to_owned().to_owned();
                    }

                    result
                }),
        );
    }

    grep_result.dedup_by(|a, b| (*a).eq(b));

    Ok(grep_result)
}
<|endoftext|>