<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The reference loader implementation for the `gltf` crate.
//!
//! # Examples
//!
//! ### Importing some `glTF` 2.0
//!
//! ```rust
//! use gltf_importer::import;
//! # #[allow(unused_variables)]
//! let path = "path/to/asset.gltf";
//! # let path = "../examples/Box.gltf";
//! match import(path) {
//!     Ok((gltf, _)) => println!("{:#?}", gltf.as_json()),
//!     Err(err) => println!("error: {:?}", err),
//! }
//! ```

extern crate base64;
extern crate gltf;
extern crate gltf_utils;

use gltf::json::{self, validation};
use std::{fmt, fs, io};

use gltf::Gltf;
use gltf_utils::Source;
use std::error::Error as StdError;
use std::path::Path;

/// Contains parameters for import configuration.
pub mod config;

pub use self::config::Config;
pub use self::config::ValidationStrategy;

/// Error encountered when importing a glTF 2.0 asset.
#[derive(Debug)]
pub enum Error {
    /// A loaded glTF buffer is not of the required length.
    BufferLength(json::Path),

    /// Base 64 decoding error.
    Base64Decoding(base64::DecodeError),

    /// A glTF extension required by the asset has not been enabled by the user.
    ExtensionDisabled(String),

    /// A glTF extension required by the asset is not supported by the library.
    ExtensionUnsupported(String),

    /// The glTF version of the asset is incompatible with the importer.
    IncompatibleVersion(String),

    /// Standard I/O error.
    Io(std::io::Error),

    /// `gltf` crate error.
    Gltf(gltf::Error),

    /// Failure when deserializing .gltf or .glb JSON.
    MalformedJson(json::Error),

    /// The .gltf data is invalid.
    Validation(Vec<(json::Path, validation::Error)>),
}

/// Buffer data returned from `import`.
#[derive(Clone, Debug)]
pub struct Buffers(Vec<Vec<u8>>);

impl Source for Buffers {
    fn source_buffer(&self, buffer: &gltf::Buffer) -> &[u8] {
        &self.0[buffer.index()]
    }
}

impl Buffers {
    /// Obtain the contents of a loaded buffer.
    pub fn buffer(&self, buffer: &gltf::Buffer) -> Option<&[u8]> {
        self.0.get(buffer.index()).map(Vec::as_slice)
    }

    /// Obtain the contents of a loaded buffer view.
    pub fn view(&self, view: &gltf::buffer::View) -> Option<&[u8]> {
        self.buffer(&view.buffer())
            .map(|data| {
                let begin = view.offset();
                let end = begin + view.length();
                &data[begin..end]
            })
    }

    /// Take the loaded buffer data.
    pub fn take(self) -> Vec<Vec<u8>> {
        self.0
    }
}

fn import_impl(path: &Path, config: &Config) -> Result<(Gltf, Buffers), Error> {
    let data = read_to_end(path)?;
    if data.starts_with(b"glTF") {
        import_binary(&data, config, path)
    } else {
        import_standard(&data, config, path)
    }
}

/// Imports glTF 2.0 with custom configuration.
pub fn import_with_config<P>(path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), config)
}

/// Imports glTF 2.0 with default configuration.
pub fn import<P>(path: P) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), &Default::default())
}

fn read_to_end_impl(path: &Path) -> Result<Vec<u8>, Error> {
    use io::Read;
    let file = fs::File::open(path)?;
    let mut reader = io::BufReader::new(file);
    let mut buffer = vec![];
    let _ = reader.read_to_end(&mut buffer)?;
    Ok(buffer)
}

fn read_to_end<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    read_to_end_impl(path.as_ref())
}

fn parse_data_uri(uri: &str) -> Result<Vec<u8>, Error> {
    let encoded = uri.split(',').nth(1).unwrap();
    let decoded = base64::decode(&encoded)?;
    Ok(decoded)
}

fn load_external_buffers(
    base_path: &Path,
    gltf: &Gltf,
    mut bin: Option<Vec<u8>>,
) -> Result<Vec<Vec<u8>>, Error> {
    let mut buffers = vec![];
    for (index, buffer) in gltf.buffers().enumerate() {
        let uri = buffer.uri();
        let data = if uri == "#bin" {
            Ok(bin.take().unwrap())
        } else if uri.starts_with("data:") {
            Ok(parse_data_uri(uri)?)
        } else {
            let path = base_path.parent().unwrap_or_else(|| Path::new("./")).join(uri);
            read_to_end(&path)
        }?;
        if data.len() < buffer.length() {
            let path = json::Path::new().field("buffers").index(index);
            return Err(Error::BufferLength(path));
        }
        buffers.push(data);
    }
    Ok(buffers)
}

fn validate_standard(
    unvalidated: gltf::Unvalidated,
    config: &Config,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    Ok(match config.validation_strategy {
        ValidationStrategy::Skip => unvalidated.skip_validation(),
        ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
        ValidationStrategy::Complete => unvalidated.validate_completely()?,
    })
}

fn validate_binary(
    unvalidated: gltf::Unvalidated,
    config: &Config,
    has_bin: bool,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    use json::validation::Error as Reason;

    if config.validation_strategy == ValidationStrategy::Skip {
        return Ok(unvalidated.skip_validation());
    }

    let mut errs = vec![];
    {
        let json = unvalidated.as_json();
        for (index, buffer) in json.buffers.iter().enumerate() {
            let path = || {
                json::Path::new()
                    .field("buffers")
                    .index(index)
                    .field("uri")
            };
            match index {
                0 if has_bin => if buffer.uri.is_some() {
                    errs.push((path(), Reason::Missing));
                },
                _ if buffer.uri.is_none() => {
                    errs.push((path(), Reason::Missing));
                },
                _ => {},
            }
        }
    }

    if errs.is_empty() {
        Ok(match config.validation_strategy {
            ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
            ValidationStrategy::Complete => unvalidated.validate_completely()?,
            ValidationStrategy::Skip => unreachable!(),
        })
    } else {
        Err(Error::Validation(errs))
    }
}

fn import_standard<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let unvalidated = Gltf::from_slice(data)?;
    let gltf = validate_standard(unvalidated, config)?;
    let bin = None;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

fn import_binary<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let gltf::Glb { json, bin, .. } = gltf::Glb::from_slice(data)?;
    let unvalidated = Gltf::from_slice(json)?;
    let bin = bin.map(|x| x.to_vec());
    let gltf = validate_binary(unvalidated, config, bin.is_some())?;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        Error::MalformedJson(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Vec<(json::Path, validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, validation::Error)>) -> Error {
        Error::Validation(errs)
    }
}

impl From<gltf::Error> for Error {
    fn from(err: gltf::Error) -> Error {
        match err {
            gltf::Error::Validation(errs) => Error::Validation(errs),
            _ => Error::Gltf(err),
        }
    }
}

impl From<base64::DecodeError> for Error {
    fn from(err: base64::DecodeError) -> Error {
        Error::Base64Decoding(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Base64Decoding(_) => "Base 64 decoding failed",
            BufferLength(_) => "Loaded buffer does not match required length",
            ExtensionDisabled(_) => "Asset requires a disabled extension",
            ExtensionUnsupported(_) => "Assets requires an unsupported extension",
            IncompatibleVersion(_) => "Asset is not glTF version 2.0",
            Io(_) => "I/O error",
            Gltf(_) => "Error from gltf crate",
            MalformedJson(_) => "Malformed .gltf / .glb JSON",
            Validation(_) => "Asset failed validation tests",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match *self {
            MalformedJson(ref err) => Some(err),
            Io(ref err) => Some(err),
            _ => None,
        }
    }
}
<commit_msg>Add importing from a data slice to the public importer API<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The reference loader implementation for the `gltf` crate.
//!
//! # Examples
//!
//! ### Importing some `glTF` 2.0
//!
//! ```rust
//! use gltf_importer::import;
//! # #[allow(unused_variables)]
//! let path = "path/to/asset.gltf";
//! # let path = "../examples/Box.gltf";
//! match import(path) {
//!     Ok((gltf, _)) => println!("{:#?}", gltf.as_json()),
//!     Err(err) => println!("error: {:?}", err),
//! }
//! ```

extern crate base64;
extern crate gltf;
extern crate gltf_utils;

use gltf::json::{self, validation};
use std::{fmt, fs, io};

use gltf::Gltf;
use gltf_utils::Source;
use std::error::Error as StdError;
use std::path::Path;

/// Contains parameters for import configuration.
pub mod config;

pub use self::config::Config;
pub use self::config::ValidationStrategy;

/// Error encountered when importing a glTF 2.0 asset.
#[derive(Debug)]
pub enum Error {
    /// A loaded glTF buffer is not of the required length.
    BufferLength(json::Path),

    /// Base 64 decoding error.
    Base64Decoding(base64::DecodeError),

    /// A glTF extension required by the asset has not been enabled by the user.
    ExtensionDisabled(String),

    /// A glTF extension required by the asset is not supported by the library.
    ExtensionUnsupported(String),

    /// The glTF version of the asset is incompatible with the importer.
    IncompatibleVersion(String),

    /// Standard I/O error.
    Io(std::io::Error),

    /// `gltf` crate error.
    Gltf(gltf::Error),

    /// Failure when deserializing .gltf or .glb JSON.
    MalformedJson(json::Error),

    /// The .gltf data is invalid.
    Validation(Vec<(json::Path, validation::Error)>),
}

/// Buffer data returned from `import`.
#[derive(Clone, Debug)]
pub struct Buffers(Vec<Vec<u8>>);

impl Source for Buffers {
    fn source_buffer(&self, buffer: &gltf::Buffer) -> &[u8] {
        &self.0[buffer.index()]
    }
}

impl Buffers {
    /// Obtain the contents of a loaded buffer.
    pub fn buffer(&self, buffer: &gltf::Buffer) -> Option<&[u8]> {
        self.0.get(buffer.index()).map(Vec::as_slice)
    }

    /// Obtain the contents of a loaded buffer view.
    pub fn view(&self, view: &gltf::buffer::View) -> Option<&[u8]> {
        self.buffer(&view.buffer())
            .map(|data| {
                let begin = view.offset();
                let end = begin + view.length();
                &data[begin..end]
            })
    }

    /// Take the loaded buffer data.
    pub fn take(self) -> Vec<Vec<u8>> {
        self.0
    }
}

fn import_impl(path: &Path, config: &Config) -> Result<(Gltf, Buffers), Error> {
    let data = read_to_end(path)?;
    import_data_slice(&data, path, config)
}

pub fn import_data_slice<'a>(data: &'a [u8], path: &Path, config: Config) -> Result<(Gltf, Buffers), Error> {
    if data.starts_with(b"glTF") {
        import_binary(&data, config, path)
    } else {
        import_standard(&data, config, path)
    }
}

/// Imports glTF 2.0 with custom configuration.
pub fn import_with_config<P>(path: P, config: &Config) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), config)
}

/// Imports glTF 2.0 with default configuration.
pub fn import<P>(path: P) -> Result<(Gltf, Buffers), Error>
    where P: AsRef<Path>
{
    import_impl(path.as_ref(), &Default::default())
}

fn read_to_end_impl(path: &Path) -> Result<Vec<u8>, Error> {
    use io::Read;
    let file = fs::File::open(path)?;
    let mut reader = io::BufReader::new(file);
    let mut buffer = vec![];
    let _ = reader.read_to_end(&mut buffer)?;
    Ok(buffer)
}

fn read_to_end<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    read_to_end_impl(path.as_ref())
}

fn parse_data_uri(uri: &str) -> Result<Vec<u8>, Error> {
    let encoded = uri.split(',').nth(1).unwrap();
    let decoded = base64::decode(&encoded)?;
    Ok(decoded)
}

fn load_external_buffers(
    base_path: &Path,
    gltf: &Gltf,
    mut bin: Option<Vec<u8>>,
) -> Result<Vec<Vec<u8>>, Error> {
    let mut buffers = vec![];
    for (index, buffer) in gltf.buffers().enumerate() {
        let uri = buffer.uri();
        let data = if uri == "#bin" {
            Ok(bin.take().unwrap())
        } else if uri.starts_with("data:") {
            Ok(parse_data_uri(uri)?)
        } else {
            let path = base_path.parent().unwrap_or_else(|| Path::new("./")).join(uri);
            read_to_end(&path)
        }?;
        if data.len() < buffer.length() {
            let path = json::Path::new().field("buffers").index(index);
            return Err(Error::BufferLength(path));
        }
        buffers.push(data);
    }
    Ok(buffers)
}

fn validate_standard(
    unvalidated: gltf::Unvalidated,
    config: &Config,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    Ok(match config.validation_strategy {
        ValidationStrategy::Skip => unvalidated.skip_validation(),
        ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
        ValidationStrategy::Complete => unvalidated.validate_completely()?,
    })
}

fn validate_binary(
    unvalidated: gltf::Unvalidated,
    config: &Config,
    has_bin: bool,
) -> Result<Gltf, Error> {
    use config::ValidationStrategy;
    use json::validation::Error as Reason;

    if config.validation_strategy == ValidationStrategy::Skip {
        return Ok(unvalidated.skip_validation());
    }

    let mut errs = vec![];
    {
        let json = unvalidated.as_json();
        for (index, buffer) in json.buffers.iter().enumerate() {
            let path = || {
                json::Path::new()
                    .field("buffers")
                    .index(index)
                    .field("uri")
            };
            match index {
                0 if has_bin => if buffer.uri.is_some() {
                    errs.push((path(), Reason::Missing));
                },
                _ if buffer.uri.is_none() => {
                    errs.push((path(), Reason::Missing));
                },
                _ => {},
            }
        }
    }

    if errs.is_empty() {
        Ok(match config.validation_strategy {
            ValidationStrategy::Minimal => unvalidated.validate_minimally()?,
            ValidationStrategy::Complete => unvalidated.validate_completely()?,
            ValidationStrategy::Skip => unreachable!(),
        })
    } else {
        Err(Error::Validation(errs))
    }
}

fn import_standard<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let unvalidated = Gltf::from_slice(data)?;
    let gltf = validate_standard(unvalidated, config)?;
    let bin = None;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

fn import_binary<'a>(
    data: &'a [u8],
    config: &Config,
    base_path: &Path,
) -> Result<(Gltf, Buffers), Error> {
    let gltf::Glb { json, bin, .. } = gltf::Glb::from_slice(data)?;
    let unvalidated = Gltf::from_slice(json)?;
    let bin = bin.map(|x| x.to_vec());
    let gltf = validate_binary(unvalidated, config, bin.is_some())?;
    let mut buffers = Buffers(vec![]);
    for buffer in load_external_buffers(base_path, &gltf, bin)? {
        buffers.0.push(buffer);
    }
    Ok((gltf, buffers))
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Error {
        Error::MalformedJson(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Vec<(json::Path, validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, validation::Error)>) -> Error {
        Error::Validation(errs)
    }
}

impl From<gltf::Error> for Error {
    fn from(err: gltf::Error) -> Error {
        match err {
            gltf::Error::Validation(errs) => Error::Validation(errs),
            _ => Error::Gltf(err),
        }
    }
}

impl From<base64::DecodeError> for Error {
    fn from(err: base64::DecodeError) -> Error {
        Error::Base64Decoding(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Base64Decoding(_) => "Base 64 decoding failed",
            BufferLength(_) => "Loaded buffer does not match required length",
            ExtensionDisabled(_) => "Asset requires a disabled extension",
            ExtensionUnsupported(_) => "Assets requires an unsupported extension",
            IncompatibleVersion(_) => "Asset is not glTF version 2.0",
            Io(_) => "I/O error",
            Gltf(_) => "Error from gltf crate",
            MalformedJson(_) => "Malformed .gltf / .glb JSON",
            Validation(_) => "Asset failed validation tests",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use self::Error::*;
        match *self {
            MalformedJson(ref err) => Some(err),
            Io(ref err) => Some(err),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! This calculates the types which has storage which lives across a suspension point in a
//! generator from the perspective of typeck. The actual types used at runtime
//! is calculated in `rustc_mir::transform::generator` and may be a subset of the
//! types computed here.

use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_middle::middle::region::{self, YieldData};
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use smallvec::SmallVec;

struct InteriorVisitor<'a, 'tcx> {
    fcx: &'a FnCtxt<'a, 'tcx>,
    types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
    region_scope_tree: &'tcx region::ScopeTree,
    expr_count: usize,
    kind: hir::GeneratorKind,
    prev_unresolved_span: Option<Span>,
    /// Match arm guards have temporary borrows from the pattern bindings.
    /// In case there is a yield point in a guard with a reference to such bindings,
    /// such borrows can span across this yield point.
    /// As such, we need to track these borrows and record them despite of the fact
    /// that they may succeed the said yield point in the post-order.
    nested_scope_of_guards: SmallVec<[SmallVec<[HirId; 4]>; 4]>,
    current_scope_of_guards: HirIdSet,
    arm_has_guard: bool,
}

impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
    fn record(
        &mut self,
        ty: Ty<'tcx>,
        scope: Option<region::Scope>,
        expr: Option<&'tcx Expr<'tcx>>,
        source_span: Span,
        guard_borrowing_from_pattern: bool,
    ) {
        use rustc_span::DUMMY_SP;

        debug!(
            "generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
            ty, scope, expr, source_span
        );

        let live_across_yield = scope
            .map(|s| {
                self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
                    // If we are recording an expression that is the last yield
                    // in the scope, or that has a postorder CFG index larger
                    // than the one of all of the yields, then its value can't
                    // be storage-live (and therefore live) at any of the yields.
                    //
                    // See the mega-comment at `yield_in_scope` for a proof.

                    debug!(
                        "comparing counts yield: {} self: {}, source_span = {:?}",
                        yield_data.expr_and_pat_count, self.expr_count, source_span
                    );

                    if guard_borrowing_from_pattern
                        || yield_data.expr_and_pat_count >= self.expr_count
                    {
                        Some(yield_data)
                    } else {
                        None
                    }
                })
            })
            .unwrap_or_else(|| {
                Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, source: self.kind.into() })
            });

        if let Some(yield_data) = live_across_yield {
            let ty = self.fcx.resolve_vars_if_possible(&ty);
            debug!(
                "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
                expr, scope, ty, self.expr_count, yield_data.span
            );

            if let Some((unresolved_type, unresolved_type_span)) =
                self.fcx.unresolved_type_vars(&ty)
            {
                let note = format!(
                    "the type is part of the {} because of this {}",
                    self.kind, yield_data.source
                );

                // If unresolved type isn't a ty_var then unresolved_type_span is None
                let span = self
                    .prev_unresolved_span
                    .unwrap_or_else(|| unresolved_type_span.unwrap_or(source_span));
                self.fcx
                    .need_type_info_err_in_generator(self.kind, span, unresolved_type)
                    .span_note(yield_data.span, &*note)
                    .emit();
            } else {
                // Insert the type into the ordered set.
                let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
                self.types.insert(ty::GeneratorInteriorTypeCause {
                    span: source_span,
                    ty: &ty,
                    scope_span,
                    yield_span: yield_data.span,
                    expr: expr.map(|e| e.hir_id),
                });
            }
        } else {
            debug!(
                "no type in expr = {:?}, count = {:?}, span = {:?}",
                expr,
                self.expr_count,
                expr.map(|e| e.span)
            );
            let ty = self.fcx.resolve_vars_if_possible(&ty);
            if let Some((unresolved_type, unresolved_type_span)) =
                self.fcx.unresolved_type_vars(&ty)
            {
                debug!(
                    "remained unresolved_type = {:?}, unresolved_type_span: {:?}",
                    unresolved_type, unresolved_type_span
                );
                self.prev_unresolved_span = unresolved_type_span;
            }
        }
    }
}

pub fn resolve_interior<'a, 'tcx>(
    fcx: &'a FnCtxt<'a, 'tcx>,
    def_id: DefId,
    body_id: hir::BodyId,
    interior: Ty<'tcx>,
    kind: hir::GeneratorKind,
) {
    let body = fcx.tcx.hir().body(body_id);
    let mut visitor = InteriorVisitor {
        fcx,
        types: FxIndexSet::default(),
        region_scope_tree: fcx.tcx.region_scope_tree(def_id),
        expr_count: 0,
        kind,
        prev_unresolved_span: None,
        nested_scope_of_guards: <_>::default(),
        current_scope_of_guards: <_>::default(),
        arm_has_guard: false,
    };
    intravisit::walk_body(&mut visitor, body);

    // Check that we visited the same amount of expressions and the RegionResolutionVisitor
    let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
    assert_eq!(region_expr_count, visitor.expr_count);

    // The types are already kept in insertion order.
    let types = visitor.types;

    // The types in the generator interior contain lifetimes local to the generator itself,
    // which should not be exposed outside of the generator. Therefore, we replace these
    // lifetimes with existentially-bound lifetimes, which reflect the exact value of the
    // lifetimes not being known by users.
    //
    // These lifetimes are used in auto trait impl checking (for example,
    // if a Sync generator contains an &'α T, we need to check whether &'α T: Sync),
    // so knowledge of the exact relationships between them isn't particularly important.

    debug!("types in generator {:?}, span = {:?}", types, body.value.span);

    let mut counter = 0;
    let mut captured_tys = FxHashSet::default();
    let type_causes: Vec<_> = types
        .into_iter()
        .filter_map(|mut cause| {
            // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
            // can.
            let erased = fcx.tcx.erase_regions(&cause.ty);
            if captured_tys.insert(erased) {
                // Replace all regions inside the generator interior with late bound regions.
                // Note that each region slot in the types gets a new fresh late bound region,
                // which means that none of the regions inside relate to any other, even if
                // typeck had previously found constraints that would cause them to be related.
                let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| {
                    counter += 1;
                    fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter)))
                });

                cause.ty = folded;
                Some(cause)
            } else {
                None
            }
        })
        .collect();

    // Extract type components to build the witness type.
    let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
    let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list));

    // Store the generator types and spans into the typeck results for this generator.
    visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = type_causes;

    debug!(
        "types in generator after region replacement {:?}, span = {:?}",
        witness, body.value.span
    );

    // Unify the type variable inside the generator with the new witness
    match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
        Ok(ok) => fcx.register_infer_ok_obligations(ok),
        _ => bug!(),
    }
}

// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
// there.
impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
    type Map = intravisit::ErasedMap<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }

    fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
        if arm.guard.is_some() {
            self.nested_scope_of_guards.push(<_>::default());
            self.arm_has_guard = true;
        }
        self.visit_pat(&arm.pat);
        if let Some(ref g) = arm.guard {
            match g {
                Guard::If(ref e) => {
                    self.visit_expr(e);
                }
            }
            let mut scope_var_ids =
                self.nested_scope_of_guards.pop().expect("should have pushed at least one earlier");
            for var_id in scope_var_ids.drain(..) {
                assert!(
                    self.current_scope_of_guards.remove(&var_id),
                    "variable should be placed in scope earlier"
                );
            }
            self.arm_has_guard = false;
        }
        self.visit_expr(&arm.body);
    }

    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
        intravisit::walk_pat(self, pat);

        self.expr_count += 1;

        if let PatKind::Binding(_, id, ..) = pat.kind {
            let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
            let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
            self.record(ty, Some(scope), None, pat.span, false);
            if self.arm_has_guard {
                self.nested_scope_of_guards.as_mut_slice().last_mut().unwrap().push(id);
                self.current_scope_of_guards.insert(id);
            }
        }
    }

    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        let mut guard_borrowing_from_pattern = false;
        match &expr.kind {
            ExprKind::Call(callee, args) => match &callee.kind {
                ExprKind::Path(qpath) => {
                    let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id);
                    match res {
                        // Direct calls never need to keep the callee `ty::FnDef`
                        // ZST in a temporary, so skip its type, just in case it
                        // can significantly complicate the generator type.
                        Res::Def(
                            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn),
                            _,
                        ) => {
                            // NOTE(eddyb) this assumes a path expression has
                            // no nested expressions to keep track of.
                            self.expr_count += 1;

                            // Record the rest of the call expression normally.
                            for arg in *args {
                                self.visit_expr(arg);
                            }
                        }
                        _ => intravisit::walk_expr(self, expr),
                    }
                }
                _ => intravisit::walk_expr(self, expr),
            },
            ExprKind::Path(qpath) => {
                intravisit::walk_expr(self, expr);
                let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
                match res {
                    Res::Local(id) if self.current_scope_of_guards.contains(&id) => {
                        debug!("a borrow in guard from pattern local is detected");
                        guard_borrowing_from_pattern = true;
                    }
                    _ => {}
                }
            }
            _ => intravisit::walk_expr(self, expr),
        }

        self.expr_count += 1;

        let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);

        // If there are adjustments, then record the final type --
        // this is the actual value that is being produced.
        if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
            self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
        }

        // Also record the unadjusted type (which is the only type if
        // there are no adjustments). The reason for this is that the
        // unadjusted value is sometimes a "temporary" that would wind
        // up in a MIR temporary.
        //
        // As an example, consider an expression like `vec![].push(x)`.
        // Here, the `vec![]` would wind up MIR stored into a
        // temporary variable `t` which we can borrow to invoke
        // `<Vec<_>>::push(&mut t, x)`.
        //
        // Note that an expression can have many adjustments, and we
        // are just ignoring those intermediate types. This is because
        // those intermediate values are always linearly "consumed" by
        // the other adjustments, and hence would never be directly
        // captured in the MIR.
        //
        // (Note that this partly relies on the fact that the `Deref`
        // traits always return references, which means their content
        // can be reborrowed without needing to spill to a temporary.
        // If this were not the case, then we could conceivably have
        // to create intermediate temporaries.)
        //
        // The type table might not have information for this expression
        // if it is in a malformed scope. (#66387)
        if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
            self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
        } else {
            self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
        }
    }
}
<commit_msg>dedicated visitor for arm patterns<commit_after>//! This calculates the types which has storage which lives across a suspension point in a
//! generator from the perspective of typeck. The actual types used at runtime
//! is calculated in `rustc_mir::transform::generator` and may be a subset of the
//! types computed here.

use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
use rustc_middle::middle::region::{self, YieldData};
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use smallvec::SmallVec;

struct InteriorVisitor<'a, 'tcx> {
    fcx: &'a FnCtxt<'a, 'tcx>,
    types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
    region_scope_tree: &'tcx region::ScopeTree,
    expr_count: usize,
    kind: hir::GeneratorKind,
    prev_unresolved_span: Option<Span>,
    /// Match arm guards have temporary borrows from the pattern bindings.
    /// In case there is a yield point in a guard with a reference to such bindings,
    /// such borrows can span across this yield point.
    /// As such, we need to track these borrows and record them despite of the fact
    /// that they may succeed the said yield point in the post-order.
    guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
    guard_bindings_set: HirIdSet,
}

impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
    fn record(
        &mut self,
        ty: Ty<'tcx>,
        scope: Option<region::Scope>,
        expr: Option<&'tcx Expr<'tcx>>,
        source_span: Span,
        guard_borrowing_from_pattern: bool,
    ) {
        use rustc_span::DUMMY_SP;

        debug!(
            "generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
            ty, scope, expr, source_span
        );

        let live_across_yield = scope
            .map(|s| {
                self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
                    // If we are recording an expression that is the last yield
                    // in the scope, or that has a postorder CFG index larger
                    // than the one of all of the yields, then its value can't
                    // be storage-live (and therefore live) at any of the yields.
                    //
                    // See the mega-comment at `yield_in_scope` for a proof.

                    debug!(
                        "comparing counts yield: {} self: {}, source_span = {:?}",
                        yield_data.expr_and_pat_count, self.expr_count, source_span
                    );

                    if guard_borrowing_from_pattern
                        || yield_data.expr_and_pat_count >= self.expr_count
                    {
                        Some(yield_data)
                    } else {
                        None
                    }
                })
            })
            .unwrap_or_else(|| {
                Some(YieldData { span: DUMMY_SP, expr_and_pat_count: 0, source: self.kind.into() })
            });

        if let Some(yield_data) = live_across_yield {
            let ty = self.fcx.resolve_vars_if_possible(&ty);
            debug!(
                "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
                expr, scope, ty, self.expr_count, yield_data.span
            );

            if let Some((unresolved_type, unresolved_type_span)) =
                self.fcx.unresolved_type_vars(&ty)
            {
                let note = format!(
                    "the type is part of the {} because of this {}",
                    self.kind, yield_data.source
                );

                // If unresolved type isn't a ty_var then unresolved_type_span is None
                let span = self
                    .prev_unresolved_span
                    .unwrap_or_else(|| unresolved_type_span.unwrap_or(source_span));
                self.fcx
                    .need_type_info_err_in_generator(self.kind, span, unresolved_type)
                    .span_note(yield_data.span, &*note)
                    .emit();
            } else {
                // Insert the type into the ordered set.
                let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
                self.types.insert(ty::GeneratorInteriorTypeCause {
                    span: source_span,
                    ty: &ty,
                    scope_span,
                    yield_span: yield_data.span,
                    expr: expr.map(|e| e.hir_id),
                });
            }
        } else {
            debug!(
                "no type in expr = {:?}, count = {:?}, span = {:?}",
                expr,
                self.expr_count,
                expr.map(|e| e.span)
            );
            let ty = self.fcx.resolve_vars_if_possible(&ty);
            if let Some((unresolved_type, unresolved_type_span)) =
                self.fcx.unresolved_type_vars(&ty)
            {
                debug!(
                    "remained unresolved_type = {:?}, unresolved_type_span: {:?}",
                    unresolved_type, unresolved_type_span
                );
                self.prev_unresolved_span = unresolved_type_span;
            }
        }
    }
}

pub fn resolve_interior<'a, 'tcx>(
    fcx: &'a FnCtxt<'a, 'tcx>,
    def_id: DefId,
    body_id: hir::BodyId,
    interior: Ty<'tcx>,
    kind: hir::GeneratorKind,
) {
    let body = fcx.tcx.hir().body(body_id);
    let mut visitor = InteriorVisitor {
        fcx,
        types: FxIndexSet::default(),
        region_scope_tree: fcx.tcx.region_scope_tree(def_id),
        expr_count: 0,
        kind,
        prev_unresolved_span: None,
        guard_bindings: <_>::default(),
        guard_bindings_set: <_>::default(),
    };
    intravisit::walk_body(&mut visitor, body);

    // Check that we visited the same amount of expressions and the RegionResolutionVisitor
    let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
    assert_eq!(region_expr_count, visitor.expr_count);

    // The types are already kept in insertion order.
    let types = visitor.types;

    // The types in the generator interior contain lifetimes local to the generator itself,
    // which should not be exposed outside of the generator. Therefore, we replace these
    // lifetimes with existentially-bound lifetimes, which reflect the exact value of the
    // lifetimes not being known by users.
    //
    // These lifetimes are used in auto trait impl checking (for example,
    // if a Sync generator contains an &'α T, we need to check whether &'α T: Sync),
    // so knowledge of the exact relationships between them isn't particularly important.

    debug!("types in generator {:?}, span = {:?}", types, body.value.span);

    let mut counter = 0;
    let mut captured_tys = FxHashSet::default();
    let type_causes: Vec<_> = types
        .into_iter()
        .filter_map(|mut cause| {
            // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
            // can.
            let erased = fcx.tcx.erase_regions(&cause.ty);
            if captured_tys.insert(erased) {
                // Replace all regions inside the generator interior with late bound regions.
                // Note that each region slot in the types gets a new fresh late bound region,
                // which means that none of the regions inside relate to any other, even if
                // typeck had previously found constraints that would cause them to be related.
                let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| {
                    counter += 1;
                    fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter)))
                });

                cause.ty = folded;
                Some(cause)
            } else {
                None
            }
        })
        .collect();

    // Extract type components to build the witness type.
    let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
    let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list));

    // Store the generator types and spans into the typeck results for this generator.
    visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = type_causes;

    debug!(
        "types in generator after region replacement {:?}, span = {:?}",
        witness, body.value.span
    );

    // Unify the type variable inside the generator with the new witness
    match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
        Ok(ok) => fcx.register_infer_ok_obligations(ok),
        _ => bug!(),
    }
}

// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
// librustc_middle/middle/region.rs since `expr_count` is compared against the results
// there.
impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
    type Map = intravisit::ErasedMap<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }

    fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
        if arm.guard.is_some() {
            self.guard_bindings.push(<_>::default());
        }
        self.visit_pat(&arm.pat);
        if let Some(ref g) = arm.guard {
            self.guard_bindings.push(<_>::default());
            ArmPatCollector {
                guard_bindings_set: &mut self.guard_bindings_set,
                guard_bindings: self
                    .guard_bindings
                    .last_mut()
                    .expect("should have pushed at least one earlier"),
            }
            .visit_pat(&arm.pat);

            match g {
                Guard::If(ref e) => {
                    self.visit_expr(e);
                }
            }

            let mut scope_var_ids =
                self.guard_bindings.pop().expect("should have pushed at least one earlier");
            for var_id in scope_var_ids.drain(..) {
                assert!(
                    self.guard_bindings_set.remove(&var_id),
                    "variable should be placed in scope earlier"
                );
            }
        }
        self.visit_expr(&arm.body);
    }

    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
        intravisit::walk_pat(self, pat);

        self.expr_count += 1;

        if let PatKind::Binding(..) = pat.kind {
            let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
            let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
            self.record(ty, Some(scope), None, pat.span, false);
        }
    }

    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        let mut guard_borrowing_from_pattern = false;
        match &expr.kind {
            ExprKind::Call(callee, args) => match &callee.kind {
                ExprKind::Path(qpath) => {
                    let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id);
                    match res {
                        // Direct calls never need to keep the callee `ty::FnDef`
                        // ZST in a temporary, so skip its type, just in case it
                        // can significantly complicate the generator type.
                        Res::Def(
                            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn),
                            _,
                        ) => {
                            // NOTE(eddyb) this assumes a path expression has
                            // no nested expressions to keep track of.
                            self.expr_count += 1;

                            // Record the rest of the call expression normally.
                            for arg in *args {
                                self.visit_expr(arg);
                            }
                        }
                        _ => intravisit::walk_expr(self, expr),
                    }
                }
                _ => intravisit::walk_expr(self, expr),
            },
            ExprKind::Path(qpath) => {
                intravisit::walk_expr(self, expr);
                let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
                match res {
                    Res::Local(id) if self.guard_bindings_set.contains(&id) => {
                        guard_borrowing_from_pattern = true;
                    }
                    _ => {}
                }
            }
            _ => intravisit::walk_expr(self, expr),
        }

        self.expr_count += 1;

        let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);

        // If there are adjustments, then record the final type --
        // this is the actual value that is being produced.
        if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
            self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
        }

        // Also record the unadjusted type (which is the only type if
        // there are no adjustments). The reason for this is that the
        // unadjusted value is sometimes a "temporary" that would wind
        // up in a MIR temporary.
        //
        // As an example, consider an expression like `vec![].push(x)`.
        // Here, the `vec![]` would wind up MIR stored into a
        // temporary variable `t` which we can borrow to invoke
        // `<Vec<_>>::push(&mut t, x)`.
        //
        // Note that an expression can have many adjustments, and we
        // are just ignoring those intermediate types. This is because
        // those intermediate values are always linearly "consumed" by
        // the other adjustments, and hence would never be directly
        // captured in the MIR.
        //
        // (Note that this partly relies on the fact that the `Deref`
        // traits always return references, which means their content
        // can be reborrowed without needing to spill to a temporary.
        // If this were not the case, then we could conceivably have
        // to create intermediate temporaries.)
        //
        // The type table might not have information for this expression
        // if it is in a malformed scope. (#66387)
        if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
            self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
        } else {
            self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
        }
    }
}

struct ArmPatCollector<'a> {
    guard_bindings_set: &'a mut HirIdSet,
    guard_bindings: &'a mut SmallVec<[HirId; 4]>,
}

impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
    type Map = intravisit::ErasedMap<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }

    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
        intravisit::walk_pat(self, pat);
        if let PatKind::Binding(_, id, ..) = pat.kind {
            self.guard_bindings.push(id);
            self.guard_bindings_set.insert(id);
        }
    }
}
<|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.
 */

use common::{Named, NamedItem};
use graphql_syntax::*;
use interner::StringKey;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::slice::Iter;

pub(crate) type TypeMap = HashMap<StringKey, Type>;

macro_rules! type_id {
    ($name:ident, $type:ident) => {
        #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
        pub struct $name(pub $type);
        impl $name {
            pub(crate) fn as_usize(&self) -> usize {
                self.0 as usize
            }
        }
    };
}

type_id!(EnumID, u32);
type_id!(InputObjectID, u32);
type_id!(InterfaceID, u32);
type_id!(ObjectID, u32);
type_id!(ScalarID, u32);
type_id!(UnionID, u32);
type_id!(FieldID, u32);

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Type {
    Enum(EnumID),
    InputObject(InputObjectID),
    Interface(InterfaceID),
    Object(ObjectID),
    Scalar(ScalarID),
    Union(UnionID),
}

impl Type {
    pub fn is_scalar(self) -> bool {
        matches!(self, Type::Scalar(_))
    }

    pub fn is_enum(self) -> bool {
        matches!(self, Type::Enum(_))
    }

    pub fn is_input_type(self) -> bool {
        matches!(self, Type::Scalar(_) | Type::Enum(_) | Type::InputObject(_))
    }

    pub fn is_abstract_type(self) -> bool {
        matches!(self, Type::Union(_) | Type::Interface(_))
    }

    pub fn is_object(self) -> bool {
        matches!(self, Type::Object(_))
    }

    pub fn is_input_object(self) -> bool {
        matches!(self, Type::InputObject(_))
    }

    pub fn is_interface(self) -> bool {
        matches!(self, Type::Interface(_))
    }

    pub fn is_object_or_interface(self) -> bool {
        matches!(self, Type::Object(_) | Type::Interface(_))
    }

    pub fn is_union(self) -> bool {
        matches!(self, Type::Union(_))
    }

    pub fn get_enum_id(self) -> Option<EnumID> {
        match self {
            Type::Enum(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_input_object_id(self) -> Option<InputObjectID> {
        match self {
            Type::InputObject(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_interface_id(self) -> Option<InterfaceID> {
        match self {
            Type::Interface(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_object_id(self) -> Option<ObjectID> {
        match self {
            Type::Object(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_scalar_id(self) -> Option<ScalarID> {
        match self {
            Type::Scalar(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_union_id(self) -> Option<UnionID> {
        match self {
            Type::Union(id) => Some(id),
            _ => None,
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Type::Enum(id) => f.write_fmt(format_args!("Enum({:?})", id.0)),
            Type::InputObject(id) => f.write_fmt(format_args!("InputObject({:?})", id.0)),
            Type::Interface(id) => f.write_fmt(format_args!("Interface({:?})", id.0)),
            Type::Object(id) => f.write_fmt(format_args!("Object({:?})", id.0)),
            Type::Scalar(id) => f.write_fmt(format_args!("Scalar({:?})", id.0)),
            Type::Union(id) => f.write_fmt(format_args!("Union({:?})", id.0)),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum TypeReference {
    Named(Type),
    NonNull(Box<TypeReference>),
    List(Box<TypeReference>),
}

impl TypeReference {
    pub fn inner(&self) -> Type {
        match self {
            TypeReference::Named(type_) => *type_,
            TypeReference::List(of) => of.inner(),
            TypeReference::NonNull(of) => of.inner(),
        }
    }

    pub fn non_null(&self) -> TypeReference {
        match self {
            TypeReference::Named(_) => TypeReference::NonNull(Box::new(self.clone())),
            TypeReference::List(_) => TypeReference::NonNull(Box::new(self.clone())),
            TypeReference::NonNull(_) => self.clone(),
        }
    }

    pub fn nullable_type(&self) -> &TypeReference {
        match self {
            TypeReference::Named(_) => self,
            TypeReference::List(_) => self,
            TypeReference::NonNull(of) => of,
        }
    }

    pub fn is_non_null(&self) -> bool {
        matches!(self, TypeReference::NonNull(_))
    }

    pub fn is_list(&self) -> bool {
        matches!(self.nullable_type(), TypeReference::List(_))
    }

    // If the type is Named or NonNull<Named> return the inner named.
    // If the type is a List or NonNull<List> returns a matching list with nullable items.
    pub fn with_nullable_item_type(&self) -> TypeReference {
        match self {
            TypeReference::Named(_) => self.clone(),
            TypeReference::List(of) => TypeReference::List(Box::new(of.nullable_type().clone())),
            TypeReference::NonNull(of) => {
                let inner: &TypeReference = of;
                match inner {
                    TypeReference::List(_) => {
                        TypeReference::NonNull(Box::new(of.with_nullable_item_type()))
                    }
                    TypeReference::Named(_) => inner.clone(),
                    TypeReference::NonNull(_) => {
                        unreachable!("Invalid nested TypeReference::NonNull")
                    }
                }
            }
        }
    }

    pub fn list_item_type(&self) -> Option<&TypeReference> {
        match self.nullable_type() {
            TypeReference::List(of) => Some(of),
            _ => None,
        }
    }

    // Return None if the type is a List, otherwise return the inner type
    pub fn non_list_type(&self) -> Option<Type> {
        match self {
            TypeReference::List(_) => None,
            TypeReference::Named(type_) => Some(*type_),
            TypeReference::NonNull(of) => of.non_list_type(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Directive {
    pub name: StringKey,
    pub arguments: ArgumentDefinitions,
    pub locations: Vec<DirectiveLocation>,
    pub repeatable: bool,
    pub is_extension: bool,
}

impl Named for Directive {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug)]
pub struct Scalar {
    pub name: StringKey,
    pub is_extension: bool,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Object {
    pub name: StringKey,
    pub is_extension: bool,
    pub fields: Vec<FieldID>,
    pub interfaces: Vec<InterfaceID>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InputObject {
    pub name: StringKey,
    pub fields: ArgumentDefinitions,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Enum {
    pub name: StringKey,
    pub is_extension: bool,
    pub values: Vec<EnumValue>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Union {
    pub name: StringKey,
    pub is_extension: bool,
    pub members: Vec<ObjectID>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Interface {
    pub name: StringKey,
    pub is_extension: bool,
    pub implementing_objects: Vec<ObjectID>,
    pub fields: Vec<FieldID>,
    pub directives: Vec<DirectiveValue>,
    pub interfaces: Vec<InterfaceID>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Field {
    pub name: StringKey,
    pub is_extension: bool,
    pub arguments: ArgumentDefinitions,
    pub type_: TypeReference,
    pub directives: Vec<DirectiveValue>,
    /// The type on which this field was defined. This field is (should)
    /// always be set, except for special fields such as __typename and
    /// __id, which are queryable on all types and therefore don't have
    /// a single parent type.
    pub parent_type: Option<Type>,
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Argument {
    pub name: StringKey,
    pub type_: TypeReference,
    pub default_value: Option<ConstantValue>,
}

impl Named for Argument {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ArgumentValue {
    pub name: StringKey,
    pub value: ConstantValue,
}

impl Named for ArgumentValue {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct DirectiveValue {
    pub name: StringKey,
    pub arguments: Vec<ArgumentValue>,
}

impl Named for DirectiveValue {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct EnumValue {
    pub value: StringKey,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ArgumentDefinitions(pub(crate) Vec<Argument>);

impl ArgumentDefinitions {
    pub fn new(arguments: Vec<Argument>) -> Self {
        Self(arguments)
    }

    pub fn named(&self, name: StringKey) -> Option<&Argument> {
        self.0.named(name)
    }

    pub fn contains(&self, name: StringKey) -> bool {
        self.0.iter().any(|x| x.name == name)
    }

    pub fn iter(&self) -> Iter<'_, Argument> {
        self.0.iter()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl fmt::Debug for ArgumentDefinitions {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!("{:#?}", self.0))
    }
}

impl IntoIterator for ArgumentDefinitions {
    type Item = Argument;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

pub trait TypeWithFields {
    fn name(&self) -> StringKey;
    fn fields(&self) -> &Vec<FieldID>;
    fn interfaces(&self) -> &Vec<InterfaceID>;
}

impl TypeWithFields for Interface {
    fn name(&self) -> StringKey {
        self.name
    }

    fn fields(&self) -> &Vec<FieldID> {
        &self.fields
    }

    fn interfaces(&self) -> &Vec<InterfaceID> {
        &self.interfaces
    }
}

impl TypeWithFields for Object {
    fn name(&self) -> StringKey {
        self.name
    }

    fn fields(&self) -> &Vec<FieldID> {
        &self.fields
    }

    fn interfaces(&self) -> &Vec<InterfaceID> {
        &self.interfaces
    }
}
<commit_msg>add is_composite_type from definitions.js<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::{Named, NamedItem};
use graphql_syntax::*;
use interner::StringKey;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::slice::Iter;

pub(crate) type TypeMap = HashMap<StringKey, Type>;

macro_rules! type_id {
    ($name:ident, $type:ident) => {
        #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
        pub struct $name(pub $type);
        impl $name {
            pub(crate) fn as_usize(&self) -> usize {
                self.0 as usize
            }
        }
    };
}

type_id!(EnumID, u32);
type_id!(InputObjectID, u32);
type_id!(InterfaceID, u32);
type_id!(ObjectID, u32);
type_id!(ScalarID, u32);
type_id!(UnionID, u32);
type_id!(FieldID, u32);

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Type {
    Enum(EnumID),
    InputObject(InputObjectID),
    Interface(InterfaceID),
    Object(ObjectID),
    Scalar(ScalarID),
    Union(UnionID),
}

impl Type {
    pub fn is_scalar(self) -> bool {
        matches!(self, Type::Scalar(_))
    }

    pub fn is_enum(self) -> bool {
        matches!(self, Type::Enum(_))
    }

    pub fn is_input_type(self) -> bool {
        matches!(self, Type::Scalar(_) | Type::Enum(_) | Type::InputObject(_))
    }

    pub fn is_abstract_type(self) -> bool {
        matches!(self, Type::Union(_) | Type::Interface(_))
    }

    pub fn is_composite_type(self) -> bool {
        matches!(self, Type::Object(_) | Type::Interface(_) | Type::Union(_))
    }

    pub fn is_object(self) -> bool {
        matches!(self, Type::Object(_))
    }

    pub fn is_input_object(self) -> bool {
        matches!(self, Type::InputObject(_))
    }

    pub fn is_interface(self) -> bool {
        matches!(self, Type::Interface(_))
    }

    pub fn is_object_or_interface(self) -> bool {
        matches!(self, Type::Object(_) | Type::Interface(_))
    }

    pub fn is_union(self) -> bool {
        matches!(self, Type::Union(_))
    }

    pub fn get_enum_id(self) -> Option<EnumID> {
        match self {
            Type::Enum(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_input_object_id(self) -> Option<InputObjectID> {
        match self {
            Type::InputObject(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_interface_id(self) -> Option<InterfaceID> {
        match self {
            Type::Interface(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_object_id(self) -> Option<ObjectID> {
        match self {
            Type::Object(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_scalar_id(self) -> Option<ScalarID> {
        match self {
            Type::Scalar(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_union_id(self) -> Option<UnionID> {
        match self {
            Type::Union(id) => Some(id),
            _ => None,
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Type::Enum(id) => f.write_fmt(format_args!("Enum({:?})", id.0)),
            Type::InputObject(id) => f.write_fmt(format_args!("InputObject({:?})", id.0)),
            Type::Interface(id) => f.write_fmt(format_args!("Interface({:?})", id.0)),
            Type::Object(id) => f.write_fmt(format_args!("Object({:?})", id.0)),
            Type::Scalar(id) => f.write_fmt(format_args!("Scalar({:?})", id.0)),
            Type::Union(id) => f.write_fmt(format_args!("Union({:?})", id.0)),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum TypeReference {
    Named(Type),
    NonNull(Box<TypeReference>),
    List(Box<TypeReference>),
}

impl TypeReference {
    pub fn inner(&self) -> Type {
        match self {
            TypeReference::Named(type_) => *type_,
            TypeReference::List(of) => of.inner(),
            TypeReference::NonNull(of) => of.inner(),
        }
    }

    pub fn non_null(&self) -> TypeReference {
        match self {
            TypeReference::Named(_) => TypeReference::NonNull(Box::new(self.clone())),
            TypeReference::List(_) => TypeReference::NonNull(Box::new(self.clone())),
            TypeReference::NonNull(_) => self.clone(),
        }
    }

    pub fn nullable_type(&self) -> &TypeReference {
        match self {
            TypeReference::Named(_) => self,
            TypeReference::List(_) => self,
            TypeReference::NonNull(of) => of,
        }
    }

    pub fn is_non_null(&self) -> bool {
        matches!(self, TypeReference::NonNull(_))
    }

    pub fn is_list(&self) -> bool {
        matches!(self.nullable_type(), TypeReference::List(_))
    }

    // If the type is Named or NonNull<Named> return the inner named.
    // If the type is a List or NonNull<List> returns a matching list with nullable items.
    pub fn with_nullable_item_type(&self) -> TypeReference {
        match self {
            TypeReference::Named(_) => self.clone(),
            TypeReference::List(of) => TypeReference::List(Box::new(of.nullable_type().clone())),
            TypeReference::NonNull(of) => {
                let inner: &TypeReference = of;
                match inner {
                    TypeReference::List(_) => {
                        TypeReference::NonNull(Box::new(of.with_nullable_item_type()))
                    }
                    TypeReference::Named(_) => inner.clone(),
                    TypeReference::NonNull(_) => {
                        unreachable!("Invalid nested TypeReference::NonNull")
                    }
                }
            }
        }
    }

    pub fn list_item_type(&self) -> Option<&TypeReference> {
        match self.nullable_type() {
            TypeReference::List(of) => Some(of),
            _ => None,
        }
    }

    // Return None if the type is a List, otherwise return the inner type
    pub fn non_list_type(&self) -> Option<Type> {
        match self {
            TypeReference::List(_) => None,
            TypeReference::Named(type_) => Some(*type_),
            TypeReference::NonNull(of) => of.non_list_type(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Directive {
    pub name: StringKey,
    pub arguments: ArgumentDefinitions,
    pub locations: Vec<DirectiveLocation>,
    pub repeatable: bool,
    pub is_extension: bool,
}

impl Named for Directive {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug)]
pub struct Scalar {
    pub name: StringKey,
    pub is_extension: bool,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Object {
    pub name: StringKey,
    pub is_extension: bool,
    pub fields: Vec<FieldID>,
    pub interfaces: Vec<InterfaceID>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct InputObject {
    pub name: StringKey,
    pub fields: ArgumentDefinitions,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Enum {
    pub name: StringKey,
    pub is_extension: bool,
    pub values: Vec<EnumValue>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Union {
    pub name: StringKey,
    pub is_extension: bool,
    pub members: Vec<ObjectID>,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Interface {
    pub name: StringKey,
    pub is_extension: bool,
    pub implementing_objects: Vec<ObjectID>,
    pub fields: Vec<FieldID>,
    pub directives: Vec<DirectiveValue>,
    pub interfaces: Vec<InterfaceID>,
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Field {
    pub name: StringKey,
    pub is_extension: bool,
    pub arguments: ArgumentDefinitions,
    pub type_: TypeReference,
    pub directives: Vec<DirectiveValue>,
    /// The type on which this field was defined. This field is (should)
    /// always be set, except for special fields such as __typename and
    /// __id, which are queryable on all types and therefore don't have
    /// a single parent type.
    pub parent_type: Option<Type>,
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Argument {
    pub name: StringKey,
    pub type_: TypeReference,
    pub default_value: Option<ConstantValue>,
}

impl Named for Argument {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ArgumentValue {
    pub name: StringKey,
    pub value: ConstantValue,
}

impl Named for ArgumentValue {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct DirectiveValue {
    pub name: StringKey,
    pub arguments: Vec<ArgumentValue>,
}

impl Named for DirectiveValue {
    fn name(&self) -> StringKey {
        self.name
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct EnumValue {
    pub value: StringKey,
    pub directives: Vec<DirectiveValue>,
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ArgumentDefinitions(pub(crate) Vec<Argument>);

impl ArgumentDefinitions {
    pub fn new(arguments: Vec<Argument>) -> Self {
        Self(arguments)
    }

    pub fn named(&self, name: StringKey) -> Option<&Argument> {
        self.0.named(name)
    }

    pub fn contains(&self, name: StringKey) -> bool {
        self.0.iter().any(|x| x.name == name)
    }

    pub fn iter(&self) -> Iter<'_, Argument> {
        self.0.iter()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl fmt::Debug for ArgumentDefinitions {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!("{:#?}", self.0))
    }
}

impl IntoIterator for ArgumentDefinitions {
    type Item = Argument;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

pub trait TypeWithFields {
    fn name(&self) -> StringKey;
    fn fields(&self) -> &Vec<FieldID>;
    fn interfaces(&self) -> &Vec<InterfaceID>;
}

impl TypeWithFields for Interface {
    fn name(&self) -> StringKey {
        self.name
    }

    fn fields(&self) -> &Vec<FieldID> {
        &self.fields
    }

    fn interfaces(&self) -> &Vec<InterfaceID> {
        &self.interfaces
    }
}

impl TypeWithFields for Object {
    fn name(&self) -> StringKey {
        self.name
    }

    fn fields(&self) -> &Vec<FieldID> {
        &self.fields
    }

    fn interfaces(&self) -> &Vec<InterfaceID> {
        &self.interfaces
    }
}
<|endoftext|>


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

use context::SharedContext;
use events::*;
use iron::{Iron, Request, Response, IronResult};
use iron::headers::ContentType;
use iron::status::Status;
use router::Router;
use service::{ Service, ServiceAdapter, ServiceProperties };
use std::time::Duration;
use std::thread;
use uuid::Uuid;

struct DummyService {
    properties: ServiceProperties,
    sender: EventSender,
    context: SharedContext,
    dontKill: bool
}

impl DummyService {
    fn new(sender: EventSender, context: SharedContext, id: u32) -> DummyService {
        println!("Creating dummy service");
        let mut ctxClone = context.clone();
        let ctx = ctxClone.lock().unwrap();
        let serviceId = Uuid::new_v4().to_simple_string();
        DummyService {
            properties: ServiceProperties {
                id: serviceId.clone(),
                name: "dummy service".to_string(),
                description: "really nothing to see".to_string(),
                http_url: format!("http://{}:{}/services/{}/", ctx.hostname, ctx.http_port, serviceId),
                ws_url: format!("ws://{}:{}/services/{}/", ctx.hostname, ctx.http_port, serviceId)
            },
            sender: sender,
            context: context,
            dontKill: id % 3 == 0
        }
    }
}

impl Drop for DummyService {
    fn drop(&mut self) {
        println!("Droping DummyService {}", self.properties.id);
    }
}

impl Service for DummyService {
    fn get_properties(&self) -> ServiceProperties {
        self.properties.clone()
    }

    // Starts the service, it will just spawn a thread and get messages once
    // in a while.
    fn start(&self) {
        let sender = self.sender.clone();
        let props = self.properties.clone();
        let canKill = !self.dontKill.clone();
        thread::spawn(move || {
            println!("Hello from dummy service thread!");
            let mut i = 0;
            loop {
                thread::sleep(Duration::from_millis(1000));
                println!("Bip #{} from {}", i, props.id);
                i += 1;
                if i == 3 && canKill {
                    break;
                }
            }
            sender.send(EventData::ServiceStop { id: props.id.to_string() });
        });
    }

    fn stop(&self) {
        println!("Stopping dummy service");
    }

    // Processes a request.
    fn process_request(&self, req: &    Request) -> IronResult<Response> {
        let cmd = req.extensions.get::<Router>().unwrap().find("command").unwrap_or("");
        let mut response = Response::with(format!("Got command {} at url {}", cmd, req.url));
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::plaintext());
        Ok(response)
    }
}

pub struct DummyAdapter {
    name: String,
    sender: EventSender,
    context: SharedContext
}

impl DummyAdapter {
    pub fn new(sender: EventSender,
           context: SharedContext) -> DummyAdapter {
        println!("Creating dummy adapter");
        DummyAdapter { name: "DummyAdapter".to_string(),
                       sender: sender,
                       context: context
                     }
    }
}

impl ServiceAdapter for DummyAdapter {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn start(&self) {
        let sender = self.sender.clone();
        let mut id = 0;
        let context = self.context.clone();
        thread::spawn(move || {
            sender.send(EventData::AdapterStart { name: "Dummy Service Adapter".to_string() });
            loop {
                thread::sleep(Duration::from_millis(2000));
                id += 1;
                let service = DummyService::new(sender.clone(), context.clone(), id);
                let sId = service.get_properties().id;
                service.start();
                let mut ctx = context.lock().unwrap();
                ctx.services.insert(sId.clone(), Box::new(service));
                sender.send(EventData::ServiceStart { id: sId });

                // Create at most 5 dummy services.
                if id == 5 {
                    break;
                }
            }
        });
    }

    fn stop(&self) {
        println!("Stopping dummy adapter");
    }
}
<commit_msg>Fix compiler warnings<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use context::SharedContext;
use events::*;
use iron::{Request, Response, IronResult};
use iron::headers::ContentType;
use iron::status::Status;
use router::Router;
use service::{ Service, ServiceAdapter, ServiceProperties };
use std::time::Duration;
use std::thread;
use uuid::Uuid;

struct DummyService {
    properties: ServiceProperties,
    sender: EventSender,
    dont_kill: bool
}

impl DummyService {
    fn new(sender: EventSender, context: SharedContext, id: u32) -> DummyService {
        println!("Creating dummy service");
        let ctx_clone = context.clone();
        let ctx = ctx_clone.lock().unwrap();
        let service_id = Uuid::new_v4().to_simple_string();
        DummyService {
            properties: ServiceProperties {
                id: service_id.clone(),
                name: "dummy service".to_string(),
                description: "really nothing to see".to_string(),
                http_url: format!("http://{}:{}/services/{}/", ctx.hostname, ctx.http_port, service_id),
                ws_url: format!("ws://{}:{}/services/{}/", ctx.hostname, ctx.http_port, service_id)
            },
            sender: sender,
            dont_kill: id % 3 == 0
        }
    }
}

impl Drop for DummyService {
    fn drop(&mut self) {
        println!("Droping DummyService {}", self.properties.id);
    }
}

impl Service for DummyService {
    fn get_properties(&self) -> ServiceProperties {
        self.properties.clone()
    }

    // Starts the service, it will just spawn a thread and get messages once
    // in a while.
    fn start(&self) {
        let sender = self.sender.clone();
        let props = self.properties.clone();
        let can_kill = !self.dont_kill.clone();
        thread::spawn(move || {
            println!("Hello from dummy service thread!");
            let mut i = 0;
            loop {
                thread::sleep(Duration::from_millis(1000));
                println!("Bip #{} from {}", i, props.id);
                i += 1;
                if i == 3 && can_kill {
                    break;
                }
            }
            sender.send(EventData::ServiceStop { id: props.id.to_string() }).unwrap();
        });
    }

    fn stop(&self) {
        println!("Stopping dummy service");
    }

    // Processes a request.
    fn process_request(&self, req: &    Request) -> IronResult<Response> {
        let cmd = req.extensions.get::<Router>().unwrap().find("command").unwrap_or("");
        let mut response = Response::with(format!("Got command {} at url {}", cmd, req.url));
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::plaintext());
        Ok(response)
    }
}

pub struct DummyAdapter {
    name: String,
    sender: EventSender,
    context: SharedContext
}

impl DummyAdapter {
    pub fn new(sender: EventSender,
           context: SharedContext) -> DummyAdapter {
        println!("Creating dummy adapter");
        DummyAdapter { name: "DummyAdapter".to_string(),
                       sender: sender,
                       context: context
                     }
    }
}

impl ServiceAdapter for DummyAdapter {
    fn get_name(&self) -> String {
        self.name.clone()
    }

    fn start(&self) {
        let sender = self.sender.clone();
        let mut id = 0;
        let context = self.context.clone();
        thread::spawn(move || {
            sender.send(EventData::AdapterStart { name: "Dummy Service Adapter".to_string() }).unwrap();
            loop {
                thread::sleep(Duration::from_millis(2000));
                id += 1;
                let service = DummyService::new(sender.clone(), context.clone(), id);
                let service_id = service.get_properties().id;
                service.start();
                let mut ctx = context.lock().unwrap();
                ctx.services.insert(service_id.clone(), Box::new(service));
                sender.send(EventData::ServiceStart { id: service_id }).unwrap();

                // Create at most 5 dummy services.
                if id == 5 {
                    break;
                }
            }
        });
    }

    fn stop(&self) {
        println!("Stopping dummy adapter");
    }
}
<|endoftext|>


<commit_before>//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.

use std::cmp;
use std::hash::Hasher;
use std::mem;
use std::ptr;
use std::slice;

#[cfg(test)]
mod tests;

#[derive(Debug, Clone)]
pub struct SipHasher128 {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    state: State,  // hash State
    tail: u64,     // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State {
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64,
    v2: u64,
    v1: u64,
    v3: u64,
}

macro_rules! compress {
    ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
        $v0 = $v0.wrapping_add($v1);
        $v1 = $v1.rotate_left(13);
        $v1 ^= $v0;
        $v0 = $v0.rotate_left(32);
        $v2 = $v2.wrapping_add($v3);
        $v3 = $v3.rotate_left(16);
        $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3);
        $v3 = $v3.rotate_left(21);
        $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1);
        $v1 = $v1.rotate_left(17);
        $v1 ^= $v2;
        $v2 = $v2.rotate_left(32);
    }};
}

/// Loads an integer of the desired type from a byte stream, in LE order. Uses
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load it from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
macro_rules! load_int_le {
    ($buf:expr, $i:expr, $int_ty:ident) => {{
        debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
        let mut data = 0 as $int_ty;
        ptr::copy_nonoverlapping(
            $buf.get_unchecked($i),
            &mut data as *mut _ as *mut u8,
            mem::size_of::<$int_ty>(),
        );
        data.to_le()
    }};
}

/// Loads an u64 using up to 7 bytes of a byte slice.
///
/// Unsafe because: unchecked indexing at start..start+len
#[inline]
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
    debug_assert!(len < 8);
    let mut i = 0; // current byte index (from LSB) in the output u64
    let mut out = 0;
    if i + 3 < len {
        out = u64::from(load_int_le!(buf, start + i, u32));
        i += 4;
    }
    if i + 1 < len {
        out |= u64::from(load_int_le!(buf, start + i, u16)) << (i * 8);
        i += 2
    }
    if i < len {
        out |= u64::from(*buf.get_unchecked(start + i)) << (i * 8);
        i += 1;
    }
    debug_assert_eq!(i, len);
    out
}

impl SipHasher128 {
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
        let mut state = SipHasher128 {
            k0: key0,
            k1: key1,
            length: 0,
            state: State { v0: 0, v1: 0, v2: 0, v3: 0 },
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.state.v0 = self.k0 ^ 0x736f6d6570736575;
        self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.state.v2 = self.k0 ^ 0x6c7967656e657261;
        self.state.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;

        // This is only done in the 128 bit version:
        self.state.v1 ^= 0xee;
    }

    // Specialized write function that is only valid for buffers with len <= 8.
    // It's used to force inlining of write_u8 and write_usize, those would normally be inlined
    // except for composite types (that includes slices and str hashing because of delimiter).
    // Without this extra push the compiler is very reluctant to inline delimiter writes,
    // degrading performance substantially for the most common use cases.
    #[inline]
    fn short_write(&mut self, msg: &[u8]) {
        debug_assert!(msg.len() <= 8);
        let length = msg.len();
        self.length += length;

        let needed = 8 - self.ntail;
        let fill = cmp::min(length, needed);
        if fill == 8 {
            self.tail = unsafe { load_int_le!(msg, 0, u64) };
        } else {
            self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
            if length < needed {
                self.ntail += length;
                return;
            }
        }
        self.state.v3 ^= self.tail;
        Sip24Rounds::c_rounds(&mut self.state);
        self.state.v0 ^= self.tail;

        // Buffered tail is now flushed, process new input.
        self.ntail = length - needed;
        self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
    }

    #[inline(always)]
    fn short_write_gen<T>(&mut self, x: T) {
        let bytes =
            unsafe { slice::from_raw_parts(&x as *const T as *const u8, mem::size_of::<T>()) };
        self.short_write(bytes);
    }

    #[inline]
    pub fn finish128(mut self) -> (u64, u64) {
        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        self.state.v3 ^= b;
        Sip24Rounds::c_rounds(&mut self.state);
        self.state.v0 ^= b;

        self.state.v2 ^= 0xee;
        Sip24Rounds::d_rounds(&mut self.state);
        let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;

        self.state.v1 ^= 0xdd;
        Sip24Rounds::d_rounds(&mut self.state);
        let _1 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
        (_0, _1)
    }
}

impl Hasher for SipHasher128 {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_i8(&mut self, i: i8) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_i16(&mut self, i: i16) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_i32(&mut self, i: i32) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_i64(&mut self, i: i64) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write_isize(&mut self, i: isize) {
        self.short_write_gen(i);
    }

    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
            if length < needed {
                self.ntail += length;
                return;
            } else {
                self.state.v3 ^= self.tail;
                Sip24Rounds::c_rounds(&mut self.state);
                self.state.v0 ^= self.tail;
                self.ntail = 0;
            }
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = unsafe { load_int_le!(msg, i, u64) };

            self.state.v3 ^= mi;
            Sip24Rounds::c_rounds(&mut self.state);
            self.state.v0 ^= mi;

            i += 8;
        }

        self.tail = unsafe { u8to64_le(msg, i, left) };
        self.ntail = left;
    }

    fn finish(&self) -> u64 {
        panic!("SipHasher128 cannot provide valid 64 bit hashes")
    }
}

#[derive(Debug, Clone, Default)]
struct Sip24Rounds;

impl Sip24Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
        compress!(state);
    }
}
<commit_msg>Rollup merge of #68914 - nnethercote:speed-up-SipHasher128, r=michaelwoerister<commit_after>//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.

use std::cmp;
use std::hash::Hasher;
use std::mem;
use std::ptr;

#[cfg(test)]
mod tests;

#[derive(Debug, Clone)]
pub struct SipHasher128 {
    k0: u64,
    k1: u64,
    length: usize, // how many bytes we've processed
    state: State,  // hash State
    tail: u64,     // unprocessed bytes le
    ntail: usize,  // how many bytes in tail are valid
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State {
    // v0, v2 and v1, v3 show up in pairs in the algorithm,
    // and simd implementations of SipHash will use vectors
    // of v02 and v13. By placing them in this order in the struct,
    // the compiler can pick up on just a few simd optimizations by itself.
    v0: u64,
    v2: u64,
    v1: u64,
    v3: u64,
}

macro_rules! compress {
    ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
        $v0 = $v0.wrapping_add($v1);
        $v1 = $v1.rotate_left(13);
        $v1 ^= $v0;
        $v0 = $v0.rotate_left(32);
        $v2 = $v2.wrapping_add($v3);
        $v3 = $v3.rotate_left(16);
        $v3 ^= $v2;
        $v0 = $v0.wrapping_add($v3);
        $v3 = $v3.rotate_left(21);
        $v3 ^= $v0;
        $v2 = $v2.wrapping_add($v1);
        $v1 = $v1.rotate_left(17);
        $v1 ^= $v2;
        $v2 = $v2.rotate_left(32);
    }};
}

/// Loads up to 8 bytes from a byte-slice into a little-endian u64.
#[inline]
fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
    assert!(len <= 8 && start + len <= buf.len());

    let mut out = 0u64;
    unsafe {
        let out_ptr = &mut out as *mut _ as *mut u8;
        ptr::copy_nonoverlapping(buf.as_ptr().offset(start as isize), out_ptr, len);
    }
    out.to_le()
}

impl SipHasher128 {
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
        let mut state = SipHasher128 {
            k0: key0,
            k1: key1,
            length: 0,
            state: State { v0: 0, v1: 0, v2: 0, v3: 0 },
            tail: 0,
            ntail: 0,
        };
        state.reset();
        state
    }

    #[inline]
    fn reset(&mut self) {
        self.length = 0;
        self.state.v0 = self.k0 ^ 0x736f6d6570736575;
        self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.state.v2 = self.k0 ^ 0x6c7967656e657261;
        self.state.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;

        // This is only done in the 128 bit version:
        self.state.v1 ^= 0xee;
    }

    // A specialized write function for values with size <= 8.
    //
    // The hashing of multi-byte integers depends on endianness. E.g.:
    // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])`
    // - big-endian:    `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])`
    //
    // This function does the right thing for little-endian hardware. On
    // big-endian hardware `x` must be byte-swapped first to give the right
    // behaviour. After any byte-swapping, the input must be zero-extended to
    // 64-bits. The caller is responsible for the byte-swapping and
    // zero-extension.
    #[inline]
    fn short_write<T>(&mut self, _x: T, x: u64) {
        let size = mem::size_of::<T>();
        self.length += size;

        // The original number must be zero-extended, not sign-extended.
        debug_assert!(if size < 8 { x >> (8 * size) == 0 } else { true });

        // The number of bytes needed to fill `self.tail`.
        let needed = 8 - self.ntail;

        // SipHash parses the input stream as 8-byte little-endian integers.
        // Inputs are put into `self.tail` until 8 bytes of data have been
        // collected, and then that word is processed.
        //
        // For example, imagine that `self.tail` is 0x0000_00EE_DDCC_BBAA,
        // `self.ntail` is 5 (because 5 bytes have been put into `self.tail`),
        // and `needed` is therefore 3.
        //
        // - Scenario 1, `self.write_u8(0xFF)`: we have already zero-extended
        //   the input to 0x0000_0000_0000_00FF. We now left-shift it five
        //   bytes, giving 0x0000_FF00_0000_0000. We then bitwise-OR that value
        //   into `self.tail`, resulting in 0x0000_FFEE_DDCC_BBAA.
        //   (Zero-extension of the original input is critical in this scenario
        //   because we don't want the high two bytes of `self.tail` to be
        //   touched by the bitwise-OR.) `self.tail` is not yet full, so we
        //   return early, after updating `self.ntail` to 6.
        //
        // - Scenario 2, `self.write_u32(0xIIHH_GGFF)`: we have already
        //   zero-extended the input to 0x0000_0000_IIHH_GGFF. We now
        //   left-shift it five bytes, giving 0xHHGG_FF00_0000_0000. We then
        //   bitwise-OR that value into `self.tail`, resulting in
        //   0xHHGG_FFEE_DDCC_BBAA. `self.tail` is now full, and we can use it
        //   to update `self.state`. (As mentioned above, this assumes a
        //   little-endian machine; on a big-endian machine we would have
        //   byte-swapped 0xIIHH_GGFF in the caller, giving 0xFFGG_HHII, and we
        //   would then end up bitwise-ORing 0xGGHH_II00_0000_0000 into
        //   `self.tail`).
        //
        self.tail |= x << (8 * self.ntail);
        if size < needed {
            self.ntail += size;
            return;
        }

        // `self.tail` is full, process it.
        self.state.v3 ^= self.tail;
        Sip24Rounds::c_rounds(&mut self.state);
        self.state.v0 ^= self.tail;

        // Continuing scenario 2: we have one byte left over from the input. We
        // set `self.ntail` to 1 and `self.tail` to `0x0000_0000_IIHH_GGFF >>
        // 8*3`, which is 0x0000_0000_0000_00II. (Or on a big-endian machine
        // the prior byte-swapping would leave us with 0x0000_0000_0000_00FF.)
        //
        // The `if` is needed to avoid shifting by 64 bits, which Rust
        // complains about.
        self.ntail = size - needed;
        self.tail = if needed < 8 { x >> (8 * needed) } else { 0 };
    }

    #[inline]
    pub fn finish128(mut self) -> (u64, u64) {
        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        self.state.v3 ^= b;
        Sip24Rounds::c_rounds(&mut self.state);
        self.state.v0 ^= b;

        self.state.v2 ^= 0xee;
        Sip24Rounds::d_rounds(&mut self.state);
        let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;

        self.state.v1 ^= 0xdd;
        Sip24Rounds::d_rounds(&mut self.state);
        let _1 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
        (_0, _1)
    }
}

impl Hasher for SipHasher128 {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.short_write(i, i as u64);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.short_write(i, i.to_le() as u64);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.short_write(i, i.to_le() as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.short_write(i, i.to_le() as u64);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.short_write(i, i.to_le() as u64);
    }

    #[inline]
    fn write_i8(&mut self, i: i8) {
        self.short_write(i, i as u8 as u64);
    }

    #[inline]
    fn write_i16(&mut self, i: i16) {
        self.short_write(i, (i as u16).to_le() as u64);
    }

    #[inline]
    fn write_i32(&mut self, i: i32) {
        self.short_write(i, (i as u32).to_le() as u64);
    }

    #[inline]
    fn write_i64(&mut self, i: i64) {
        self.short_write(i, (i as u64).to_le() as u64);
    }

    #[inline]
    fn write_isize(&mut self, i: isize) {
        self.short_write(i, (i as usize).to_le() as u64);
    }

    #[inline]
    fn write(&mut self, msg: &[u8]) {
        let length = msg.len();
        self.length += length;

        let mut needed = 0;

        if self.ntail != 0 {
            needed = 8 - self.ntail;
            self.tail |= u8to64_le(msg, 0, cmp::min(length, needed)) << (8 * self.ntail);
            if length < needed {
                self.ntail += length;
                return;
            } else {
                self.state.v3 ^= self.tail;
                Sip24Rounds::c_rounds(&mut self.state);
                self.state.v0 ^= self.tail;
                self.ntail = 0;
            }
        }

        // Buffered tail is now flushed, process new input.
        let len = length - needed;
        let left = len & 0x7;

        let mut i = needed;
        while i < len - left {
            let mi = u8to64_le(msg, i, 8);

            self.state.v3 ^= mi;
            Sip24Rounds::c_rounds(&mut self.state);
            self.state.v0 ^= mi;

            i += 8;
        }

        self.tail = u8to64_le(msg, i, left);
        self.ntail = left;
    }

    fn finish(&self) -> u64 {
        panic!("SipHasher128 cannot provide valid 64 bit hashes")
    }
}

#[derive(Debug, Clone, Default)]
struct Sip24Rounds;

impl Sip24Rounds {
    #[inline]
    fn c_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
    }

    #[inline]
    fn d_rounds(state: &mut State) {
        compress!(state);
        compress!(state);
        compress!(state);
        compress!(state);
    }
}
<|endoftext|>