<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::conversion::analysis::fun::{ArgumentAnalysis, ReceiverMutability};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use std::borrow::Cow;
use syn::{
    parse_quote, punctuated::Punctuated, token::Comma, FnArg, GenericArgument, PatType, Path,
    PathSegment, ReturnType, Type, TypePath,
};

/// Function which can add explicit lifetime parameters to function signatures
/// where necessary, based on analysis of parameters and return types.
/// This is necessary only in one case - where the parameter is a Pin<&mut T>
/// and the return type is some kind of reference - because lifetime elision
/// is not smart enough to see inside a Pin.
pub(crate) fn add_explicit_lifetime_if_necessary<'r>(
    param_details: &[ArgumentAnalysis],
    mut params: Punctuated<FnArg, Comma>,
    ret_type: &'r ReturnType,
) -> (
    Option<TokenStream>,
    Punctuated<FnArg, Comma>,
    Cow<'r, ReturnType>,
) {
    let has_mutable_receiver = param_details
        .iter()
        .any(|pd| matches!(pd.self_type, Some((_, ReceiverMutability::Mutable))));
    if !has_mutable_receiver {
        return (None, params, Cow::Borrowed(ret_type));
    }
    let new_return_type = match ret_type {
        ReturnType::Type(rarrow, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => {
                let mut new_rtr = rtr.clone();
                new_rtr.lifetime = Some(parse_quote! { 'a });
                Some(ReturnType::Type(
                    *rarrow,
                    Box::new(Type::Reference(new_rtr)),
                ))
            }
            Type::Path(typ) => {
                let mut new_path = typ.clone();
                add_lifetime_to_pinned_reference(&mut new_path.path.segments)
                    .ok()
                    .map(|_| ReturnType::Type(*rarrow, Box::new(Type::Path(new_path))))
            }
            _ => None,
        },
        _ => None,
    };

    match new_return_type {
        None => (None, params, Cow::Borrowed(ret_type)),
        Some(new_return_type) => {
            for mut param in params.iter_mut() {
                match &mut param {
                    FnArg::Typed(PatType { ty, .. }) => match ty.as_mut() {
                        Type::Path(TypePath {
                            path: Path { segments, .. },
                            ..
                        }) => add_lifetime_to_pinned_reference(segments).unwrap(),
                        _ => panic!("Expected Pin<T>"),
                    },
                    _ => panic!("Unexpected fnarg"),
                }
            }

            (Some(quote! { <'a> }), params, Cow::Owned(new_return_type))
        }
    }
}

#[derive(Debug)]
enum AddLifetimeError {
    WasNotPin,
}

fn add_lifetime_to_pinned_reference(
    segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
) -> Result<(), AddLifetimeError> {
    static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
        ("std", false),
        ("pin", false),
        ("Pin", true), // true = act on the arguments of this segment
    ];

    for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
        if seg.ident != expected_name {
            return Err(AddLifetimeError::WasNotPin);
        }
        if *act {
            match &mut seg.arguments {
                syn::PathArguments::AngleBracketed(aba) => match aba.args.iter_mut().next() {
                    Some(GenericArgument::Type(Type::Reference(tyr))) => {
                        add_lifetime_to_reference(tyr);
                    }
                    _ => panic!("Expected generic args with a reference"),
                },
                _ => panic!("Expected angle bracketed args"),
            }
        }
    }
    Ok(())
}

fn add_lifetime_to_reference(tyr: &mut syn::TypeReference) {
    tyr.lifetime = Some(parse_quote! { 'a })
}

pub(crate) fn add_lifetime_to_all_params(params: &mut Punctuated<FnArg, Comma>) {
    for mut param in params.iter_mut() {
        match &mut param {
            FnArg::Typed(PatType { ty, .. }) => match ty.as_mut() {
                Type::Path(TypePath {
                    path: Path { segments, .. },
                    ..
                }) => add_lifetime_to_pinned_reference(segments).unwrap(),
                Type::Reference(tyr) => add_lifetime_to_reference(tyr),
                _ => {}
            },
            _ => panic!("Unexpected fnarg"),
        }
    }
}
<commit_msg>Remove unused import.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::conversion::analysis::fun::{ArgumentAnalysis, ReceiverMutability};
use proc_macro2::TokenStream;
use quote::quote;
use std::borrow::Cow;
use syn::{
    parse_quote, punctuated::Punctuated, token::Comma, FnArg, GenericArgument, PatType, Path,
    PathSegment, ReturnType, Type, TypePath,
};

/// Function which can add explicit lifetime parameters to function signatures
/// where necessary, based on analysis of parameters and return types.
/// This is necessary only in one case - where the parameter is a Pin<&mut T>
/// and the return type is some kind of reference - because lifetime elision
/// is not smart enough to see inside a Pin.
pub(crate) fn add_explicit_lifetime_if_necessary<'r>(
    param_details: &[ArgumentAnalysis],
    mut params: Punctuated<FnArg, Comma>,
    ret_type: &'r ReturnType,
) -> (
    Option<TokenStream>,
    Punctuated<FnArg, Comma>,
    Cow<'r, ReturnType>,
) {
    let has_mutable_receiver = param_details
        .iter()
        .any(|pd| matches!(pd.self_type, Some((_, ReceiverMutability::Mutable))));
    if !has_mutable_receiver {
        return (None, params, Cow::Borrowed(ret_type));
    }
    let new_return_type = match ret_type {
        ReturnType::Type(rarrow, boxed_type) => match boxed_type.as_ref() {
            Type::Reference(rtr) => {
                let mut new_rtr = rtr.clone();
                new_rtr.lifetime = Some(parse_quote! { 'a });
                Some(ReturnType::Type(
                    *rarrow,
                    Box::new(Type::Reference(new_rtr)),
                ))
            }
            Type::Path(typ) => {
                let mut new_path = typ.clone();
                add_lifetime_to_pinned_reference(&mut new_path.path.segments)
                    .ok()
                    .map(|_| ReturnType::Type(*rarrow, Box::new(Type::Path(new_path))))
            }
            _ => None,
        },
        _ => None,
    };

    match new_return_type {
        None => (None, params, Cow::Borrowed(ret_type)),
        Some(new_return_type) => {
            for mut param in params.iter_mut() {
                match &mut param {
                    FnArg::Typed(PatType { ty, .. }) => match ty.as_mut() {
                        Type::Path(TypePath {
                            path: Path { segments, .. },
                            ..
                        }) => add_lifetime_to_pinned_reference(segments).unwrap(),
                        _ => panic!("Expected Pin<T>"),
                    },
                    _ => panic!("Unexpected fnarg"),
                }
            }

            (Some(quote! { <'a> }), params, Cow::Owned(new_return_type))
        }
    }
}

#[derive(Debug)]
enum AddLifetimeError {
    WasNotPin,
}

fn add_lifetime_to_pinned_reference(
    segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
) -> Result<(), AddLifetimeError> {
    static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
        ("std", false),
        ("pin", false),
        ("Pin", true), // true = act on the arguments of this segment
    ];

    for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
        if seg.ident != expected_name {
            return Err(AddLifetimeError::WasNotPin);
        }
        if *act {
            match &mut seg.arguments {
                syn::PathArguments::AngleBracketed(aba) => match aba.args.iter_mut().next() {
                    Some(GenericArgument::Type(Type::Reference(tyr))) => {
                        add_lifetime_to_reference(tyr);
                    }
                    _ => panic!("Expected generic args with a reference"),
                },
                _ => panic!("Expected angle bracketed args"),
            }
        }
    }
    Ok(())
}

fn add_lifetime_to_reference(tyr: &mut syn::TypeReference) {
    tyr.lifetime = Some(parse_quote! { 'a })
}

pub(crate) fn add_lifetime_to_all_params(params: &mut Punctuated<FnArg, Comma>) {
    for mut param in params.iter_mut() {
        match &mut param {
            FnArg::Typed(PatType { ty, .. }) => match ty.as_mut() {
                Type::Path(TypePath {
                    path: Path { segments, .. },
                    ..
                }) => add_lifetime_to_pinned_reference(segments).unwrap(),
                Type::Reference(tyr) => add_lifetime_to_reference(tyr),
                _ => {}
            },
            _ => panic!("Unexpected fnarg"),
        }
    }
}
<|endoftext|>


<commit_before>use cf = core_foundation;
use cf::base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFIndex,
    CFRelease,
    CFTypeID,
    CFTypeRef,
};

use libc::{c_void, c_char, size_t};

pub type CGDataProviderGetBytesCallback = *u8;
pub type CGDataProviderReleaseInfoCallback = *u8;
pub type CGDataProviderRewindCallback = *u8;
pub type CGDataProviderSkipBytesCallback = *u8;
pub type CGDataProviderSkipForwardCallback = *u8;

pub type CGDataProviderGetBytePointerCallback = *u8;
pub type CGDataProviderGetBytesAtOffsetCallback = *u8;
pub type CGDataProviderReleaseBytePointerCallback = *u8;
pub type CGDataProviderReleaseDataCallback = *u8;
pub type CGDataProviderGetBytesAtPositionCallback = *u8;

struct __CGDataProvider { private: () }
pub type CGDataProviderRef = *__CGDataProvider;

pub impl CGDataProviderRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

pub struct CGDataProvider {
    obj: CGDataProviderRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl CGDataProvider : AbstractCFType<CGDataProviderRef> {
    pure fn get_ref() -> CGDataProviderRef { self.obj }

    static fn wrap(obj: CGDataProviderRef) -> CGDataProvider {
        CGDataProvider { obj: obj }
    }

    static fn unwrap(wrapper: CGDataProvider) -> CGDataProviderRef {
        wrapper.obj
    }
}

pub impl CGDataProvider {
    static fn new_from_buffer(buf: *u8, len: uint) -> CGDataProvider unsafe {
        let obj = CGDataProviderCreateWithData(
            ptr::null(),
            cast::transmute(buf),
            len as size_t,
            ptr::null());

        return cf::base::wrap(obj);
    }
}

#[nolink]
#[link_args="-framework ApplicationServices"]
pub extern {
    //fn CGDataProviderCopyData
    //fn CGDataProviderCreateDirect
    //fn CGDataProviderCreateSequential
    //fn CGDataProviderCreateWithCFData
    fn CGDataProviderCreateWithData(info: *c_void,
                                    data: *c_void,
                                    size: size_t,
                                    releaseData: CGDataProviderReleaseDataCallback
                                   ) -> CGDataProviderRef;
    fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef;
    //fn CGDataProviderCreateWithURL
    fn CGDataProviderGetTypeID() -> CFTypeID;
    fn CGDataProviderRelease(provider: CGDataProviderRef);
    fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
}
<commit_msg>Rewrite the Core Foundation wrapper system.<commit_after>use cf = core_foundation;
use cf::base::{
    AbstractCFTypeRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
};

use libc::{c_void, c_char, size_t};

pub type CGDataProviderGetBytesCallback = *u8;
pub type CGDataProviderReleaseInfoCallback = *u8;
pub type CGDataProviderRewindCallback = *u8;
pub type CGDataProviderSkipBytesCallback = *u8;
pub type CGDataProviderSkipForwardCallback = *u8;

pub type CGDataProviderGetBytePointerCallback = *u8;
pub type CGDataProviderGetBytesAtOffsetCallback = *u8;
pub type CGDataProviderReleaseBytePointerCallback = *u8;
pub type CGDataProviderReleaseDataCallback = *u8;
pub type CGDataProviderGetBytesAtPositionCallback = *u8;

struct __CGDataProvider { private: () }
pub type CGDataProviderRef = *__CGDataProvider;

pub impl CGDataProviderRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

pub type CGDataProvider = CFWrapper<CGDataProviderRef, (), ()>;

pub trait CGDataProviderMethods {
    static fn new_from_buffer(buf: *u8, len: uint) -> CGDataProvider;
}

pub impl CGDataProvider : CGDataProviderMethods {
    static fn new_from_buffer(buf: *u8, len: uint) -> CGDataProvider unsafe {
        let result = CGDataProviderCreateWithData(
            ptr::null(),
            cast::transmute(buf),
            len as size_t,
            ptr::null());

        CFWrapper::wrap_owned(result)
    }
}

#[nolink]
#[link_args="-framework ApplicationServices"]
pub extern {
    //fn CGDataProviderCopyData
    //fn CGDataProviderCreateDirect
    //fn CGDataProviderCreateSequential
    //fn CGDataProviderCreateWithCFData
    fn CGDataProviderCreateWithData(info: *c_void,
                                    data: *c_void,
                                    size: size_t,
                                    releaseData: CGDataProviderReleaseDataCallback
                                   ) -> CGDataProviderRef;
    fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef;
    //fn CGDataProviderCreateWithURL
    fn CGDataProviderGetTypeID() -> CFTypeID;
    fn CGDataProviderRelease(provider: CGDataProviderRef);
    fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use rustc_hash::FxHashSet;

use ra_syntax::ast::{AstNode, StructLit};

use crate::{
    expr::AstPtr,
    HirDatabase,
    Function,
    Name,
    diagnostics::{DiagnosticSink, MissingFields},
    adt::AdtDef,
    Path,
    ty::InferenceResult
};
use super::{Expr, StructLitField, ExprId};

pub(crate) struct ExprValidator<'a, 'b: 'a> {
    func: Function,
    infer: Arc<InferenceResult>,
    sink: &'a mut DiagnosticSink<'b>,
}

impl<'a, 'b> ExprValidator<'a, 'b> {
    pub(crate) fn new(
        func: Function,
        infer: Arc<InferenceResult>,
        sink: &'a mut DiagnosticSink<'b>,
    ) -> ExprValidator<'a, 'b> {
        ExprValidator { func, infer, sink }
    }

    pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
        let body = self.func.body(db);
        for e in body.exprs() {
            match e {
                (id, Expr::StructLit { path, fields, spread }) => {
                    self.validate_struct_literal(id, path, fields, spread, db)
                }
                _ => (),
            }
        }
    }

    fn validate_struct_literal(
        &mut self,
        id: ExprId,
        _path: &Option<Path>,
        fields: &Vec<StructLitField>,
        spread: &Option<ExprId>,
        db: &impl HirDatabase,
    ) {
        if let Some(_) = spread {
            return;
        }
        let lit_fields: FxHashSet<_> = fields.into_iter().map(|f| &f.name).collect();
        let struct_ty = &self.infer[id];
        if let Some((AdtDef::Struct(s), _)) = struct_ty.as_adt() {
            let missed_fields: Vec<Name> = s
                .fields(db)
                .iter()
                .filter_map(|f| {
                    let name = f.name(db);
                    if lit_fields.contains(&name) {
                        None
                    } else {
                        Some(name)
                    }
                })
                .collect();
            if missed_fields.is_empty() {
                return;
            }
            let source_map = self.func.body_source_map(db);
            let file_id = self.func.source(db).0;
            let source_file = db.parse(file_id.original_file(db));
            if let Some(field_list_node) = source_map
                .expr_syntax(id)
                .map(|ptr| ptr.to_node(source_file.syntax()))
                .and_then(StructLit::cast)
                .and_then(|lit| lit.named_field_list())
            {
                let field_list_ptr = AstPtr::new(field_list_node);
                self.sink.push(MissingFields {
                    file: file_id,
                    field_list: field_list_ptr,
                    missed_fields,
                })
            }
        }
    }
}
<commit_msg>simplify<commit_after>use std::sync::Arc;
use rustc_hash::FxHashSet;

use ra_syntax::ast::{AstNode, StructLit};

use crate::{
    expr::AstPtr,
    HirDatabase, Function, Name,
    diagnostics::{DiagnosticSink, MissingFields},
    adt::AdtDef,
    Path,
    ty::InferenceResult,
};
use super::{Expr, StructLitField, ExprId};

pub(crate) struct ExprValidator<'a, 'b: 'a> {
    func: Function,
    infer: Arc<InferenceResult>,
    sink: &'a mut DiagnosticSink<'b>,
}

impl<'a, 'b> ExprValidator<'a, 'b> {
    pub(crate) fn new(
        func: Function,
        infer: Arc<InferenceResult>,
        sink: &'a mut DiagnosticSink<'b>,
    ) -> ExprValidator<'a, 'b> {
        ExprValidator { func, infer, sink }
    }

    pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
        let body = self.func.body(db);
        for e in body.exprs() {
            match e {
                (id, Expr::StructLit { path, fields, spread }) => {
                    self.validate_struct_literal(id, path, fields, spread, db)
                }
                _ => (),
            }
        }
    }

    fn validate_struct_literal(
        &mut self,
        id: ExprId,
        _path: &Option<Path>,
        fields: &Vec<StructLitField>,
        spread: &Option<ExprId>,
        db: &impl HirDatabase,
    ) {
        if spread.is_some() {
            return;
        }

        let struct_def = match self.infer[id].as_adt() {
            Some((AdtDef::Struct(s), _)) => s,
            _ => return,
        };

        let lit_fields: FxHashSet<_> = fields.into_iter().map(|f| &f.name).collect();
        let missed_fields: Vec<Name> = struct_def
            .fields(db)
            .iter()
            .filter_map(|f| {
                let name = f.name(db);
                if lit_fields.contains(&name) {
                    None
                } else {
                    Some(name)
                }
            })
            .collect();
        if missed_fields.is_empty() {
            return;
        }
        let source_map = self.func.body_source_map(db);
        let file_id = self.func.source(db).0;
        let source_file = db.parse(file_id.original_file(db));
        if let Some(field_list_node) = source_map
            .expr_syntax(id)
            .map(|ptr| ptr.to_node(source_file.syntax()))
            .and_then(StructLit::cast)
            .and_then(|lit| lit.named_field_list())
        {
            let field_list_ptr = AstPtr::new(field_list_node);
            self.sink.push(MissingFields {
                file: file_id,
                field_list: field_list_ptr,
                missed_fields,
            })
        }
    }
}
<|endoftext|>


<commit_before>//! Conversion code from/to Chalk.
use std::sync::Arc;

use log::debug;

use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};

use ra_db::salsa::{InternId, InternKey};

use crate::{
    Trait, HasGenericParams, ImplBlock,
    db::HirDatabase,
    ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs},
};
use super::ChalkContext;

pub(super) trait ToChalk {
    type Chalk;
    fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
    fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self;
}

pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
where
    T: ToChalk<Chalk = ChalkT>,
{
    T::from_chalk(db, chalk)
}

impl ToChalk for Ty {
    type Chalk = chalk_ir::Ty;
    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
        match self {
            Ty::Apply(apply_ty) => chalk_ir::Ty::Apply(apply_ty.to_chalk(db)),
            Ty::Param { idx, .. } => {
                PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
            }
            Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
            Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
            // FIXME this is clearly incorrect, but probably not too incorrect
            // and I'm not sure what to actually do with Ty::Unknown
            Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(),
        }
    }
    fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
        match chalk {
            chalk_ir::Ty::Apply(apply_ty) => {
                match apply_ty.name {
                    // FIXME handle TypeKindId::Trait/Type here
                    TypeName::TypeKindId(_) => Ty::Apply(from_chalk(db, apply_ty)),
                    TypeName::AssociatedType(_) => unimplemented!(),
                    TypeName::Placeholder(idx) => {
                        assert_eq!(idx.ui, UniverseIndex::ROOT);
                        Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
                    }
                }
            }
            chalk_ir::Ty::Projection(_) => unimplemented!(),
            chalk_ir::Ty::UnselectedProjection(_) => unimplemented!(),
            chalk_ir::Ty::ForAll(_) => unimplemented!(),
            chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
            chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
        }
    }
}

// TODO merge this into the ToChalk implementation for Ty
impl ToChalk for ApplicationTy {
    type Chalk = chalk_ir::ApplicationTy;

    fn to_chalk(self: ApplicationTy, db: &impl HirDatabase) -> chalk_ir::ApplicationTy {
        let struct_id = self.ctor.to_chalk(db);
        let name = TypeName::TypeKindId(struct_id.into());
        let parameters = self.parameters.to_chalk(db);
        chalk_ir::ApplicationTy { name, parameters }
    }

    fn from_chalk(db: &impl HirDatabase, apply_ty: chalk_ir::ApplicationTy) -> ApplicationTy {
        let ctor = match apply_ty.name {
            TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => from_chalk(db, struct_id),
            TypeName::TypeKindId(_) => unimplemented!(),
            TypeName::Placeholder(_) => unimplemented!(),
            TypeName::AssociatedType(_) => unimplemented!(),
        };
        let parameters = from_chalk(db, apply_ty.parameters);
        ApplicationTy { ctor, parameters }
    }
}

impl ToChalk for Substs {
    type Chalk = Vec<chalk_ir::Parameter>;

    fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> {
        self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
    }

    fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
        parameters
            .into_iter()
            .map(|p| match p {
                chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
                chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
            })
            .collect::<Vec<_>>()
            .into()
    }
}

impl ToChalk for TraitRef {
    type Chalk = chalk_ir::TraitRef;

    fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef {
        let trait_id = self.trait_.to_chalk(db);
        let parameters = self.substs.to_chalk(db);
        chalk_ir::TraitRef { trait_id, parameters }
    }

    fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self {
        let trait_ = from_chalk(db, trait_ref.trait_id);
        let substs = from_chalk(db, trait_ref.parameters);
        TraitRef { trait_, substs }
    }
}

impl ToChalk for Trait {
    type Chalk = chalk_ir::TraitId;

    fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
        self.id.into()
    }

    fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
        Trait { id: trait_id.into() }
    }
}

impl ToChalk for TypeCtor {
    type Chalk = chalk_ir::StructId;

    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId {
        db.intern_type_ctor(self).into()
    }

    fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor {
        db.lookup_intern_type_ctor(struct_id.into())
    }
}

impl ToChalk for ImplBlock {
    type Chalk = chalk_ir::ImplId;

    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
        db.intern_impl_block(self).into()
    }

    fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
        db.lookup_intern_impl_block(impl_id.into())
    }
}

fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
    chalk_ir::Binders {
        value,
        binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
    }
}

impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
where
    DB: HirDatabase,
{
    fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> {
        unimplemented!()
    }
    fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
        debug!("trait_datum {:?}", trait_id);
        let trait_: Trait = from_chalk(self.db, trait_id);
        let generic_params = trait_.generic_params(self.db);
        let bound_vars = Substs::bound_vars(&generic_params);
        let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
        let flags = chalk_rust_ir::TraitFlags {
            // FIXME set these flags correctly
            auto: false,
            marker: false,
            upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
            fundamental: false,
        };
        let where_clauses = Vec::new(); // FIXME add where clauses
        let associated_ty_ids = Vec::new(); // FIXME add associated tys
        let trait_datum_bound =
            chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
        let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
        Arc::new(trait_datum)
    }
    fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
        debug!("struct_datum {:?}", struct_id);
        let type_ctor = from_chalk(self.db, struct_id);
        // TODO might be nicer if we can create a fake GenericParams for the TypeCtor
        let (num_params, upstream) = match type_ctor {
            TypeCtor::Bool
            | TypeCtor::Char
            | TypeCtor::Int(_)
            | TypeCtor::Float(_)
            | TypeCtor::Never
            | TypeCtor::Str => (0, true),
            TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true),
            TypeCtor::FnPtr | TypeCtor::Tuple => unimplemented!(), // FIXME tuples and FnPtr are currently variadic... we need to make the parameter number explicit
            TypeCtor::FnDef(_) => unimplemented!(),
            TypeCtor::Adt(adt) => {
                let generic_params = adt.generic_params(self.db);
                (
                    generic_params.count_params_including_parent(),
                    adt.krate(self.db) != Some(self.krate),
                )
            }
        };
        let flags = chalk_rust_ir::StructFlags {
            upstream,
            // FIXME set fundamental flag correctly
            fundamental: false,
        };
        let where_clauses = Vec::new(); // FIXME add where clauses
        let ty = ApplicationTy {
            ctor: type_ctor,
            parameters: (0..num_params).map(|i| Ty::Bound(i as u32)).collect::<Vec<_>>().into(),
        };
        let struct_datum_bound = chalk_rust_ir::StructDatumBound {
            self_ty: ty.to_chalk(self.db),
            fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
            where_clauses,
            flags,
        };
        let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) };
        Arc::new(struct_datum)
    }
    fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
        debug!("impl_datum {:?}", impl_id);
        let impl_block: ImplBlock = from_chalk(self.db, impl_id);
        let generic_params = impl_block.generic_params(self.db);
        let bound_vars = Substs::bound_vars(&generic_params);
        let trait_ref = impl_block
            .target_trait_ref(self.db)
            .expect("FIXME handle unresolved impl block trait ref")
            .subst(&bound_vars);
        let impl_type = if impl_block.module().krate(self.db) == Some(self.krate) {
            chalk_rust_ir::ImplType::Local
        } else {
            chalk_rust_ir::ImplType::External
        };
        let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
            // FIXME handle negative impls (impl !Sync for Foo)
            trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)),
            where_clauses: Vec::new(),        // FIXME add where clauses
            associated_ty_values: Vec::new(), // FIXME add associated type values
            impl_type,
        };
        let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
        Arc::new(impl_datum)
    }
    fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
        debug!("impls_for_trait {:?}", trait_id);
        let trait_ = from_chalk(self.db, trait_id);
        self.db
            .impls_for_trait(self.krate, trait_)
            .iter()
            // FIXME temporary hack -- as long as we're not lowering where clauses
            // correctly, ignore impls with them completely so as to not treat
            // impl<T> Trait for T where T: ... as a blanket impl on all types
            .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
            .map(|impl_block| impl_block.to_chalk(self.db))
            .collect()
    }
    fn impl_provided_for(
        &self,
        auto_trait_id: chalk_ir::TraitId,
        struct_id: chalk_ir::StructId,
    ) -> bool {
        debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
        false // FIXME
    }
    fn type_name(&self, _id: TypeKindId) -> Identifier {
        unimplemented!()
    }
    fn split_projection<'p>(
        &self,
        projection: &'p ProjectionTy,
    ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
        debug!("split_projection {:?}", projection);
        unimplemented!()
    }
    fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
        debug!("custom_clauses");
        vec![]
    }
    fn all_structs(&self) -> Vec<chalk_ir::StructId> {
        debug!("all_structs");
        // FIXME
        vec![]
    }
}

fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
    T::from_intern_id(InternId::from(chalk_id.index))
}
fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
    chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
}

impl From<chalk_ir::TraitId> for crate::ids::TraitId {
    fn from(trait_id: chalk_ir::TraitId) -> Self {
        id_from_chalk(trait_id.0)
    }
}

impl From<crate::ids::TraitId> for chalk_ir::TraitId {
    fn from(trait_id: crate::ids::TraitId) -> Self {
        chalk_ir::TraitId(id_to_chalk(trait_id))
    }
}

impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
    fn from(struct_id: chalk_ir::StructId) -> Self {
        id_from_chalk(struct_id.0)
    }
}

impl From<crate::ids::TypeCtorId> for chalk_ir::StructId {
    fn from(type_ctor_id: crate::ids::TypeCtorId) -> Self {
        chalk_ir::StructId(id_to_chalk(type_ctor_id))
    }
}

impl From<chalk_ir::ImplId> for crate::ids::GlobalImplId {
    fn from(impl_id: chalk_ir::ImplId) -> Self {
        id_from_chalk(impl_id.0)
    }
}

impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
    fn from(impl_id: crate::ids::GlobalImplId) -> Self {
        chalk_ir::ImplId(id_to_chalk(impl_id))
    }
}
<commit_msg>Remove ToChalk implementation for ApplicationTy<commit_after>//! Conversion code from/to Chalk.
use std::sync::Arc;

use log::debug;

use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};

use ra_db::salsa::{InternId, InternKey};

use crate::{
    Trait, HasGenericParams, ImplBlock,
    db::HirDatabase,
    ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs},
};
use super::ChalkContext;

pub(super) trait ToChalk {
    type Chalk;
    fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
    fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self;
}

pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
where
    T: ToChalk<Chalk = ChalkT>,
{
    T::from_chalk(db, chalk)
}

impl ToChalk for Ty {
    type Chalk = chalk_ir::Ty;
    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
        match self {
            Ty::Apply(apply_ty) => {
                let struct_id = apply_ty.ctor.to_chalk(db);
                let name = TypeName::TypeKindId(struct_id.into());
                let parameters = apply_ty.parameters.to_chalk(db);
                chalk_ir::ApplicationTy { name, parameters }.cast()
            }
            Ty::Param { idx, .. } => {
                PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
            }
            Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
            Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
            // FIXME this is clearly incorrect, but probably not too incorrect
            // and I'm not sure what to actually do with Ty::Unknown
            Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(),
        }
    }
    fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
        match chalk {
            chalk_ir::Ty::Apply(apply_ty) => {
                match apply_ty.name {
                    TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
                        let ctor = from_chalk(db, struct_id);
                        let parameters = from_chalk(db, apply_ty.parameters);
                        Ty::Apply(ApplicationTy { ctor, parameters })
                    }
                    // FIXME handle TypeKindId::Trait/Type here
                    TypeName::TypeKindId(_) => unimplemented!(),
                    TypeName::AssociatedType(_) => unimplemented!(),
                    TypeName::Placeholder(idx) => {
                        assert_eq!(idx.ui, UniverseIndex::ROOT);
                        Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
                    }
                }
            }
            chalk_ir::Ty::Projection(_) => unimplemented!(),
            chalk_ir::Ty::UnselectedProjection(_) => unimplemented!(),
            chalk_ir::Ty::ForAll(_) => unimplemented!(),
            chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
            chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
        }
    }
}

impl ToChalk for Substs {
    type Chalk = Vec<chalk_ir::Parameter>;

    fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> {
        self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
    }

    fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
        parameters
            .into_iter()
            .map(|p| match p {
                chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
                chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
            })
            .collect::<Vec<_>>()
            .into()
    }
}

impl ToChalk for TraitRef {
    type Chalk = chalk_ir::TraitRef;

    fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef {
        let trait_id = self.trait_.to_chalk(db);
        let parameters = self.substs.to_chalk(db);
        chalk_ir::TraitRef { trait_id, parameters }
    }

    fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self {
        let trait_ = from_chalk(db, trait_ref.trait_id);
        let substs = from_chalk(db, trait_ref.parameters);
        TraitRef { trait_, substs }
    }
}

impl ToChalk for Trait {
    type Chalk = chalk_ir::TraitId;

    fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
        self.id.into()
    }

    fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
        Trait { id: trait_id.into() }
    }
}

impl ToChalk for TypeCtor {
    type Chalk = chalk_ir::StructId;

    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId {
        db.intern_type_ctor(self).into()
    }

    fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor {
        db.lookup_intern_type_ctor(struct_id.into())
    }
}

impl ToChalk for ImplBlock {
    type Chalk = chalk_ir::ImplId;

    fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
        db.intern_impl_block(self).into()
    }

    fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
        db.lookup_intern_impl_block(impl_id.into())
    }
}

fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
    chalk_ir::Binders {
        value,
        binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
    }
}

impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
where
    DB: HirDatabase,
{
    fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> {
        unimplemented!()
    }
    fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
        debug!("trait_datum {:?}", trait_id);
        let trait_: Trait = from_chalk(self.db, trait_id);
        let generic_params = trait_.generic_params(self.db);
        let bound_vars = Substs::bound_vars(&generic_params);
        let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
        let flags = chalk_rust_ir::TraitFlags {
            // FIXME set these flags correctly
            auto: false,
            marker: false,
            upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
            fundamental: false,
        };
        let where_clauses = Vec::new(); // FIXME add where clauses
        let associated_ty_ids = Vec::new(); // FIXME add associated tys
        let trait_datum_bound =
            chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
        let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
        Arc::new(trait_datum)
    }
    fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
        debug!("struct_datum {:?}", struct_id);
        let type_ctor = from_chalk(self.db, struct_id);
        // TODO might be nicer if we can create a fake GenericParams for the TypeCtor
        let (num_params, upstream) = match type_ctor {
            TypeCtor::Bool
            | TypeCtor::Char
            | TypeCtor::Int(_)
            | TypeCtor::Float(_)
            | TypeCtor::Never
            | TypeCtor::Str => (0, true),
            TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true),
            TypeCtor::FnPtr | TypeCtor::Tuple => unimplemented!(), // FIXME tuples and FnPtr are currently variadic... we need to make the parameter number explicit
            TypeCtor::FnDef(_) => unimplemented!(),
            TypeCtor::Adt(adt) => {
                let generic_params = adt.generic_params(self.db);
                (
                    generic_params.count_params_including_parent(),
                    adt.krate(self.db) != Some(self.krate),
                )
            }
        };
        let flags = chalk_rust_ir::StructFlags {
            upstream,
            // FIXME set fundamental flag correctly
            fundamental: false,
        };
        let where_clauses = Vec::new(); // FIXME add where clauses
        let self_ty = chalk_ir::ApplicationTy {
            name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
            parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
        };
        let struct_datum_bound = chalk_rust_ir::StructDatumBound {
            self_ty,
            fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
            where_clauses,
            flags,
        };
        let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) };
        Arc::new(struct_datum)
    }
    fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
        debug!("impl_datum {:?}", impl_id);
        let impl_block: ImplBlock = from_chalk(self.db, impl_id);
        let generic_params = impl_block.generic_params(self.db);
        let bound_vars = Substs::bound_vars(&generic_params);
        let trait_ref = impl_block
            .target_trait_ref(self.db)
            .expect("FIXME handle unresolved impl block trait ref")
            .subst(&bound_vars);
        let impl_type = if impl_block.module().krate(self.db) == Some(self.krate) {
            chalk_rust_ir::ImplType::Local
        } else {
            chalk_rust_ir::ImplType::External
        };
        let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
            // FIXME handle negative impls (impl !Sync for Foo)
            trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)),
            where_clauses: Vec::new(),        // FIXME add where clauses
            associated_ty_values: Vec::new(), // FIXME add associated type values
            impl_type,
        };
        let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
        Arc::new(impl_datum)
    }
    fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
        debug!("impls_for_trait {:?}", trait_id);
        let trait_ = from_chalk(self.db, trait_id);
        self.db
            .impls_for_trait(self.krate, trait_)
            .iter()
            // FIXME temporary hack -- as long as we're not lowering where clauses
            // correctly, ignore impls with them completely so as to not treat
            // impl<T> Trait for T where T: ... as a blanket impl on all types
            .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
            .map(|impl_block| impl_block.to_chalk(self.db))
            .collect()
    }
    fn impl_provided_for(
        &self,
        auto_trait_id: chalk_ir::TraitId,
        struct_id: chalk_ir::StructId,
    ) -> bool {
        debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
        false // FIXME
    }
    fn type_name(&self, _id: TypeKindId) -> Identifier {
        unimplemented!()
    }
    fn split_projection<'p>(
        &self,
        projection: &'p ProjectionTy,
    ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
        debug!("split_projection {:?}", projection);
        unimplemented!()
    }
    fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
        debug!("custom_clauses");
        vec![]
    }
    fn all_structs(&self) -> Vec<chalk_ir::StructId> {
        debug!("all_structs");
        // FIXME
        vec![]
    }
}

fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
    T::from_intern_id(InternId::from(chalk_id.index))
}
fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
    chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
}

impl From<chalk_ir::TraitId> for crate::ids::TraitId {
    fn from(trait_id: chalk_ir::TraitId) -> Self {
        id_from_chalk(trait_id.0)
    }
}

impl From<crate::ids::TraitId> for chalk_ir::TraitId {
    fn from(trait_id: crate::ids::TraitId) -> Self {
        chalk_ir::TraitId(id_to_chalk(trait_id))
    }
}

impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
    fn from(struct_id: chalk_ir::StructId) -> Self {
        id_from_chalk(struct_id.0)
    }
}

impl From<crate::ids::TypeCtorId> for chalk_ir::StructId {
    fn from(type_ctor_id: crate::ids::TypeCtorId) -> Self {
        chalk_ir::StructId(id_to_chalk(type_ctor_id))
    }
}

impl From<chalk_ir::ImplId> for crate::ids::GlobalImplId {
    fn from(impl_id: chalk_ir::ImplId) -> Self {
        id_from_chalk(impl_id.0)
    }
}

impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
    fn from(impl_id: crate::ids::GlobalImplId) -> Self {
        chalk_ir::ImplId(id_to_chalk(impl_id))
    }
}
<|endoftext|>


<commit_before>use serde_json;
use std::collections::HashMap;

/// Permitted JSON-API values (all JSON Values)
pub type JsonApiValue = serde_json::Value;
/// Vector of Resource
pub type Resources = Vec<Resource>;
/// Vector of ResourceIdentifiers
pub type ResourceIdentifiers = Vec<ResourceIdentifier>;
pub type Links = HashMap<String, JsonApiValue>;
/// Meta-data object, can contain any data
pub type Meta = HashMap<String, JsonApiValue>;
/// Resource Attributes, can be any JSON value
pub type ResourceAttributes = HashMap<String, JsonApiValue>;
/// Map of relationships with other objects
pub type Relationships = HashMap<String, Relationship>;
/// Side-loaded Resources
pub type Included = Vec<Resource>;
/// Data-related errors
pub type JsonApiErrors = Vec<JsonApiError>;

/// Resource Identifier
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct ResourceIdentifier {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: String,
}

/// JSON-API Resource
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Resource {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: String,
    pub attributes: ResourceAttributes,
    pub relationships: Option<Relationships>,
    pub links: Option<Links>,
}

/// Relationship with another object
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Relationship {
    pub data: IdentifierData,
    pub links: Option<Links>,
}

/// Valid data Resource (can be None)
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum PrimaryData {
    None,
    Single(Resource),
    Multiple(Resources),
}

/// Valid Resource Identifier (can be None)
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum IdentifierData {
    None,
    Single(ResourceIdentifier),
    Multiple(ResourceIdentifiers),
}

/// The specification refers to this as a top-level `document`
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiDocument {
    pub data: Option<PrimaryData>,
    pub included: Option<Resources>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
    pub errors: Option<JsonApiErrors>,
    pub jsonapi: Option<JsonApiInfo>,
}

/// Error location
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct ErrorSource {
    pub pointer: Option<String>,
    pub parameter: Option<String>,
}

/// JSON-API Error
/// All fields are optional
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiError {
    pub id: Option<String>,
    pub links: Option<Links>,
    pub status: Option<String>,
    pub code: Option<String>,
    pub title: Option<String>,
    pub detail: Option<String>,
    pub source: Option<ErrorSource>,
    pub meta: Option<Meta>,
}

/// Optional JsonApiDocument payload identifying the JSON-API version the server implements
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiInfo {
    pub version: Option<String>,
    pub meta: Option<Meta>,
}

/// Pagination links
#[derive(Serialize, Deserialize, Debug)]
pub struct Pagination {
    pub first: Option<String>,
    pub prev: Option<String>,
    pub next: Option<String>,
    pub last: Option<String>,
}

impl Pagination {
    pub fn has_first(&self) -> bool {
        !self.first.is_none()
    }
    pub fn has_prev(&self) -> bool {
        !self.prev.is_none()
    }
    pub fn has_next(&self) -> bool {
        !self.next.is_none()
    }
    pub fn has_last(&self) -> bool {
        !self.last.is_none()
    }
}

/// Top-level JSON-API Document
impl JsonApiDocument {
    fn has_errors(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_meta(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_included(&self) -> bool {
        !self.included.is_none()
    }
    fn has_data(&self) -> bool {
        !self.data.is_none()
    }
    /// This function returns `false` if the `JsonApiDocument` contains any violations of the
    /// specification. See `DocumentValidationError`
    ///
    /// The spec dictates that the document must have least one of `data`, `errors` or `meta`.
    /// Of these, `data` and `errors` must not co-exist.
    /// The optional field `included` may only be present if the `data` field is present too.
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors};
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// assert_eq!(doc.is_valid(), false);
    /// ```
    pub fn is_valid(&self) -> bool {
        match self.validate() {
            Some(_) => false,
            None => true,
        }
    }

    /// This function returns a `Vec` with identified specification violations enumerated in
    /// `DocumentValidationError`
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors, DocumentValidationError};
    ///
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// match doc.validate() {
    ///   Some(errors) => {
    ///     assert!(
    ///       errors.contains(
    ///         &DocumentValidationError::DataWithErrors
    ///       )
    ///     )
    ///   }
    ///   None => assert!(false)
    /// }
    /// ```
    pub fn validate(&self) -> Option<Vec<DocumentValidationError>> {

        let mut errors = Vec::<DocumentValidationError>::new();

        if self.has_data() && self.has_errors() {
            errors.push(DocumentValidationError::DataWithErrors);
        }

        if self.has_included() && !self.has_data() {
            errors.push(DocumentValidationError::IncludedWithoutData);
        }

        if !(self.has_data() || self.has_meta() || self.has_errors()) {
            errors.push(DocumentValidationError::MissingContent);
        }

        match errors.len() {
            0 => None,
            _ => Some(errors),
        }

    }

    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::JsonApiDocument;
    ///
    /// let serialized = r#"{
    ///   "data" : [
    ///     { "id":"1", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"2", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"3", "type":"post", "attributes":{}, "relationships":{}, "links" :{} }
    ///   ]
    /// }"#;
    /// let doc = JsonApiDocument::from_str(&serialized);
    /// assert_eq!(doc.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        let data: Result<Self, serde_json::Error> = serde_json::from_str(&s);
        data
    }
}

/// Top-level (Document) JSON-API specification violations
#[derive(Debug, PartialEq)]
pub enum DocumentValidationError {
    IncludedWithoutData,
    DataWithErrors,
    MissingContent,
}
<commit_msg>feat: Add Resource functions get_relationship and get_attribute_x<commit_after>use serde_json;
use std::collections::HashMap;

/// Permitted JSON-API values (all JSON Values)
pub type JsonApiValue = serde_json::Value;
/// Vector of Resource
pub type Resources = Vec<Resource>;
/// Vector of ResourceIdentifiers
pub type ResourceIdentifiers = Vec<ResourceIdentifier>;
pub type Links = HashMap<String, JsonApiValue>;
/// Meta-data object, can contain any data
pub type Meta = HashMap<String, JsonApiValue>;
/// Resource Attributes, can be any JSON value
pub type ResourceAttributes = HashMap<String, JsonApiValue>;
/// Map of relationships with other objects
pub type Relationships = HashMap<String, Relationship>;
/// Side-loaded Resources
pub type Included = Vec<Resource>;
/// Data-related errors
pub type JsonApiErrors = Vec<JsonApiError>;

/// Resource Identifier
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct ResourceIdentifier {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: String,
}

/// JSON-API Resource
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Resource {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: String,
    pub attributes: ResourceAttributes,
    pub relationships: Option<Relationships>,
    pub links: Option<Links>,
}

/// Relationship with another object
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Relationship {
    pub data: IdentifierData,
    pub links: Option<Links>,
}

/// Valid data Resource (can be None)
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum PrimaryData {
    None,
    Single(Resource),
    Multiple(Resources),
}

/// Valid Resource Identifier (can be None)
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum IdentifierData {
    None,
    Single(ResourceIdentifier),
    Multiple(ResourceIdentifiers),
}

/// The specification refers to this as a top-level `document`
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiDocument {
    pub data: Option<PrimaryData>,
    pub included: Option<Resources>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
    pub errors: Option<JsonApiErrors>,
    pub jsonapi: Option<JsonApiInfo>,
}

/// Error location
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct ErrorSource {
    pub pointer: Option<String>,
    pub parameter: Option<String>,
}

/// JSON-API Error
/// All fields are optional
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiError {
    pub id: Option<String>,
    pub links: Option<Links>,
    pub status: Option<String>,
    pub code: Option<String>,
    pub title: Option<String>,
    pub detail: Option<String>,
    pub source: Option<ErrorSource>,
    pub meta: Option<Meta>,
}

/// Optional JsonApiDocument payload identifying the JSON-API version the server implements
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct JsonApiInfo {
    pub version: Option<String>,
    pub meta: Option<Meta>,
}

/// Pagination links
#[derive(Serialize, Deserialize, Debug)]
pub struct Pagination {
    pub first: Option<String>,
    pub prev: Option<String>,
    pub next: Option<String>,
    pub last: Option<String>,
}

impl Pagination {
    pub fn has_first(&self) -> bool {
        !self.first.is_none()
    }
    pub fn has_prev(&self) -> bool {
        !self.prev.is_none()
    }
    pub fn has_next(&self) -> bool {
        !self.next.is_none()
    }
    pub fn has_last(&self) -> bool {
        !self.last.is_none()
    }
}

/// Top-level JSON-API Document
impl JsonApiDocument {
    fn has_errors(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_meta(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_included(&self) -> bool {
        !self.included.is_none()
    }
    fn has_data(&self) -> bool {
        !self.data.is_none()
    }
    /// This function returns `false` if the `JsonApiDocument` contains any violations of the
    /// specification. See `DocumentValidationError`
    ///
    /// The spec dictates that the document must have least one of `data`, `errors` or `meta`.
    /// Of these, `data` and `errors` must not co-exist.
    /// The optional field `included` may only be present if the `data` field is present too.
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors};
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// assert_eq!(doc.is_valid(), false);
    /// ```
    pub fn is_valid(&self) -> bool {
        match self.validate() {
            Some(_) => false,
            None => true,
        }
    }

    /// This function returns a `Vec` with identified specification violations enumerated in
    /// `DocumentValidationError`
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors, DocumentValidationError};
    ///
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// match doc.validate() {
    ///   Some(errors) => {
    ///     assert!(
    ///       errors.contains(
    ///         &DocumentValidationError::DataWithErrors
    ///       )
    ///     )
    ///   }
    ///   None => assert!(false)
    /// }
    /// ```
    pub fn validate(&self) -> Option<Vec<DocumentValidationError>> {

        let mut errors = Vec::<DocumentValidationError>::new();

        if self.has_data() && self.has_errors() {
            errors.push(DocumentValidationError::DataWithErrors);
        }

        if self.has_included() && !self.has_data() {
            errors.push(DocumentValidationError::IncludedWithoutData);
        }

        if !(self.has_data() || self.has_meta() || self.has_errors()) {
            errors.push(DocumentValidationError::MissingContent);
        }

        match errors.len() {
            0 => None,
            _ => Some(errors),
        }

    }

    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::JsonApiDocument;
    ///
    /// let serialized = r#"{
    ///   "data" : [
    ///     { "id":"1", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"2", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"3", "type":"post", "attributes":{}, "relationships":{}, "links" :{} }
    ///   ]
    /// }"#;
    /// let doc = JsonApiDocument::from_str(&serialized);
    /// assert_eq!(doc.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        let data: Result<Self, serde_json::Error> = serde_json::from_str(&s);
        data
    }
}

impl Resource {
    pub fn get_relationship(&self, name: &str) -> Option<&Relationship> {
        match self.relationships {
            None => None,
            Some(ref relationships) => {
                match relationships.get(name) {
                    None => None,
                    Some(rel) => Some(rel),
                }
            }
        }
    }

    pub fn get_attribute_as_string(&self, attr: &str) -> Result<String, JsonApiDataError> {
        match self.attributes.get(attr) {
            None => Err(JsonApiDataError::AttributeNotFound),
            Some(json_attr) => {
                match json_attr.as_str() {
                    None => Err(JsonApiDataError::IncompatibleAttributeType),
                    Some(s) => Ok(s.into()),
                }
            }
        }

    }

    /*
    pub fn get_relationship_id(&self, name: &str) -> Option<&i64> {
        match self.get_relationship(name) {
            None => None,
            Some(rel) => {
                match rel.data {
                    None => None,
                    Single(resource_identifier) => Some(resource_identifier.id),
                    Multiple(_) => {
                        println!("Relationship is not 1");
                        None
                    }
                }
            }
        }
    }
    */
}

/// Top-level (Document) JSON-API specification violations
#[derive(Debug, PartialEq)]
pub enum DocumentValidationError {
    IncludedWithoutData,
    DataWithErrors,
    MissingContent,
}

#[derive(Debug, PartialEq)]
pub enum JsonApiDataError {
    AttributeNotFound,
    IncompatibleAttributeType,
}
<|endoftext|>


<commit_before>use latch::{LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use job::StackJob;
use std::sync::Arc;
use std::error::Error;
use std::fmt;
use thread_pool::{self, Registry, WorkerThread};
use std::mem;
use unwind;

/// Custom error type for the rayon thread pool configuration.
#[derive(Debug,PartialEq)]
pub enum InitError {
    /// Error if number of threads is set to zero.
    NumberOfThreadsZero,

    /// Error if the gloal thread pool is initialized multiple times
    /// and the configuration is not equal for all configurations.
    GlobalPoolAlreadyInitialized,
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InitError::NumberOfThreadsZero => {
                write!(f,
                       "The number of threads was set to zero but must be greater than zero.")
            }
            InitError::GlobalPoolAlreadyInitialized => {
                write!(f,
                       "The gobal thread pool has already been initialized with a different \
                        configuration. Only one valid configuration is allowed.")
            }
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::NumberOfThreadsZero => "number of threads set to zero",
            InitError::GlobalPoolAlreadyInitialized => {
                "global thread pool has already been initialized"
            }
        }
    }
}

/// Contains the rayon thread pool configuration.
#[derive(Clone, Debug)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool. Must not be zero.
    num_threads: Option<usize>,
}

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration { num_threads: None }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> Option<usize> {
        self.num_threads
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// The argument `num_threads` must not be zero. If you do not
    /// call this function, rayon will select a suitable default
    /// (currently, the default is one thread per CPU core).
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = Some(num_threads);
        self
    }

    /// Checks whether the configuration is valid.
    fn validate(&self) -> Result<(), InitError> {
        if let Some(value) = self.num_threads {
            if value == 0 {
                return Err(InitError::NumberOfThreadsZero);
            }
        }

        Ok(())
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will simply check that the global thread pool already has the
/// configuration you requested, rather than making changes.
///
/// An `Ok` result indicates that the thread pool is running with the
/// given configuration. Otherwise, a suitable error is returned.
pub fn initialize(config: Configuration) -> Result<(), InitError> {
    try!(config.validate());

    let num_threads = config.num_threads;

    let registry = thread_pool::get_registry_with_config(config);

    if let Some(value) = num_threads {
        if value != registry.num_threads() {
            return Err(InitError::GlobalPoolAlreadyInitialized);
        }
    }

    registry.wait_until_primed();

    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    unsafe {
        let worker_thread = WorkerThread::current();

        // slow path: not yet in the thread pool
        if worker_thread.is_null() {
            return join_inject(oper_a, oper_b);
        }

        log!(Join { worker: (*worker_thread).index() });

        // create virtual wrapper for task b; this all has to be
        // done here so that the stack frame can keep it all live
        // long enough
        let job_b = StackJob::new(oper_b, SpinLatch::new());
        (*worker_thread).push(job_b.as_job_ref());

        // record how many async spawns have occurred on this thread
        // before task A is executed
        let spawn_count = (*worker_thread).current_spawn_count();

        // execute task a; hopefully b gets stolen
        let result_a;
        {
            let guard = unwind::finally(&job_b.latch, |job_b_latch| {
                // If another thread stole our job when we panic, we must halt unwinding
                // until that thread is finished using it.
                if (*WorkerThread::current()).pop().is_none() {
                    job_b_latch.spin();
                }
            });
            result_a = oper_a();
            mem::forget(guard);
        }

        // before we can try to pop b, we have to first pop off any async spawns
        // that have occurred on this thread
        (*worker_thread).pop_spawned_jobs(spawn_count);

        // if b was not stolen, do it ourselves, else wait for the thief to finish
        let result_b;
        if (*worker_thread).pop().is_some() {
            log!(PoppedJob { worker: (*worker_thread).index() });
            result_b = job_b.run_inline(); // not stolen, let's do it!
        } else {
            log!(LostJob { worker: (*worker_thread).index() });
            (*worker_thread).steal_until(&job_b.latch); // stolen, wait for them to finish
            result_b = job_b.into_result();
        }

        // now result_b should be initialized
        (result_a, result_b)
    }
}

#[cold] // cold path
unsafe fn join_inject<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    let job_a = StackJob::new(oper_a, LockLatch::new());
    let job_b = StackJob::new(oper_b, LockLatch::new());

    thread_pool::get_registry().inject(&[job_a.as_job_ref(), job_b.as_job_ref()]);

    job_a.latch.wait();
    job_b.latch.wait();

    (job_a.into_result(), job_b.into_result())
}

pub struct ThreadPool {
    registry: Arc<Registry>,
}

impl ThreadPool {
    /// Constructs a new thread pool with the given configuration. If
    /// the configuration is not valid, returns a suitable `Err`
    /// result.  See `InitError` for more details.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, InitError> {
        try!(configuration.validate());
        Ok(ThreadPool { registry: Registry::new(configuration.num_threads) })
    }

    /// Executes `op` within the threadpool. Any attempts to `join`
    /// which occur there will then operate within that threadpool.
    pub fn install<OP, R>(&self, op: OP) -> R
        where OP: FnOnce() -> R + Send
    {
        unsafe {
            let job_a = StackJob::new(op, LockLatch::new());
            self.registry.inject(&[job_a.as_job_ref()]);
            job_a.latch.wait();
            job_a.into_result()
        }
    }

    /// Returns the number of threads in the thread pool.
    pub fn num_threads(&self) -> usize {
        self.registry.num_threads()
    }

    /// Returns the index of the current thread in the thread pool. Panics if
    /// the current thread is not in this thread pool.
    pub fn current_thread_index(&self) -> usize {
        unsafe {
            let curr = WorkerThread::current();
            assert!(!curr.is_null());
            (*curr).index()
        }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}
<commit_msg>modify to check the registry id and to extend the comment<commit_after>use latch::{LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use job::StackJob;
use std::sync::Arc;
use std::error::Error;
use std::fmt;
use thread_pool::{self, Registry, WorkerThread};
use std::mem;
use unwind;

/// Custom error type for the rayon thread pool configuration.
#[derive(Debug,PartialEq)]
pub enum InitError {
    /// Error if number of threads is set to zero.
    NumberOfThreadsZero,

    /// Error if the gloal thread pool is initialized multiple times
    /// and the configuration is not equal for all configurations.
    GlobalPoolAlreadyInitialized,
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InitError::NumberOfThreadsZero => {
                write!(f,
                       "The number of threads was set to zero but must be greater than zero.")
            }
            InitError::GlobalPoolAlreadyInitialized => {
                write!(f,
                       "The gobal thread pool has already been initialized with a different \
                        configuration. Only one valid configuration is allowed.")
            }
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::NumberOfThreadsZero => "number of threads set to zero",
            InitError::GlobalPoolAlreadyInitialized => {
                "global thread pool has already been initialized"
            }
        }
    }
}

/// Contains the rayon thread pool configuration.
#[derive(Clone, Debug)]
pub struct Configuration {
    /// The number of threads in the rayon thread pool. Must not be zero.
    num_threads: Option<usize>,
}

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration { num_threads: None }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> Option<usize> {
        self.num_threads
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// The argument `num_threads` must not be zero. If you do not
    /// call this function, rayon will select a suitable default
    /// (currently, the default is one thread per CPU core).
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = Some(num_threads);
        self
    }

    /// Checks whether the configuration is valid.
    fn validate(&self) -> Result<(), InitError> {
        if let Some(value) = self.num_threads {
            if value == 0 {
                return Err(InitError::NumberOfThreadsZero);
            }
        }

        Ok(())
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will simply check that the global thread pool already has the
/// configuration you requested, rather than making changes.
///
/// An `Ok` result indicates that the thread pool is running with the
/// given configuration. Otherwise, a suitable error is returned.
pub fn initialize(config: Configuration) -> Result<(), InitError> {
    try!(config.validate());

    let num_threads = config.num_threads;

    let registry = thread_pool::get_registry_with_config(config);

    if let Some(value) = num_threads {
        if value != registry.num_threads() {
            return Err(InitError::GlobalPoolAlreadyInitialized);
        }
    }

    registry.wait_until_primed();

    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    unsafe {
        let worker_thread = WorkerThread::current();

        // slow path: not yet in the thread pool
        if worker_thread.is_null() {
            return join_inject(oper_a, oper_b);
        }

        log!(Join { worker: (*worker_thread).index() });

        // create virtual wrapper for task b; this all has to be
        // done here so that the stack frame can keep it all live
        // long enough
        let job_b = StackJob::new(oper_b, SpinLatch::new());
        (*worker_thread).push(job_b.as_job_ref());

        // record how many async spawns have occurred on this thread
        // before task A is executed
        let spawn_count = (*worker_thread).current_spawn_count();

        // execute task a; hopefully b gets stolen
        let result_a;
        {
            let guard = unwind::finally(&job_b.latch, |job_b_latch| {
                // If another thread stole our job when we panic, we must halt unwinding
                // until that thread is finished using it.
                if (*WorkerThread::current()).pop().is_none() {
                    job_b_latch.spin();
                }
            });
            result_a = oper_a();
            mem::forget(guard);
        }

        // before we can try to pop b, we have to first pop off any async spawns
        // that have occurred on this thread
        (*worker_thread).pop_spawned_jobs(spawn_count);

        // if b was not stolen, do it ourselves, else wait for the thief to finish
        let result_b;
        if (*worker_thread).pop().is_some() {
            log!(PoppedJob { worker: (*worker_thread).index() });
            result_b = job_b.run_inline(); // not stolen, let's do it!
        } else {
            log!(LostJob { worker: (*worker_thread).index() });
            (*worker_thread).steal_until(&job_b.latch); // stolen, wait for them to finish
            result_b = job_b.into_result();
        }

        // now result_b should be initialized
        (result_a, result_b)
    }
}

#[cold] // cold path
unsafe fn join_inject<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
    where A: FnOnce() -> RA + Send,
          B: FnOnce() -> RB + Send,
          RA: Send,
          RB: Send
{
    let job_a = StackJob::new(oper_a, LockLatch::new());
    let job_b = StackJob::new(oper_b, LockLatch::new());

    thread_pool::get_registry().inject(&[job_a.as_job_ref(), job_b.as_job_ref()]);

    job_a.latch.wait();
    job_b.latch.wait();

    (job_a.into_result(), job_b.into_result())
}

pub struct ThreadPool {
    registry: Arc<Registry>,
}

impl ThreadPool {
    /// Constructs a new thread pool with the given configuration. If
    /// the configuration is not valid, returns a suitable `Err`
    /// result.  See `InitError` for more details.
    pub fn new(configuration: Configuration) -> Result<ThreadPool, InitError> {
        try!(configuration.validate());
        Ok(ThreadPool { registry: Registry::new(configuration.num_threads) })
    }

    /// Executes `op` within the threadpool. Any attempts to `join`
    /// which occur there will then operate within that threadpool.
    pub fn install<OP, R>(&self, op: OP) -> R
        where OP: FnOnce() -> R + Send
    {
        unsafe {
            let job_a = StackJob::new(op, LockLatch::new());
            self.registry.inject(&[job_a.as_job_ref()]);
            job_a.latch.wait();
            job_a.into_result()
        }
    }

    /// Returns the number of threads in the thread pool.
    pub fn num_threads(&self) -> usize {
        self.registry.num_threads()
    }

    /// If called from a Rayon worker thread in this thread-pool,
    /// returns the index of that thread; if not called from a Rayon
    /// thread, or called from a Rayon thread that belongs to a
    /// different thread-pool, returns `None`.
    ///
    /// The index for a given thread will not change over the thread's
    /// lifetime. However, multiple threads may share the same index if
    /// they are in distinct thread-pools.
    ///
    /// ### Future compatibility note
    ///
    /// Currently, every thread-pool (including the global thread-pool)
    /// has a fixed number of threads, but this may change in future Rayon
    /// versions. In that case, the index for a thread would not change
    /// during its lifetime, but thread indices may wind up being reused
    /// if threads are terminated and restarted. (If this winds up being
    /// an untenable policy, then a semver-incompatible version can be
    /// used.)
    pub fn current_thread_index(&self) -> Option<usize> {
        unsafe {
            let curr = WorkerThread::current();
            if curr.is_null() {
                None
            } else if (*curr).registry().id() != self.registry.id() {
                None
            } else {
                Some((*curr).index())
            }
        }
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        self.registry.terminate();
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::ptr;
use std::str::from_utf8;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<commit_msg>Only init Capstone once<commit_after>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::ptr;
use std::str::from_utf8;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        // If handle is already setup we just return from here
        if self.handle != ptr::null_mut() {
            return Ok(());
        }

        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<|endoftext|>