<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//
#![crate_name = "mnemosyne"]
#![crate_type = "lib"]
#![feature(rustc_private)]
#![feature(static_recursion)]
#![feature(box_syntax, box_patterns)]

//! # Mnemosyne core
//!
//! This crate contains the core Mnemosyne programming language components.
//! This includes the mnemosyne abstract syntax tree (`semantic::ast`),
//! functions for performing semantic analysis (`semantic`), functions
//! for compiling abstract syntax trees to LLVM bytecode (`compile`), and
//! assorted utility code such as a positional reference type and a
//! `ForkTable` data structure for use as a symbol table.
//!
//! The Mnemosyne parser is contained in a separate crate in order to improve
//! compile times.

extern crate rustc;
extern crate libc;
extern crate combine;
#[macro_use] extern crate itertools;

#[macro_use]
macro_rules! ice {
    ($msg:expr) => (
        panic!( "[internal error] {}\n \
                 [internal error] Something has gone horribly wrong.\n \
                 [internal error] Please contact the Mnemosyne implementors."
              , $msg)
          );
    ($fmt:expr, $($arg:tt)+) => (
        panic!( "[internal error] {}\n \
                 [internal error] Something has gone horribly wrong.\n \
                 [internal error] Please contact the Mnemosyne implementors."
              , format_args!($fmt, $($arg)+)
              )
          )
}

pub mod position;
pub mod semantic;
pub mod compile;
pub mod forktable;
pub mod chars;
pub mod errors;

pub use semantic::ast;

use rustc::lib::llvm::{LLVMVersionMajor, LLVMVersionMinor};

use std::fmt::Debug;

const VERSION_MAJOR: u32 = 0;
const VERSION_MINOR: u32 = 1;

/// Returns the LLVM version as a String
pub fn llvm_version() -> String {
    unsafe { format!("LLVM v{}.{}", LLVMVersionMajor(), LLVMVersionMinor()) }
}

/// Returns the Mnemosyne version as a String
pub fn mnemosyne_version() -> String {
    format!("Mnemosyne v{}.{}", VERSION_MAJOR, VERSION_MINOR)
}
<commit_msg>ICE macro prints the Mnemosyne and LLVM versions<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//
#![crate_name = "mnemosyne"]
#![crate_type = "lib"]
#![feature(rustc_private)]
#![feature(static_recursion)]
#![feature(box_syntax, box_patterns)]

//! # Mnemosyne core
//!
//! This crate contains the core Mnemosyne programming language components.
//! This includes the mnemosyne abstract syntax tree (`semantic::ast`),
//! functions for performing semantic analysis (`semantic`), functions
//! for compiling abstract syntax trees to LLVM bytecode (`compile`), and
//! assorted utility code such as a positional reference type and a
//! `ForkTable` data structure for use as a symbol table.
//!
//! The Mnemosyne parser is contained in a separate crate in order to improve
//! compile times.

extern crate rustc;
extern crate libc;
extern crate combine;
#[macro_use] extern crate itertools;

/// Macro for formatting an internal compiler error panic.
///
/// This should be used instead of the Rust standard library's `panic!()`
/// macro in the event of an unrecoverable internal compiler error.
#[macro_use]
macro_rules! ice {
    ($msg:expr) => (
        panic!( "[internal error] {}\n \
                 [internal error] Something has gone horribly wrong.\n \
                 [internal error] Please contact the Mnemosyne implementors.\n\
                 {},{}"
              , $msg
              , mnemosyne_version(), llvm_version()
              )
          );
    ($fmt:expr, $($arg:tt)+) => (
        panic!( "[internal error] {}\n \
                 [internal error] Something has gone horribly wrong.\n \
                 [internal error] Please contact the Mnemosyne implementors.\n\
                 {},{}"
              , format_args!($fmt, $($arg)+)
              , mnemosyne_version(), llvm_version()
              )
          )
}

pub mod position;
pub mod semantic;
pub mod compile;
pub mod forktable;
pub mod chars;
pub mod errors;

pub use semantic::ast;

use rustc::lib::llvm::{LLVMVersionMajor, LLVMVersionMinor};

use std::fmt::Debug;

const VERSION_MAJOR: u32 = 0;
const VERSION_MINOR: u32 = 1;

/// Returns the LLVM version as a String
pub fn llvm_version() -> String {
    unsafe { format!("LLVM v{}.{}", LLVMVersionMajor(), LLVMVersionMinor()) }
}

/// Returns the Mnemosyne version as a String
pub fn mnemosyne_version() -> String {
    format!("Mnemosyne v{}.{}", VERSION_MAJOR, VERSION_MINOR)
}
<|endoftext|>


<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.
 */

mod fetchable_query_generator;
mod node_query_generator;
mod query_query_generator;
mod refetchable_directive;
mod utils;
mod viewer_query_generator;

use crate::{
    connections::{extract_connection_metadata_from_directive, ConnectionConstants},
    relay_directive::{PLURAL_ARG_NAME, RELAY_DIRECTIVE_NAME},
    root_variables::{InferVariablesVisitor, VariableMap},
};

use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use errors::validate_map;
use fetchable_query_generator::FETCHABLE_QUERY_GENERATOR;
use graphql_ir::{
    Directive, FragmentDefinition, OperationDefinition, Program, Selection, ValidationMessage,
    VariableDefinition,
};
use graphql_syntax::OperationKind;
use intern::string_key::{StringKey, StringKeyMap, StringKeySet};
use node_query_generator::NODE_QUERY_GENERATOR;
use query_query_generator::QUERY_QUERY_GENERATOR;
use schema::{SDLSchema, Schema};
use std::{fmt::Write, sync::Arc};
use utils::*;
pub use utils::{RefetchableDerivedFromMetadata, RefetchableMetadata, CONSTANTS};
use viewer_query_generator::VIEWER_QUERY_GENERATOR;

use self::refetchable_directive::RefetchableDirective;
pub use self::refetchable_directive::REFETCHABLE_NAME;

/// This transform synthesizes "refetch" queries for fragments that
/// are trivially refetchable. This is comprised of three main stages:
///
/// 1. Validating that fragments marked with @refetchable qualify for
///    refetch query generation; mainly this means that the fragment
///    type is able to be refetched in some canonical way.
/// 2. Determining the variable definitions to use for each generated
///    query. GraphQL does not have a notion of fragment-local variables
///    at all, and although Relay adds this concept developers are still
///    allowed to reference global variables. This necessitates a
///    visiting all reachable fragments for each @refetchable fragment,
///    and finding the union of all global variables expceted to be defined.
/// 3. Building the refetch queries, a straightforward copying transform from
///    Fragment to Root IR nodes.
pub fn transform_refetchable_fragment(
    program: &Program,
    base_fragment_names: &'_ StringKeySet,
    for_typegen: bool,
) -> DiagnosticsResult<Program> {
    let mut next_program = Program::new(Arc::clone(&program.schema));
    let query_type = program.schema.query_type().unwrap();

    let mut transformer = RefetchableFragment::new(program, for_typegen);

    for operation in program.operations() {
        next_program.insert_operation(Arc::clone(operation));
    }

    validate_map(program.fragments(), |fragment| {
        let operation_result = transformer.transform_refetch_fragment(fragment)?;
        if let Some((refetchable_directive, operation_result)) = operation_result {
            next_program.insert_fragment(operation_result.fragment);
            if !base_fragment_names.contains(&fragment.name.item) {
                let mut directives = refetchable_directive.directives;
                directives.push(RefetchableDerivedFromMetadata(fragment.name.item).into());

                next_program.insert_operation(Arc::new(OperationDefinition {
                    kind: OperationKind::Query,
                    name: WithLocation::new(
                        fragment.name.location,
                        refetchable_directive.query_name.item,
                    ),
                    type_: query_type,
                    variable_definitions: operation_result.variable_definitions,
                    directives,
                    selections: operation_result.selections,
                }));
            }
        } else {
            next_program.insert_fragment(Arc::clone(fragment));
        }
        Ok(())
    })?;

    Ok(next_program)
}

type ExistingRefetchOperations = StringKeyMap<WithLocation<StringKey>>;

pub struct RefetchableFragment<'program> {
    connection_constants: ConnectionConstants,
    existing_refetch_operations: ExistingRefetchOperations,
    for_typegen: bool,
    program: &'program Program,
    visitor: InferVariablesVisitor<'program>,
}

impl<'program> RefetchableFragment<'program> {
    pub fn new(program: &'program Program, for_typegen: bool) -> Self {
        RefetchableFragment {
            connection_constants: Default::default(),
            existing_refetch_operations: Default::default(),
            for_typegen,
            program,
            visitor: InferVariablesVisitor::new(program),
        }
    }

    fn transform_refetch_fragment(
        &mut self,
        fragment: &Arc<FragmentDefinition>,
    ) -> DiagnosticsResult<Option<(RefetchableDirective, RefetchRoot)>> {
        fragment
            .directives
            .named(*REFETCHABLE_NAME)
            .map(|refetchable_directive| {
                self.transform_refetch_fragment_with_refetchable_directive(
                    fragment,
                    refetchable_directive,
                )
            })
            .transpose()
    }

    pub fn transform_refetch_fragment_with_refetchable_directive(
        &mut self,
        fragment: &Arc<FragmentDefinition>,
        directive: &Directive,
    ) -> DiagnosticsResult<(RefetchableDirective, RefetchRoot)> {
        let refetchable_directive =
            RefetchableDirective::from_directive(&self.program.schema, directive)?;
        self.validate_sibling_directives(fragment)?;
        self.validate_refetch_name(fragment, &refetchable_directive)?;

        let variables_map = self.visitor.infer_fragment_variables(fragment);
        for generator in GENERATORS.iter() {
            if let Some(refetch_root) = (generator.build_refetch_operation)(
                &self.program.schema,
                fragment,
                refetchable_directive.query_name.item,
                &variables_map,
            )? {
                if !self.for_typegen {
                    self.validate_connection_metadata(refetch_root.fragment.as_ref())?;
                }
                return Ok((refetchable_directive, refetch_root));
            }
        }
        let mut descriptions = String::new();
        for generator in GENERATORS.iter() {
            writeln!(descriptions, " - {}", generator.description).unwrap();
        }
        descriptions.pop();
        Err(vec![Diagnostic::error(
            ValidationMessage::UnsupportedRefetchableFragment {
                fragment_name: fragment.name.item,
                descriptions,
            },
            fragment.name.location,
        )])
    }

    fn validate_sibling_directives(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> DiagnosticsResult<()> {
        let relay_directive = fragment.directives.named(*RELAY_DIRECTIVE_NAME);
        let plural_directive = relay_directive
            .filter(|directive| directive.arguments.named(*PLURAL_ARG_NAME).is_some());
        if let Some(directive) = plural_directive {
            Err(vec![Diagnostic::error(
                ValidationMessage::InvalidRefetchableFragmentWithRelayPlural {
                    fragment_name: fragment.name.item,
                },
                directive.name.location,
            )])
        } else {
            Ok(())
        }
    }

    fn validate_refetch_name(
        &mut self,
        fragment: &FragmentDefinition,
        refetchable_directive: &RefetchableDirective,
    ) -> DiagnosticsResult<()> {
        // check for conflict with other @refetchable names
        if let Some(previous_fragment) = self
            .existing_refetch_operations
            .insert(refetchable_directive.query_name.item, fragment.name)
        {
            let (first_fragment, second_fragment) = if fragment.name.item > previous_fragment.item {
                (previous_fragment, fragment.name)
            } else {
                (fragment.name, previous_fragment)
            };
            return Err(vec![Diagnostic::error(
                ValidationMessage::DuplicateRefetchableOperation {
                    query_name: refetchable_directive.query_name.item,
                    first_fragment_name: first_fragment.item,
                    second_fragment_name: second_fragment.item,
                },
                first_fragment.location,
            )
            .annotate("also defined here", second_fragment.location)]);
        }

        // check for conflict with operations
        if let Some(existing_query) = self
            .program
            .operation(refetchable_directive.query_name.item)
        {
            return Err(vec![Diagnostic::error(
                ValidationMessage::RefetchableQueryConflictWithQuery {
                    query_name: refetchable_directive.query_name.item,
                },
                refetchable_directive.query_name.location,
            )
            .annotate(
                "an operation with that name is already defined here",
                existing_query.name.location,
            )]);
        }

        Ok(())
    }

    /// Validate that any @connection usage is valid for refetching:
    /// - Variables are used for both the "count" and "cursor" arguments
    ///   (after/first or before/last)
    /// - Exactly one connection
    /// - Has a stable path to the connection data
    ///
    /// Connection metadata is extracted in `transform_connection`
    fn validate_connection_metadata(&self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        if let Some(metadatas) = extract_connection_metadata_from_directive(&fragment.directives) {
            // TODO: path or connection field locations in the error messages
            if metadatas.len() > 1 {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RefetchableWithMultipleConnections {
                        fragment_name: fragment.name.item,
                    },
                    fragment.name.location,
                )]);
            } else if metadatas.len() == 1 {
                let metadata = &metadatas[0];
                if metadata.path.is_none() {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConnectionInPlural {
                            fragment_name: fragment.name.item,
                        },
                        fragment.name.location,
                    )]);
                }
                if (metadata.after.is_none() || metadata.first.is_none())
                    && metadata.direction != self.connection_constants.direction_backward
                {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConstConnectionArguments {
                            fragment_name: fragment.name.item,
                            arguments: "after and first",
                        },
                        fragment.name.location,
                    )]);
                } else if (metadata.before.is_none() || metadata.last.is_none())
                    && metadata.direction != self.connection_constants.direction_forward
                {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConstConnectionArguments {
                            fragment_name: fragment.name.item,
                            arguments: "before and last",
                        },
                        fragment.name.location,
                    )]);
                }
            }
        }
        Ok(())
    }
}

type BuildRefetchOperationFn = fn(
    schema: &SDLSchema,
    fragment: &Arc<FragmentDefinition>,
    query_name: StringKey,
    variables_map: &VariableMap,
) -> DiagnosticsResult<Option<RefetchRoot>>;
/// A strategy to generate queries for a given fragment. Multiple stategies
/// can be tried, such as generating a `node(id: ID)` query or a query directly
/// on the root query type.
pub struct QueryGenerator {
    /// Used to describe what fragments this QueryGenerator applies to, used in
    /// error messages.
    pub description: &'static str,

    /// Returns RefetchRoot or null if not applicable. Might throw a user error
    /// for an invalid schema or other problems.
    pub build_refetch_operation: BuildRefetchOperationFn,
}

const GENERATORS: [QueryGenerator; 4] = [
    VIEWER_QUERY_GENERATOR,
    QUERY_QUERY_GENERATOR,
    NODE_QUERY_GENERATOR,
    FETCHABLE_QUERY_GENERATOR,
];

pub struct RefetchRoot {
    pub fragment: Arc<FragmentDefinition>,
    pub selections: Vec<Selection>,
    pub variable_definitions: Vec<VariableDefinition>,
}
<commit_msg>Fix incremental mode bug about undefined operation varaible<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.
 */

mod fetchable_query_generator;
mod node_query_generator;
mod query_query_generator;
mod refetchable_directive;
mod utils;
mod viewer_query_generator;

use crate::{
    connections::{extract_connection_metadata_from_directive, ConnectionConstants},
    relay_directive::{PLURAL_ARG_NAME, RELAY_DIRECTIVE_NAME},
    root_variables::{InferVariablesVisitor, VariableMap},
};

use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use errors::validate_map;
use fetchable_query_generator::FETCHABLE_QUERY_GENERATOR;
use graphql_ir::{
    Directive, FragmentDefinition, OperationDefinition, Program, Selection, ValidationMessage,
    VariableDefinition,
};
use graphql_syntax::OperationKind;
use intern::string_key::{StringKey, StringKeyMap, StringKeySet};
use node_query_generator::NODE_QUERY_GENERATOR;
use query_query_generator::QUERY_QUERY_GENERATOR;
use schema::{SDLSchema, Schema};
use std::{fmt::Write, sync::Arc};
use utils::*;
pub use utils::{RefetchableDerivedFromMetadata, RefetchableMetadata, CONSTANTS};
use viewer_query_generator::VIEWER_QUERY_GENERATOR;

use self::refetchable_directive::RefetchableDirective;
pub use self::refetchable_directive::REFETCHABLE_NAME;

/// This transform synthesizes "refetch" queries for fragments that
/// are trivially refetchable. This is comprised of three main stages:
///
/// 1. Validating that fragments marked with @refetchable qualify for
///    refetch query generation; mainly this means that the fragment
///    type is able to be refetched in some canonical way.
/// 2. Determining the variable definitions to use for each generated
///    query. GraphQL does not have a notion of fragment-local variables
///    at all, and although Relay adds this concept developers are still
///    allowed to reference global variables. This necessitates a
///    visiting all reachable fragments for each @refetchable fragment,
///    and finding the union of all global variables expceted to be defined.
/// 3. Building the refetch queries, a straightforward copying transform from
///    Fragment to Root IR nodes.
pub fn transform_refetchable_fragment(
    program: &Program,
    base_fragment_names: &'_ StringKeySet,
    for_typegen: bool,
) -> DiagnosticsResult<Program> {
    let mut next_program = Program::new(Arc::clone(&program.schema));
    let query_type = program.schema.query_type().unwrap();

    let mut transformer = RefetchableFragment::new(program, for_typegen);

    for operation in program.operations() {
        next_program.insert_operation(Arc::clone(operation));
    }

    validate_map(program.fragments(), |fragment| {
        let operation_result = transformer.transform_refetch_fragment(fragment)?;
        if let Some((refetchable_directive, operation_result)) = operation_result {
            next_program.insert_fragment(operation_result.fragment);
            if !base_fragment_names.contains(&fragment.name.item) {
                let mut directives = refetchable_directive.directives;
                directives.push(RefetchableDerivedFromMetadata(fragment.name.item).into());

                next_program.insert_operation(Arc::new(OperationDefinition {
                    kind: OperationKind::Query,
                    name: WithLocation::new(
                        fragment.name.location,
                        refetchable_directive.query_name.item,
                    ),
                    type_: query_type,
                    variable_definitions: operation_result.variable_definitions,
                    directives,
                    selections: operation_result.selections,
                }));
            }
        } else {
            next_program.insert_fragment(Arc::clone(fragment));
        }
        Ok(())
    })?;

    Ok(next_program)
}

type ExistingRefetchOperations = StringKeyMap<WithLocation<StringKey>>;

pub struct RefetchableFragment<'program> {
    connection_constants: ConnectionConstants,
    existing_refetch_operations: ExistingRefetchOperations,
    for_typegen: bool,
    program: &'program Program,
}

impl<'program> RefetchableFragment<'program> {
    pub fn new(program: &'program Program, for_typegen: bool) -> Self {
        RefetchableFragment {
            connection_constants: Default::default(),
            existing_refetch_operations: Default::default(),
            for_typegen,
            program,
        }
    }

    fn transform_refetch_fragment(
        &mut self,
        fragment: &Arc<FragmentDefinition>,
    ) -> DiagnosticsResult<Option<(RefetchableDirective, RefetchRoot)>> {
        fragment
            .directives
            .named(*REFETCHABLE_NAME)
            .map(|refetchable_directive| {
                self.transform_refetch_fragment_with_refetchable_directive(
                    fragment,
                    refetchable_directive,
                )
            })
            .transpose()
    }

    pub fn transform_refetch_fragment_with_refetchable_directive(
        &mut self,
        fragment: &Arc<FragmentDefinition>,
        directive: &Directive,
    ) -> DiagnosticsResult<(RefetchableDirective, RefetchRoot)> {
        let refetchable_directive =
            RefetchableDirective::from_directive(&self.program.schema, directive)?;
        self.validate_sibling_directives(fragment)?;
        self.validate_refetch_name(fragment, &refetchable_directive)?;
        let variables_map =
            InferVariablesVisitor::new(self.program).infer_fragment_variables(fragment);

        for generator in GENERATORS.iter() {
            if let Some(refetch_root) = (generator.build_refetch_operation)(
                &self.program.schema,
                fragment,
                refetchable_directive.query_name.item,
                &variables_map,
            )? {
                if !self.for_typegen {
                    self.validate_connection_metadata(refetch_root.fragment.as_ref())?;
                }
                return Ok((refetchable_directive, refetch_root));
            }
        }
        let mut descriptions = String::new();
        for generator in GENERATORS.iter() {
            writeln!(descriptions, " - {}", generator.description).unwrap();
        }
        descriptions.pop();
        Err(vec![Diagnostic::error(
            ValidationMessage::UnsupportedRefetchableFragment {
                fragment_name: fragment.name.item,
                descriptions,
            },
            fragment.name.location,
        )])
    }

    fn validate_sibling_directives(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> DiagnosticsResult<()> {
        let relay_directive = fragment.directives.named(*RELAY_DIRECTIVE_NAME);
        let plural_directive = relay_directive
            .filter(|directive| directive.arguments.named(*PLURAL_ARG_NAME).is_some());
        if let Some(directive) = plural_directive {
            Err(vec![Diagnostic::error(
                ValidationMessage::InvalidRefetchableFragmentWithRelayPlural {
                    fragment_name: fragment.name.item,
                },
                directive.name.location,
            )])
        } else {
            Ok(())
        }
    }

    fn validate_refetch_name(
        &mut self,
        fragment: &FragmentDefinition,
        refetchable_directive: &RefetchableDirective,
    ) -> DiagnosticsResult<()> {
        // check for conflict with other @refetchable names
        if let Some(previous_fragment) = self
            .existing_refetch_operations
            .insert(refetchable_directive.query_name.item, fragment.name)
        {
            let (first_fragment, second_fragment) = if fragment.name.item > previous_fragment.item {
                (previous_fragment, fragment.name)
            } else {
                (fragment.name, previous_fragment)
            };
            return Err(vec![Diagnostic::error(
                ValidationMessage::DuplicateRefetchableOperation {
                    query_name: refetchable_directive.query_name.item,
                    first_fragment_name: first_fragment.item,
                    second_fragment_name: second_fragment.item,
                },
                first_fragment.location,
            )
            .annotate("also defined here", second_fragment.location)]);
        }

        // check for conflict with operations
        if let Some(existing_query) = self
            .program
            .operation(refetchable_directive.query_name.item)
        {
            return Err(vec![Diagnostic::error(
                ValidationMessage::RefetchableQueryConflictWithQuery {
                    query_name: refetchable_directive.query_name.item,
                },
                refetchable_directive.query_name.location,
            )
            .annotate(
                "an operation with that name is already defined here",
                existing_query.name.location,
            )]);
        }

        Ok(())
    }

    /// Validate that any @connection usage is valid for refetching:
    /// - Variables are used for both the "count" and "cursor" arguments
    ///   (after/first or before/last)
    /// - Exactly one connection
    /// - Has a stable path to the connection data
    ///
    /// Connection metadata is extracted in `transform_connection`
    fn validate_connection_metadata(&self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> {
        if let Some(metadatas) = extract_connection_metadata_from_directive(&fragment.directives) {
            // TODO: path or connection field locations in the error messages
            if metadatas.len() > 1 {
                return Err(vec![Diagnostic::error(
                    ValidationMessage::RefetchableWithMultipleConnections {
                        fragment_name: fragment.name.item,
                    },
                    fragment.name.location,
                )]);
            } else if metadatas.len() == 1 {
                let metadata = &metadatas[0];
                if metadata.path.is_none() {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConnectionInPlural {
                            fragment_name: fragment.name.item,
                        },
                        fragment.name.location,
                    )]);
                }
                if (metadata.after.is_none() || metadata.first.is_none())
                    && metadata.direction != self.connection_constants.direction_backward
                {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConstConnectionArguments {
                            fragment_name: fragment.name.item,
                            arguments: "after and first",
                        },
                        fragment.name.location,
                    )]);
                } else if (metadata.before.is_none() || metadata.last.is_none())
                    && metadata.direction != self.connection_constants.direction_forward
                {
                    return Err(vec![Diagnostic::error(
                        ValidationMessage::RefetchableWithConstConnectionArguments {
                            fragment_name: fragment.name.item,
                            arguments: "before and last",
                        },
                        fragment.name.location,
                    )]);
                }
            }
        }
        Ok(())
    }
}

type BuildRefetchOperationFn = fn(
    schema: &SDLSchema,
    fragment: &Arc<FragmentDefinition>,
    query_name: StringKey,
    variables_map: &VariableMap,
) -> DiagnosticsResult<Option<RefetchRoot>>;
/// A strategy to generate queries for a given fragment. Multiple stategies
/// can be tried, such as generating a `node(id: ID)` query or a query directly
/// on the root query type.
pub struct QueryGenerator {
    /// Used to describe what fragments this QueryGenerator applies to, used in
    /// error messages.
    pub description: &'static str,

    /// Returns RefetchRoot or null if not applicable. Might throw a user error
    /// for an invalid schema or other problems.
    pub build_refetch_operation: BuildRefetchOperationFn,
}

const GENERATORS: [QueryGenerator; 4] = [
    VIEWER_QUERY_GENERATOR,
    QUERY_QUERY_GENERATOR,
    NODE_QUERY_GENERATOR,
    FETCHABLE_QUERY_GENERATOR,
];

pub struct RefetchRoot {
    pub fragment: Arc<FragmentDefinition>,
    pub selections: Vec<Selection>,
    pub variable_definitions: Vec<VariableDefinition>,
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::result;
/// This is the `VirtioDevice` implementation for our vsock device. It handles the virtio-level
/// device logic: feature negociation, device configuration, and device activation.
///
/// We aim to conform to the VirtIO v1.1 spec:
/// https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html
///
/// The vsock device has two input parameters: a CID to identify the device, and a `VsockBackend`
/// to use for offloading vsock traffic.
///
/// Upon its activation, the vsock device registers handlers for the following events/FDs:
/// - an RX queue FD;
/// - a TX queue FD;
/// - an event queue FD; and
/// - a backend FD.
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use logger::{debug, error, warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
use vm_memory::GuestMemoryMmap;

use super::super::super::Error as DeviceError;
use super::super::{
    ActivateError, ActivateResult, DeviceState, Queue as VirtQueue, VirtioDevice, VsockError,
    VIRTIO_MMIO_INT_VRING,
};
use super::packet::VsockPacket;
use super::VsockBackend;
use super::{defs, defs::uapi};

pub(crate) const RXQ_INDEX: usize = 0;
pub(crate) const TXQ_INDEX: usize = 1;
pub(crate) const EVQ_INDEX: usize = 2;

/// The virtio features supported by our vsock device:
/// - VIRTIO_F_VERSION_1: the device conforms to at least version 1.0 of the VirtIO spec.
/// - VIRTIO_F_IN_ORDER: the device returns used buffers in the same order that the driver makes
///   them available.
pub(crate) const AVAIL_FEATURES: u64 =
    1 << uapi::VIRTIO_F_VERSION_1 as u64 | 1 << uapi::VIRTIO_F_IN_ORDER as u64;

pub struct Vsock<B> {
    cid: u64,
    pub(crate) queues: Vec<VirtQueue>,
    pub(crate) queue_events: Vec<EventFd>,
    pub(crate) backend: B,
    pub(crate) avail_features: u64,
    pub(crate) acked_features: u64,
    pub(crate) interrupt_status: Arc<AtomicUsize>,
    pub(crate) interrupt_evt: EventFd,
    // This EventFd is the only one initially registered for a vsock device, and is used to convert
    // a VirtioDevice::activate call into an EventHandler read event which allows the other events
    // (queue and backend related) to be registered post virtio device activation. That's
    // mostly something we wanted to happen for the backend events, to prevent (potentially)
    // continuous triggers from happening before the device gets activated.
    pub(crate) activate_evt: EventFd,
    pub(crate) device_state: DeviceState,
}

// TODO: Detect / handle queue deadlock:
// 1. If the driver halts RX queue processing, we'll need to notify `self.backend`, so that it
//    can unregister any EPOLLIN listeners, since otherwise it will keep spinning, unable to consume
//    its EPOLLIN events.

impl<B> Vsock<B>
where
    B: VsockBackend,
{
    pub(crate) fn with_queues(
        cid: u64,
        backend: B,
        queues: Vec<VirtQueue>,
    ) -> super::Result<Vsock<B>> {
        let mut queue_events = Vec::new();
        for _ in 0..queues.len() {
            queue_events.push(EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?);
        }

        Ok(Vsock {
            cid,
            queues,
            queue_events,
            backend,
            avail_features: AVAIL_FEATURES,
            acked_features: 0,
            interrupt_status: Arc::new(AtomicUsize::new(0)),
            interrupt_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?,
            activate_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?,
            device_state: DeviceState::Inactive,
        })
    }

    /// Create a new virtio-vsock device with the given VM CID and vsock backend.
    pub fn new(cid: u64, backend: B) -> super::Result<Vsock<B>> {
        let queues: Vec<VirtQueue> = defs::QUEUE_SIZES
            .iter()
            .map(|&max_size| VirtQueue::new(max_size))
            .collect();
        Self::with_queues(cid, backend, queues)
    }

    pub fn id(&self) -> &str {
        defs::VSOCK_DEV_ID
    }

    pub fn cid(&self) -> u64 {
        self.cid
    }

    pub fn backend(&self) -> &B {
        &self.backend
    }

    /// Signal the guest driver that we've used some virtio buffers that it had previously made
    /// available.
    pub fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
        debug!("vsock: raising IRQ");
        self.interrupt_status
            .fetch_or(VIRTIO_MMIO_INT_VRING as usize, Ordering::SeqCst);
        self.interrupt_evt.write(1).map_err(|e| {
            error!("Failed to signal used queue: {:?}", e);
            DeviceError::FailedSignalingUsedQueue(e)
        })
    }

    /// Walk the driver-provided RX queue buffers and attempt to fill them up with any data that we
    /// have pending. Return `true` if descriptors have been added to the used ring, and `false`
    /// otherwise.
    pub fn process_rx(&mut self) -> bool {
        debug!("vsock: process_rx()");
        let mem = match self.device_state {
            DeviceState::Activated(ref mem) => mem,
            // This should never happen, it's been already validated in the event handler.
            DeviceState::Inactive => unreachable!(),
        };

        let mut have_used = false;

        while let Some(head) = self.queues[RXQ_INDEX].pop(mem) {
            let used_len = match VsockPacket::from_rx_virtq_head(&head) {
                Ok(mut pkt) => {
                    if self.backend.recv_pkt(&mut pkt).is_ok() {
                        pkt.hdr().len() as u32 + pkt.len()
                    } else {
                        // We are using a consuming iterator over the virtio buffers, so, if we can't
                        // fill in this buffer, we'll need to undo the last iterator step.
                        self.queues[RXQ_INDEX].undo_pop();
                        break;
                    }
                }
                Err(e) => {
                    warn!("vsock: RX queue error: {:?}", e);
                    0
                }
            };

            have_used = true;
            self.queues[RXQ_INDEX]
                .add_used(mem, head.index, used_len)
                .unwrap_or_else(|e| {
                    error!("Failed to add available descriptor {}: {}", head.index, e)
                });
        }

        have_used
    }

    /// Walk the driver-provided TX queue buffers, package them up as vsock packets, and send them
    /// to the backend for processing. Return `true` if descriptors have been added to the used
    /// ring, and `false` otherwise.
    pub fn process_tx(&mut self) -> bool {
        debug!("vsock::process_tx()");
        let mem = match self.device_state {
            DeviceState::Activated(ref mem) => mem,
            // This should never happen, it's been already validated in the event handler.
            DeviceState::Inactive => unreachable!(),
        };

        let mut have_used = false;

        while let Some(head) = self.queues[TXQ_INDEX].pop(mem) {
            let pkt = match VsockPacket::from_tx_virtq_head(&head) {
                Ok(pkt) => pkt,
                Err(e) => {
                    error!("vsock: error reading TX packet: {:?}", e);
                    have_used = true;
                    self.queues[TXQ_INDEX]
                        .add_used(mem, head.index, 0)
                        .unwrap_or_else(|e| {
                            error!("Failed to add available descriptor {}: {}", head.index, e);
                        });
                    continue;
                }
            };

            if self.backend.send_pkt(&pkt).is_err() {
                self.queues[TXQ_INDEX].undo_pop();
                break;
            }

            have_used = true;
            self.queues[TXQ_INDEX]
                .add_used(mem, head.index, 0)
                .unwrap_or_else(|e| {
                    error!("Failed to add available descriptor {}: {}", head.index, e);
                });
        }

        have_used
    }
}

impl<B> VirtioDevice for Vsock<B>
where
    B: VsockBackend + 'static,
{
    fn avail_features(&self) -> u64 {
        self.avail_features
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn set_acked_features(&mut self, acked_features: u64) {
        self.acked_features = acked_features
    }

    fn device_type(&self) -> u32 {
        uapi::VIRTIO_ID_VSOCK
    }

    fn queues(&self) -> &[VirtQueue] {
        &self.queues
    }

    fn queues_mut(&mut self) -> &mut [VirtQueue] {
        &mut self.queues
    }

    fn queue_events(&self) -> &[EventFd] {
        &self.queue_events
    }

    fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }

    fn interrupt_status(&self) -> Arc<AtomicUsize> {
        self.interrupt_status.clone()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        match offset {
            0 if data.len() == 8 => byte_order::write_le_u64(data, self.cid()),
            0 if data.len() == 4 => {
                byte_order::write_le_u32(data, (self.cid() & 0xffff_ffff) as u32)
            }
            4 if data.len() == 4 => {
                byte_order::write_le_u32(data, ((self.cid() >> 32) & 0xffff_ffff) as u32)
            }
            _ => {
                METRICS.vsock.cfg_fails.inc();
                warn!(
                    "vsock: virtio-vsock received invalid read request of {} bytes at offset {}",
                    data.len(),
                    offset
                )
            }
        }
    }

    fn write_config(&mut self, offset: u64, data: &[u8]) {
        METRICS.vsock.cfg_fails.inc();
        warn!(
            "vsock: guest driver attempted to write device config (offset={:x}, len={:x})",
            offset,
            data.len()
        );
    }

    fn activate(&mut self, mem: GuestMemoryMmap) -> ActivateResult {
        if self.queues.len() != defs::NUM_QUEUES {
            METRICS.vsock.activate_fails.inc();
            error!(
                "Cannot perform activate. Expected {} queue(s), got {}",
                defs::NUM_QUEUES,
                self.queues.len()
            );
            return Err(ActivateError::BadActivate);
        }

        if self.activate_evt.write(1).is_err() {
            METRICS.vsock.activate_fails.inc();
            error!("Cannot write to activate_evt",);
            return Err(ActivateError::BadActivate);
        }

        self.device_state = DeviceState::Activated(mem);

        Ok(())
    }

    fn is_activated(&self) -> bool {
        match self.device_state {
            DeviceState::Inactive => false,
            DeviceState::Activated(_) => true,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::virtio::vsock::defs::uapi;
    use crate::virtio::vsock::test_utils::TestContext;

    #[test]
    fn test_virtio_device() {
        let mut ctx = TestContext::new();
        let device_features = AVAIL_FEATURES;
        let driver_features: u64 = AVAIL_FEATURES | 1 | (1 << 32);
        let device_pages = [
            (device_features & 0xffff_ffff) as u32,
            (device_features >> 32) as u32,
        ];
        let driver_pages = [
            (driver_features & 0xffff_ffff) as u32,
            (driver_features >> 32) as u32,
        ];
        assert_eq!(ctx.device.device_type(), uapi::VIRTIO_ID_VSOCK);
        assert_eq!(ctx.device.avail_features_by_page(0), device_pages[0]);
        assert_eq!(ctx.device.avail_features_by_page(1), device_pages[1]);
        assert_eq!(ctx.device.avail_features_by_page(2), 0);

        // Ack device features, page 0.
        ctx.device.ack_features_by_page(0, driver_pages[0]);
        // Ack device features, page 1.
        ctx.device.ack_features_by_page(1, driver_pages[1]);
        // Ack some bogus page (i.e. 2). This should have no side effect.
        ctx.device.ack_features_by_page(2, 0);
        // Attempt to un-ack the first feature page. This should have no side effect.
        ctx.device.ack_features_by_page(0, !driver_pages[0]);
        // Check that no side effect are present, and that the acked features are exactly the same
        // as the device features.
        assert_eq!(ctx.device.acked_features, device_features & driver_features);

        // Test reading 32-bit chunks.
        let mut data = [0u8; 8];
        ctx.device.read_config(0, &mut data[..4]);
        assert_eq!(
            u64::from(byte_order::read_le_u32(&data[..])),
            ctx.cid & 0xffff_ffff
        );
        ctx.device.read_config(4, &mut data[4..]);
        assert_eq!(
            u64::from(byte_order::read_le_u32(&data[4..])),
            (ctx.cid >> 32) & 0xffff_ffff
        );

        // Test reading 64-bit.
        let mut data = [0u8; 8];
        ctx.device.read_config(0, &mut data);
        assert_eq!(byte_order::read_le_u64(&data), ctx.cid);

        // Check that out-of-bounds reading doesn't mutate the destination buffer.
        let mut data = [0u8, 1, 2, 3, 4, 5, 6, 7];
        ctx.device.read_config(2, &mut data);
        assert_eq!(data, [0u8, 1, 2, 3, 4, 5, 6, 7]);

        // Just covering lines here, since the vsock device has no writable config.
        // A warning is, however, logged, if the guest driver attempts to write any config data.
        ctx.device.write_config(0, &data[..4]);

        // Test a bad activation.
        // let bad_activate = ctx.device.activate(
        //     ctx.mem.clone(),
        // );
        // match bad_activate {
        //     Err(ActivateError::BadActivate) => (),
        //     other => panic!("{:?}", other),
        // }

        // Test a correct activation.
        ctx.device.activate(ctx.mem.clone()).unwrap();
    }
}
<commit_msg>vsock: change visibility for function<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::result;
/// This is the `VirtioDevice` implementation for our vsock device. It handles the virtio-level
/// device logic: feature negociation, device configuration, and device activation.
///
/// We aim to conform to the VirtIO v1.1 spec:
/// https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html
///
/// The vsock device has two input parameters: a CID to identify the device, and a `VsockBackend`
/// to use for offloading vsock traffic.
///
/// Upon its activation, the vsock device registers handlers for the following events/FDs:
/// - an RX queue FD;
/// - a TX queue FD;
/// - an event queue FD; and
/// - a backend FD.
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use logger::{debug, error, warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
use vm_memory::GuestMemoryMmap;

use super::super::super::Error as DeviceError;
use super::super::{
    ActivateError, ActivateResult, DeviceState, Queue as VirtQueue, VirtioDevice, VsockError,
    VIRTIO_MMIO_INT_VRING,
};
use super::packet::VsockPacket;
use super::VsockBackend;
use super::{defs, defs::uapi};

pub(crate) const RXQ_INDEX: usize = 0;
pub(crate) const TXQ_INDEX: usize = 1;
pub(crate) const EVQ_INDEX: usize = 2;

/// The virtio features supported by our vsock device:
/// - VIRTIO_F_VERSION_1: the device conforms to at least version 1.0 of the VirtIO spec.
/// - VIRTIO_F_IN_ORDER: the device returns used buffers in the same order that the driver makes
///   them available.
pub(crate) const AVAIL_FEATURES: u64 =
    1 << uapi::VIRTIO_F_VERSION_1 as u64 | 1 << uapi::VIRTIO_F_IN_ORDER as u64;

pub struct Vsock<B> {
    cid: u64,
    pub(crate) queues: Vec<VirtQueue>,
    pub(crate) queue_events: Vec<EventFd>,
    pub(crate) backend: B,
    pub(crate) avail_features: u64,
    pub(crate) acked_features: u64,
    pub(crate) interrupt_status: Arc<AtomicUsize>,
    pub(crate) interrupt_evt: EventFd,
    // This EventFd is the only one initially registered for a vsock device, and is used to convert
    // a VirtioDevice::activate call into an EventHandler read event which allows the other events
    // (queue and backend related) to be registered post virtio device activation. That's
    // mostly something we wanted to happen for the backend events, to prevent (potentially)
    // continuous triggers from happening before the device gets activated.
    pub(crate) activate_evt: EventFd,
    pub(crate) device_state: DeviceState,
}

// TODO: Detect / handle queue deadlock:
// 1. If the driver halts RX queue processing, we'll need to notify `self.backend`, so that it
//    can unregister any EPOLLIN listeners, since otherwise it will keep spinning, unable to consume
//    its EPOLLIN events.

impl<B> Vsock<B>
where
    B: VsockBackend,
{
    pub fn with_queues(cid: u64, backend: B, queues: Vec<VirtQueue>) -> super::Result<Vsock<B>> {
        let mut queue_events = Vec::new();
        for _ in 0..queues.len() {
            queue_events.push(EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?);
        }

        Ok(Vsock {
            cid,
            queues,
            queue_events,
            backend,
            avail_features: AVAIL_FEATURES,
            acked_features: 0,
            interrupt_status: Arc::new(AtomicUsize::new(0)),
            interrupt_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?,
            activate_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?,
            device_state: DeviceState::Inactive,
        })
    }

    /// Create a new virtio-vsock device with the given VM CID and vsock backend.
    pub fn new(cid: u64, backend: B) -> super::Result<Vsock<B>> {
        let queues: Vec<VirtQueue> = defs::QUEUE_SIZES
            .iter()
            .map(|&max_size| VirtQueue::new(max_size))
            .collect();
        Self::with_queues(cid, backend, queues)
    }

    pub fn id(&self) -> &str {
        defs::VSOCK_DEV_ID
    }

    pub fn cid(&self) -> u64 {
        self.cid
    }

    pub fn backend(&self) -> &B {
        &self.backend
    }

    /// Signal the guest driver that we've used some virtio buffers that it had previously made
    /// available.
    pub fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
        debug!("vsock: raising IRQ");
        self.interrupt_status
            .fetch_or(VIRTIO_MMIO_INT_VRING as usize, Ordering::SeqCst);
        self.interrupt_evt.write(1).map_err(|e| {
            error!("Failed to signal used queue: {:?}", e);
            DeviceError::FailedSignalingUsedQueue(e)
        })
    }

    /// Walk the driver-provided RX queue buffers and attempt to fill them up with any data that we
    /// have pending. Return `true` if descriptors have been added to the used ring, and `false`
    /// otherwise.
    pub fn process_rx(&mut self) -> bool {
        debug!("vsock: process_rx()");
        let mem = match self.device_state {
            DeviceState::Activated(ref mem) => mem,
            // This should never happen, it's been already validated in the event handler.
            DeviceState::Inactive => unreachable!(),
        };

        let mut have_used = false;

        while let Some(head) = self.queues[RXQ_INDEX].pop(mem) {
            let used_len = match VsockPacket::from_rx_virtq_head(&head) {
                Ok(mut pkt) => {
                    if self.backend.recv_pkt(&mut pkt).is_ok() {
                        pkt.hdr().len() as u32 + pkt.len()
                    } else {
                        // We are using a consuming iterator over the virtio buffers, so, if we can't
                        // fill in this buffer, we'll need to undo the last iterator step.
                        self.queues[RXQ_INDEX].undo_pop();
                        break;
                    }
                }
                Err(e) => {
                    warn!("vsock: RX queue error: {:?}", e);
                    0
                }
            };

            have_used = true;
            self.queues[RXQ_INDEX]
                .add_used(mem, head.index, used_len)
                .unwrap_or_else(|e| {
                    error!("Failed to add available descriptor {}: {}", head.index, e)
                });
        }

        have_used
    }

    /// Walk the driver-provided TX queue buffers, package them up as vsock packets, and send them
    /// to the backend for processing. Return `true` if descriptors have been added to the used
    /// ring, and `false` otherwise.
    pub fn process_tx(&mut self) -> bool {
        debug!("vsock::process_tx()");
        let mem = match self.device_state {
            DeviceState::Activated(ref mem) => mem,
            // This should never happen, it's been already validated in the event handler.
            DeviceState::Inactive => unreachable!(),
        };

        let mut have_used = false;

        while let Some(head) = self.queues[TXQ_INDEX].pop(mem) {
            let pkt = match VsockPacket::from_tx_virtq_head(&head) {
                Ok(pkt) => pkt,
                Err(e) => {
                    error!("vsock: error reading TX packet: {:?}", e);
                    have_used = true;
                    self.queues[TXQ_INDEX]
                        .add_used(mem, head.index, 0)
                        .unwrap_or_else(|e| {
                            error!("Failed to add available descriptor {}: {}", head.index, e);
                        });
                    continue;
                }
            };

            if self.backend.send_pkt(&pkt).is_err() {
                self.queues[TXQ_INDEX].undo_pop();
                break;
            }

            have_used = true;
            self.queues[TXQ_INDEX]
                .add_used(mem, head.index, 0)
                .unwrap_or_else(|e| {
                    error!("Failed to add available descriptor {}: {}", head.index, e);
                });
        }

        have_used
    }
}

impl<B> VirtioDevice for Vsock<B>
where
    B: VsockBackend + 'static,
{
    fn avail_features(&self) -> u64 {
        self.avail_features
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn set_acked_features(&mut self, acked_features: u64) {
        self.acked_features = acked_features
    }

    fn device_type(&self) -> u32 {
        uapi::VIRTIO_ID_VSOCK
    }

    fn queues(&self) -> &[VirtQueue] {
        &self.queues
    }

    fn queues_mut(&mut self) -> &mut [VirtQueue] {
        &mut self.queues
    }

    fn queue_events(&self) -> &[EventFd] {
        &self.queue_events
    }

    fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }

    fn interrupt_status(&self) -> Arc<AtomicUsize> {
        self.interrupt_status.clone()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        match offset {
            0 if data.len() == 8 => byte_order::write_le_u64(data, self.cid()),
            0 if data.len() == 4 => {
                byte_order::write_le_u32(data, (self.cid() & 0xffff_ffff) as u32)
            }
            4 if data.len() == 4 => {
                byte_order::write_le_u32(data, ((self.cid() >> 32) & 0xffff_ffff) as u32)
            }
            _ => {
                METRICS.vsock.cfg_fails.inc();
                warn!(
                    "vsock: virtio-vsock received invalid read request of {} bytes at offset {}",
                    data.len(),
                    offset
                )
            }
        }
    }

    fn write_config(&mut self, offset: u64, data: &[u8]) {
        METRICS.vsock.cfg_fails.inc();
        warn!(
            "vsock: guest driver attempted to write device config (offset={:x}, len={:x})",
            offset,
            data.len()
        );
    }

    fn activate(&mut self, mem: GuestMemoryMmap) -> ActivateResult {
        if self.queues.len() != defs::NUM_QUEUES {
            METRICS.vsock.activate_fails.inc();
            error!(
                "Cannot perform activate. Expected {} queue(s), got {}",
                defs::NUM_QUEUES,
                self.queues.len()
            );
            return Err(ActivateError::BadActivate);
        }

        if self.activate_evt.write(1).is_err() {
            METRICS.vsock.activate_fails.inc();
            error!("Cannot write to activate_evt",);
            return Err(ActivateError::BadActivate);
        }

        self.device_state = DeviceState::Activated(mem);

        Ok(())
    }

    fn is_activated(&self) -> bool {
        match self.device_state {
            DeviceState::Inactive => false,
            DeviceState::Activated(_) => true,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::virtio::vsock::defs::uapi;
    use crate::virtio::vsock::test_utils::TestContext;

    #[test]
    fn test_virtio_device() {
        let mut ctx = TestContext::new();
        let device_features = AVAIL_FEATURES;
        let driver_features: u64 = AVAIL_FEATURES | 1 | (1 << 32);
        let device_pages = [
            (device_features & 0xffff_ffff) as u32,
            (device_features >> 32) as u32,
        ];
        let driver_pages = [
            (driver_features & 0xffff_ffff) as u32,
            (driver_features >> 32) as u32,
        ];
        assert_eq!(ctx.device.device_type(), uapi::VIRTIO_ID_VSOCK);
        assert_eq!(ctx.device.avail_features_by_page(0), device_pages[0]);
        assert_eq!(ctx.device.avail_features_by_page(1), device_pages[1]);
        assert_eq!(ctx.device.avail_features_by_page(2), 0);

        // Ack device features, page 0.
        ctx.device.ack_features_by_page(0, driver_pages[0]);
        // Ack device features, page 1.
        ctx.device.ack_features_by_page(1, driver_pages[1]);
        // Ack some bogus page (i.e. 2). This should have no side effect.
        ctx.device.ack_features_by_page(2, 0);
        // Attempt to un-ack the first feature page. This should have no side effect.
        ctx.device.ack_features_by_page(0, !driver_pages[0]);
        // Check that no side effect are present, and that the acked features are exactly the same
        // as the device features.
        assert_eq!(ctx.device.acked_features, device_features & driver_features);

        // Test reading 32-bit chunks.
        let mut data = [0u8; 8];
        ctx.device.read_config(0, &mut data[..4]);
        assert_eq!(
            u64::from(byte_order::read_le_u32(&data[..])),
            ctx.cid & 0xffff_ffff
        );
        ctx.device.read_config(4, &mut data[4..]);
        assert_eq!(
            u64::from(byte_order::read_le_u32(&data[4..])),
            (ctx.cid >> 32) & 0xffff_ffff
        );

        // Test reading 64-bit.
        let mut data = [0u8; 8];
        ctx.device.read_config(0, &mut data);
        assert_eq!(byte_order::read_le_u64(&data), ctx.cid);

        // Check that out-of-bounds reading doesn't mutate the destination buffer.
        let mut data = [0u8, 1, 2, 3, 4, 5, 6, 7];
        ctx.device.read_config(2, &mut data);
        assert_eq!(data, [0u8, 1, 2, 3, 4, 5, 6, 7]);

        // Just covering lines here, since the vsock device has no writable config.
        // A warning is, however, logged, if the guest driver attempts to write any config data.
        ctx.device.write_config(0, &data[..4]);

        // Test a bad activation.
        // let bad_activate = ctx.device.activate(
        //     ctx.mem.clone(),
        // );
        // match bad_activate {
        //     Err(ActivateError::BadActivate) => (),
        //     other => panic!("{:?}", other),
        // }

        // Test a correct activation.
        ctx.device.activate(ctx.mem.clone()).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::time::Duration;
use time;

/// Conversion factor for the flick time unit
pub const FLICKS_PER_SECOND: i64 = 705_600_000;

/// Flick time unit.
///
/// See https://github.com/OculusVR/Flicks
#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Flick(pub i64);

impl Flick {
    pub fn from_seconds(seconds: f64) -> Flick {
        Flick((seconds * FLICKS_PER_SECOND as f64) as i64)
    }

    pub fn from_nanoseconds(nanos: i64) -> Flick { Flick(nanos * 7056 / 10_000) }

    /// Return current time in Flicks since an unspecified epoch.
    pub fn now() -> Flick { Flick::from_nanoseconds(time::precise_time_ns() as i64) }
}

impl fmt::Display for Flick {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.3} s", self.0 as f32 / FLICKS_PER_SECOND as f32)
    }
}

impl From<Duration> for Flick {
    fn from(d: Duration) -> Flick {
        let nano = d.as_secs() as i64 * 1_000_000_000 + d.subsec_nanos() as i64;
        Flick::from_nanoseconds(nano)
    }
}

impl From<Flick> for Duration {
    fn from(f: Flick) -> Duration {
        let secs = (f.0 / FLICKS_PER_SECOND) as u64;
        let nanos = ((f.0 % FLICKS_PER_SECOND) * 1_000_000_000 / FLICKS_PER_SECOND) as u32;
        Duration::new(secs, nanos)
    }
}

impl<T: Into<Flick>> Add<T> for Flick {
    type Output = Flick;

    fn add(self, rhs: T) -> Flick {
        Flick(
            self.0
                .checked_add(rhs.into().0)
                .expect("overflow when adding flicks"),
        )
    }
}

impl<T: Into<Flick>> AddAssign<T> for Flick {
    fn add_assign(&mut self, rhs: T) { *self = *self + rhs.into(); }
}

impl<T: Into<Flick>> Sub<T> for Flick {
    type Output = Flick;

    fn sub(self, rhs: T) -> Flick {
        Flick(
            self.0
                .checked_sub(rhs.into().0)
                .expect("overflow when subtracting flicks"),
        )
    }
}

impl<T: Into<Flick>> SubAssign<T> for Flick {
    fn sub_assign(&mut self, rhs: T) { *self = *self - rhs.into(); }
}
<commit_msg>Fix overflow<commit_after>use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::time::Duration;
use time;

/// Conversion factor for the flick time unit
pub const FLICKS_PER_SECOND: i64 = 705_600_000;

/// Flick time unit.
///
/// See https://github.com/OculusVR/Flicks
#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Flick(pub i64);

impl Flick {
    pub fn from_seconds(seconds: f64) -> Flick {
        Flick((seconds * FLICKS_PER_SECOND as f64) as i64)
    }

    pub fn from_nanoseconds(nanos: i64) -> Flick { Flick((nanos as i128 * 7056 / 10_000) as i64) }

    /// Return current time in Flicks since an unspecified epoch.
    pub fn now() -> Flick { Flick::from_nanoseconds(time::precise_time_ns() as i64) }
}

impl fmt::Display for Flick {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.3} s", self.0 as f32 / FLICKS_PER_SECOND as f32)
    }
}

impl From<Duration> for Flick {
    fn from(d: Duration) -> Flick {
        let nano = d.as_secs() as i64 * 1_000_000_000 + d.subsec_nanos() as i64;
        Flick::from_nanoseconds(nano)
    }
}

impl From<Flick> for Duration {
    fn from(f: Flick) -> Duration {
        let secs = (f.0 / FLICKS_PER_SECOND) as u64;
        let nanos = ((f.0 % FLICKS_PER_SECOND) * 1_000_000_000 / FLICKS_PER_SECOND) as u32;
        Duration::new(secs, nanos)
    }
}

impl<T: Into<Flick>> Add<T> for Flick {
    type Output = Flick;

    fn add(self, rhs: T) -> Flick {
        Flick(
            self.0
                .checked_add(rhs.into().0)
                .expect("overflow when adding flicks"),
        )
    }
}

impl<T: Into<Flick>> AddAssign<T> for Flick {
    fn add_assign(&mut self, rhs: T) { *self = *self + rhs.into(); }
}

impl<T: Into<Flick>> Sub<T> for Flick {
    type Output = Flick;

    fn sub(self, rhs: T) -> Flick {
        Flick(
            self.0
                .checked_sub(rhs.into().0)
                .expect("overflow when subtracting flicks"),
        )
    }
}

impl<T: Into<Flick>> SubAssign<T> for Flick {
    fn sub_assign(&mut self, rhs: T) { *self = *self - rhs.into(); }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use std::raw::Repr;
use core::slice::SliceExt;
use num::traits::NumCast;
use num::complex::{Complex32, Complex64};
use vector::ops::{Copy, Axpy, Scal, Dot, Nrm2, Asum, Iamax};

pub mod ll;
pub mod ops;

pub trait Vector<T> {
    fn inc(&self) -> i32;
    fn len(&self) -> i32;
    unsafe fn as_ptr(&self) -> *const T;
    unsafe fn as_mut_ptr(&mut self) -> *mut T;
}

impl<'a, T> Into<Vec<T>> for &'a Vector<T>
    where T: Copy {

    fn into(self) -> Vec<T> {
        let n = self.len() as usize;

        let mut x = Vec::with_capacity(n);
        Copy::copy(self, &mut x);
        unsafe { x.set_len(n); }

        x
    }
}

pub trait VectorOperations<T>: Sized + Vector<T>
    where T: Copy + Axpy + Scal + Dot + Nrm2 + Asum + Iamax {

    #[inline]
    fn update(&mut self, alpha: &T, x: &Vector<T>) -> &mut Self {
        Axpy::axpy(alpha, x, self);
        self
    }

    #[inline]
    fn scale(&mut self, alpha: &T) -> &mut Self {
        Scal::scal(alpha, self);
        self
    }

    #[inline]
    fn dot(&self, x: &Vector<T>) -> T {
        Dot::dot(self, x)
    }

    #[inline]
    fn abs_sum(&self) -> T {
        Asum::asum(self)
    }

    #[inline]
    fn norm(&self) -> T {
        Nrm2::nrm2(self)
    }

    #[inline]
    fn max_index(&self) -> usize {
        Iamax::iamax(self)
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { 1i32 }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(Vec::len(self));
        match l {
            Some(l) => l,
            None => panic!(),
        }
    }

    #[inline]
    unsafe fn as_ptr(&self) -> *const T { self[..].as_ptr() }

    #[inline]
    unsafe fn as_mut_ptr(&mut self) -> *mut T { (&mut self[..]).as_mut_ptr() }
}

impl<'a, T> Vector<T> for &'a [T] {
    #[inline]
    fn inc(&self) -> i32 { 1i32 }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(SliceExt::len(*self));
        match l {
            Some(l) => l,
            None => panic!(),
        }
    }

    #[inline]
    unsafe fn as_ptr(&self) -> *const T { self.repr().data }

    #[inline]
    unsafe fn as_mut_ptr(&mut self) -> *mut T { self.repr().data as *mut T }
}

macro_rules! operations_impl(
    ($v: ident, $($t: ty), +) => (
        $( impl VectorOperations<$t> for $v<$t> {} )+
    )
);

operations_impl!(Vec, f32, f64, Complex32, Complex64);
impl<'a> VectorOperations<f32> for &'a [f32] {}
impl<'a> VectorOperations<f64> for &'a [f64] {}
impl<'a> VectorOperations<Complex32> for &'a [Complex32] {}
impl<'a> VectorOperations<Complex64> for &'a [Complex64] {}
<commit_msg>Make default increment 1<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use std::raw::Repr;
use core::slice::SliceExt;
use num::traits::NumCast;
use num::complex::{Complex32, Complex64};
use vector::ops::{Copy, Axpy, Scal, Dot, Nrm2, Asum, Iamax};

pub mod ll;
pub mod ops;

pub trait Vector<T> {
    fn inc(&self) -> i32 { 1 }
    fn len(&self) -> i32;
    unsafe fn as_ptr(&self) -> *const T;
    unsafe fn as_mut_ptr(&mut self) -> *mut T;
}

impl<'a, T> Into<Vec<T>> for &'a Vector<T>
    where T: Copy {

    fn into(self) -> Vec<T> {
        let n = self.len() as usize;

        let mut x = Vec::with_capacity(n);
        Copy::copy(self, &mut x);
        unsafe { x.set_len(n); }

        x
    }
}

pub trait VectorOperations<T>: Sized + Vector<T>
    where T: Copy + Axpy + Scal + Dot + Nrm2 + Asum + Iamax {

    #[inline]
    fn update(&mut self, alpha: &T, x: &Vector<T>) -> &mut Self {
        Axpy::axpy(alpha, x, self);
        self
    }

    #[inline]
    fn scale(&mut self, alpha: &T) -> &mut Self {
        Scal::scal(alpha, self);
        self
    }

    #[inline]
    fn dot(&self, x: &Vector<T>) -> T {
        Dot::dot(self, x)
    }

    #[inline]
    fn abs_sum(&self) -> T {
        Asum::asum(self)
    }

    #[inline]
    fn norm(&self) -> T {
        Nrm2::nrm2(self)
    }

    #[inline]
    fn max_index(&self) -> usize {
        Iamax::iamax(self)
    }
}

impl<T> Vector<T> for Vec<T> {

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(Vec::len(self));
        match l {
            Some(l) => l,
            None => panic!(),
        }
    }

    #[inline]
    unsafe fn as_ptr(&self) -> *const T { self[..].as_ptr() }

    #[inline]
    unsafe fn as_mut_ptr(&mut self) -> *mut T { (&mut self[..]).as_mut_ptr() }
}

impl<'a, T> Vector<T> for &'a [T] {

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(SliceExt::len(*self));
        match l {
            Some(l) => l,
            None => panic!(),
        }
    }

    #[inline]
    unsafe fn as_ptr(&self) -> *const T { self.repr().data }

    #[inline]
    unsafe fn as_mut_ptr(&mut self) -> *mut T { self.repr().data as *mut T }
}

macro_rules! operations_impl(
    ($v: ident, $($t: ty), +) => (
        $( impl VectorOperations<$t> for $v<$t> {} )+
    )
);

operations_impl!(Vec, f32, f64, Complex32, Complex64);
impl<'a> VectorOperations<f32> for &'a [f32] {}
impl<'a> VectorOperations<f64> for &'a [f64] {}
impl<'a> VectorOperations<Complex32> for &'a [Complex32] {}
impl<'a> VectorOperations<Complex64> for &'a [Complex64] {}
<|endoftext|>


<commit_before>fn env(name: &str) -> Option<std::ffi::OsString> {
    let target = std::env::var("TARGET").expect("Cargo didn't provide `TARGET` environment var");
    let target = target.to_uppercase().replace("-", "_");
    let prefixed_name = format!("{}_{}", target, name);
    println!("cargo:rerun-if-env-changed={}", prefixed_name);
    match std::env::var_os(prefixed_name) {
        Some(v) => Some(v),
        None => {
            println!("cargo:rerun-if-env-changed={}", name);
            std::env::var_os(name)
        }
    }
}

fn main() {
    if let Some(magic_dir) = env("MAGIC_DIR").map(std::path::PathBuf::from) {
        if !std::path::Path::new(&magic_dir).exists() {
            panic!("Magic library directory {:?} does not exist", magic_dir);
        }
        println!("cargo:rustc-link-search=native={}", magic_dir.to_string_lossy());

        let static_lib = magic_dir.join("libmagic.a");
        let shared_lib = magic_dir.join("libmagic.so");
        match env("MAGIC_STATIC").as_ref().and_then(|s| s.to_str()) {
            Some("false") | Some("FALSE") | Some("0") => {
                if !shared_lib.exists() {
                    panic!("No libmagic.so found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=dylib=magic");
            }
            Some(_) => {
                if !static_lib.exists() {
                    panic!("No libmagic.a found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=static=magic");
            }
            None => {
                match (static_lib.exists(), shared_lib.exists()) {
                    (false, false) => panic!("Neither libmagic.so, nor libmagic.a was found in {:?}", magic_dir),
                    (true, false) => println!("cargo:rustc-link-lib=static=magic"),
                    (false, true) => println!("cargo:rustc-link-lib=dylib=magic"),
                    (true, true) => panic!("Both a static and a shared library were found in {:?}\nspecify a choice with `MAGIC_STATIC=true|false`", magic_dir),
                }
            }
        }
    } else {
        if let Err(err) = vcpkg::find_package("libmagic") {
            println!("Could not find vcpkg package: {}", err);
        }

        println!("cargo:rustc-link-lib=dylib=magic");
    }
}
<commit_msg>Apply `cargo +stable fmt`<commit_after>fn env(name: &str) -> Option<std::ffi::OsString> {
    let target = std::env::var("TARGET").expect("Cargo didn't provide `TARGET` environment var");
    let target = target.to_uppercase().replace("-", "_");
    let prefixed_name = format!("{}_{}", target, name);
    println!("cargo:rerun-if-env-changed={}", prefixed_name);
    match std::env::var_os(prefixed_name) {
        Some(v) => Some(v),
        None => {
            println!("cargo:rerun-if-env-changed={}", name);
            std::env::var_os(name)
        }
    }
}

fn main() {
    if let Some(magic_dir) = env("MAGIC_DIR").map(std::path::PathBuf::from) {
        if !std::path::Path::new(&magic_dir).exists() {
            panic!("Magic library directory {:?} does not exist", magic_dir);
        }
        println!(
            "cargo:rustc-link-search=native={}",
            magic_dir.to_string_lossy()
        );

        let static_lib = magic_dir.join("libmagic.a");
        let shared_lib = magic_dir.join("libmagic.so");
        match env("MAGIC_STATIC").as_ref().and_then(|s| s.to_str()) {
            Some("false") | Some("FALSE") | Some("0") => {
                if !shared_lib.exists() {
                    panic!("No libmagic.so found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=dylib=magic");
            }
            Some(_) => {
                if !static_lib.exists() {
                    panic!("No libmagic.a found in {:?}", magic_dir);
                }
                println!("cargo:rustc-link-lib=static=magic");
            }
            None => {
                match (static_lib.exists(), shared_lib.exists()) {
                    (false, false) => panic!("Neither libmagic.so, nor libmagic.a was found in {:?}", magic_dir),
                    (true, false) => println!("cargo:rustc-link-lib=static=magic"),
                    (false, true) => println!("cargo:rustc-link-lib=dylib=magic"),
                    (true, true) => panic!("Both a static and a shared library were found in {:?}\nspecify a choice with `MAGIC_STATIC=true|false`", magic_dir),
                }
            }
        }
    } else {
        if let Err(err) = vcpkg::find_package("libmagic") {
            println!("Could not find vcpkg package: {}", err);
        }

        println!("cargo:rustc-link-lib=dylib=magic");
    }
}
<|endoftext|>


<commit_before>extern crate capnpc;

fn main() {
    let prefix = Path::new("schema");

    ::capnpc::compile(prefix.clone(),
                      vec!(Path::new("schema/grain.capnp"),
                           Path::new("schema/util.capnp"),
                           Path::new("schema/web-session.capnp")).as_slice());
}
<commit_msg>slice notation<commit_after>extern crate capnpc;

fn main() {
    let prefix = Path::new("schema");

    ::capnpc::compile(prefix.clone(),
                      &[Path::new("schema/grain.capnp"),
                        Path::new("schema/util.capnp"),
                        Path::new("schema/web-session.capnp")]);
}
<|endoftext|>


<commit_before>extern crate autocfg;

use std::env;

fn main() {
    let ac = autocfg::new();
    if ac.probe_type("i128") {
        println!("cargo:rustc-cfg=has_i128");
    } else if env::var_os("CARGO_FEATURE_I128").is_some() {
        panic!("i128 support was not detected!");
    }

    autocfg::rerun_path(file!());
}
<commit_msg>Compatible with cargo --remap-path-prefix<commit_after>extern crate autocfg;

use std::env;

fn main() {
    let ac = autocfg::new();
    if ac.probe_type("i128") {
        println!("cargo:rustc-cfg=has_i128");
    } else if env::var_os("CARGO_FEATURE_I128").is_some() {
        panic!("i128 support was not detected!");
    }

    autocfg::rerun_path("build.rs");
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.minor < 36 {
        println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
    }

    if !compiler.nightly {
        println!("cargo:rustc-cfg=syn_disable_nightly_tests");
    }
}

struct Compiler {
    minor: u32,
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    let minor = match u32::from_str(next) {
        Ok(minor) => minor,
        Err(_) => return None,
    };

    Some(Compiler {
        minor: minor,
        nightly: version.contains("nightly"),
    })
}
<commit_msg>Resolve redundant_field_names lint in build.rs<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.minor < 36 {
        println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
    }

    if !compiler.nightly {
        println!("cargo:rustc-cfg=syn_disable_nightly_tests");
    }
}

struct Compiler {
    minor: u32,
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    let minor = match u32::from_str(next) {
        Ok(minor) => minor,
        Err(_) => return None,
    };

    Some(Compiler {
        minor,
        nightly: version.contains("nightly"),
    })
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=dylib=gdi32");
    println!("cargo:rustc-link-lib=dylib=comdlg32");
    println!("cargo:rustc-link-lib=dylib=user32");

    gcc::Config::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("PDC_WIDE", Some("Y")) // Build with wide-character (Unicode) support
        .define("PDC_FORCE_UTF8", Some("Y")) // Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .define("PDC_RGB", Some("Y")) // Use RGB colors, it's what most people expect them to be
        .compile("libpdcurses.a");
}
<commit_msg>gcc::Config has been renamed to gcc::Build<commit_after>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=dylib=gdi32");
    println!("cargo:rustc-link-lib=dylib=comdlg32");
    println!("cargo:rustc-link-lib=dylib=user32");

    gcc::Build::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("PDC_WIDE", Some("Y")) // Build with wide-character (Unicode) support
        .define("PDC_FORCE_UTF8", Some("Y")) // Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .define("PDC_RGB", Some("Y")) // Use RGB colors, it's what most people expect them to be
        .compile("libpdcurses.a");
}
<|endoftext|>


<commit_before>// Copyright 2019 The Exonum Team
//
// 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.

use crate::db::Database;
use crate::views::IndexType;
use crate::{
    views::IndexAddress, BinaryValue, IndexAccess, IndexBuilder, ListIndex, Snapshot, TemporaryDB,
};
use std::ops::{Deref, DerefMut};

trait ObjectAccess<V: BinaryValue>: IndexAccess {
    fn create_list<I: Into<IndexAddress>>(&self, address: I) -> ListIndex<Self, V>;

    fn get_object<K: ObjectGetter<K, Self, V>>(&self, address: IndexAddress) -> Ref<K>;
}

#[derive(Debug)]
struct Ref<T> {
    view: T,
}

trait ObjectGetter<K, T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get<I:Into<IndexAddress>>(index_access: T, address: I) -> K;
}

impl<T, V> ObjectGetter<Self, T, V> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get<I:Into<IndexAddress>>(index_access: T, address: I) -> Self {
        ListIndex::new("index", index_access)
    }
}

#[derive(Debug)]
struct RefMut<T> {
    view_mut: T,
}

impl<T> Deref for Ref<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.view
    }
}

impl<T> Deref for RefMut<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.view_mut
    }
}

impl<T> DerefMut for RefMut<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.view_mut
    }
}

impl<'a, V: BinaryValue> ObjectAccess<V> for &'a Box<dyn Snapshot> {
    fn create_list<I: Into<IndexAddress>>(&self, address: I) -> ListIndex<Self, V> {
        let address = address.into();

        ListIndex::new(address.name, *self)
    }

    fn get_object<K: ObjectGetter<K, Self, V>>(&self, address: IndexAddress) -> Ref<K> {
        Ref {
            view: K::get(*self, address),
        }
    }
}

#[test]
fn get_reference_from_snapshot() {
    let db = TemporaryDB::new();

    let snapshot = &db.snapshot();

    {
        let address = IndexAddress::new().append_name("index");

        let list_index: Ref<ListIndex<_, u32>> = snapshot.get_object(address);

        assert_eq!(list_index.get(1), None);
    }
}
<commit_msg>Apply fmt.<commit_after>// Copyright 2019 The Exonum Team
//
// 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.

use crate::db::Database;
use crate::views::IndexType;
use crate::{
    views::IndexAddress, BinaryValue, IndexAccess, IndexBuilder, ListIndex, Snapshot, TemporaryDB,
};
use std::ops::{Deref, DerefMut};

trait ObjectAccess<V: BinaryValue>: IndexAccess {

    fn create_list<I: Into<IndexAddress>>(&self, address: I) -> ListIndex<Self, V>;

    fn get_object<K: ObjectGetter<K, Self, V>>(&self, address: IndexAddress) -> Ref<K>;
}

#[derive(Debug)]
struct Ref<T> {
    view: T,
}

trait ObjectGetter<K, T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get<I: Into<IndexAddress>>(index_access: T, address: I) -> K;
}

impl<T, V> ObjectGetter<Self, T, V> for ListIndex<T, V>
where
    T: IndexAccess,
    V: BinaryValue,
{
    fn get<I: Into<IndexAddress>>(index_access: T, address: I) -> Self {
        ListIndex::new("index", index_access)
    }
}

#[derive(Debug)]
struct RefMut<T> {
    view_mut: T,
}

impl<T> Deref for Ref<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.view
    }
}

impl<T> Deref for RefMut<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.view_mut
    }
}

impl<T> DerefMut for RefMut<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.view_mut
    }
}

impl<'a, V: BinaryValue> ObjectAccess<V> for &'a Box<dyn Snapshot> {

    fn create_list<I: Into<IndexAddress>>(&self, address: I) -> ListIndex<Self, V> {
        let address = address.into();
        ListIndex::new(address.name, *self)
    }

    fn get_object<K: ObjectGetter<K, Self, V>>(&self, address: IndexAddress) -> Ref<K> {
        Ref {
            view: K::get(*self, address),
        }
    }
}

#[test]
fn get_reference_from_snapshot() {
    let db = TemporaryDB::new();

    let snapshot = &db.snapshot();

    {
        let address = IndexAddress::new().append_name("index");

        let list_index: Ref<ListIndex<_, u32>> = snapshot.get_object(address);

        assert_eq!(list_index.get(1), None);
    }
}
<|endoftext|>


<commit_before>use std::rand::random;

fn main() {
    let random_value = random::<u8>() % 10u8;
    let mut guess = 0u8;

    println!("{}", random_value);

}
<commit_msg>Add function to check for equality<commit_after>use std::io;
use std::rand::random;

fn guessed_correctly(guess: uint, machine: uint) -> bool {
    if guess == machine {
        return true;
    }
    return false;
}

fn main() {
    let random_value = random::<uint>() % 10u;
    let mut guess = 0u;
    println!("{}", random_value);
    println!("{}", guessed_correctly(guess, random_value));

}
<|endoftext|>


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

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

<%helpers:shorthand name="columns" sub_properties="column-count column-width" experimental="True"
                    extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns">
    use properties::longhands::{column_count, column_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {

        let mut column_count = None;
        let mut column_width = None;
        let mut autos = 0;

        loop {
            if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                // Leave the options to None, 'auto' is the initial value.
                autos += 1;
                continue
            }

            if column_count.is_none() {
                if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
                    column_count = Some(value);
                    continue
                }
            }

            if column_width.is_none() {
                if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
                    column_width = Some(value);
                    continue
                }
            }

            break
        }

        let values = autos + column_count.iter().len() + column_width.iter().len();
        if values == 0 || values > 2 {
            Err(())
        } else {
            Ok(Longhands {
                column_count: column_count,
                column_width: column_width,
            })
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.column_width.to_css(dest));
            try!(write!(dest, " "));

            self.column_count.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="column-rule" products="gecko" extra_prefixes="moz"
    sub_properties="column-rule-width column-rule-style column-rule-color"
    spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
    use properties::longhands::{column_rule_width, column_rule_style};
    use properties::longhands::column_rule_color;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "width style color".split():
        let mut column_rule_${name} = None;
        % endfor
        let mut any = false;

        loop {
            % for name in "width style color".split():
            if column_rule_${name}.is_none() {
                if let Ok(value) = input.try(|input|
                        column_rule_${name}::parse(context, input)) {
                    column_rule_${name} = Some(value);
                    any = true;
                    continue
                }
            }
            % endfor

            break
        }
        if any {
            Ok(Longhands {
                % for name in "width style".split():
                    column_rule_${name}: column_rule_${name}
                        .or(Some(column_rule_${name}::get_initial_specified_value())),
                % endfor
                column_rule_color: column_rule_color,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut need_space = false;
            try!(self.column_rule_width.to_css(dest));

            if let DeclaredValue::Value(ref width) = *self.column_rule_width {
                try!(width.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref style) = *self.column_rule_style {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(style.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref color) = *self.column_rule_color {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>
<commit_msg>Correct serialization of column-rule shorthand<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

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

<%helpers:shorthand name="columns" sub_properties="column-count column-width" experimental="True"
                    extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns">
    use properties::longhands::{column_count, column_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {

        let mut column_count = None;
        let mut column_width = None;
        let mut autos = 0;

        loop {
            if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                // Leave the options to None, 'auto' is the initial value.
                autos += 1;
                continue
            }

            if column_count.is_none() {
                if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
                    column_count = Some(value);
                    continue
                }
            }

            if column_width.is_none() {
                if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
                    column_width = Some(value);
                    continue
                }
            }

            break
        }

        let values = autos + column_count.iter().len() + column_width.iter().len();
        if values == 0 || values > 2 {
            Err(())
        } else {
            Ok(Longhands {
                column_count: column_count,
                column_width: column_width,
            })
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.column_width.to_css(dest));
            try!(write!(dest, " "));

            self.column_count.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="column-rule" products="gecko" extra_prefixes="moz"
    sub_properties="column-rule-width column-rule-style column-rule-color"
    spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule">
    use properties::longhands::{column_rule_width, column_rule_style};
    use properties::longhands::column_rule_color;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "width style color".split():
        let mut column_rule_${name} = None;
        % endfor
        let mut any = false;

        loop {
            % for name in "width style color".split():
            if column_rule_${name}.is_none() {
                if let Ok(value) = input.try(|input|
                        column_rule_${name}::parse(context, input)) {
                    column_rule_${name} = Some(value);
                    any = true;
                    continue
                }
            }
            % endfor

            break
        }
        if any {
            Ok(Longhands {
                % for name in "width style".split():
                    column_rule_${name}: column_rule_${name}
                        .or(Some(column_rule_${name}::get_initial_specified_value())),
                % endfor
                column_rule_color: column_rule_color,
            })
        } else {
            Err(())
        }
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut need_space = false;

            if let DeclaredValue::Value(ref width) = *self.column_rule_width {
                try!(width.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref style) = *self.column_rule_style {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(style.to_css(dest));
                need_space = true;
            }

            if let DeclaredValue::Value(ref color) = *self.column_rule_color {
                if need_space {
                    try!(write!(dest, " "));
                }
                try!(color.to_css(dest));
            }
            Ok(())
        }
    }
</%helpers:shorthand>
<|endoftext|>