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

//! Utilities to throw exceptions from Rust bindings.

use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
use dom::domexception::{DOMException, DOMErrorName};

use js::jsapi::{JSContext, JSBool, JSObject};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::glue::{ReportError};
use js::rust::with_compartment;

use libc;
use std::ffi::CString;
use std::ptr;

/// DOM exceptions that can be thrown by a native DOM method.
#[derive(Debug, Clone)]
pub enum Error {
    /// IndexSizeError
    IndexSize,
    /// NotFoundError
    NotFound,
    /// HierarchyRequestError
    HierarchyRequest,
    /// InvalidCharacterError
    InvalidCharacter,
    /// NotSupportedError
    NotSupported,
    /// InvalidStateError
    InvalidState,
    /// SyntaxError
    Syntax,
    /// NamespaceError
    NamespaceError,
    /// InvalidAccessError
    InvalidAccess,
    /// SecurityError
    Security,
    /// NetworkError
    Network,
    /// AbortError
    Abort,
    /// TimeoutError
    Timeout,
    /// DataCloneError
    DataClone,
    /// NoModificationAllowedError
    NoModificationAllowedError,
    /// A JavaScript exception is already pending.
    JSFailed,
}

/// The return type for IDL operations that can throw DOM exceptions.
pub type Fallible<T> = Result<T, Error>;

/// The return type for IDL operations that can throw DOM exceptions and
/// return `()`.
pub type ErrorResult = Fallible<()>;

/// Set a pending DOM exception for the given `result` on `cx`.
pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
                           result: Error) {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let code = match result {
        Error::IndexSize => DOMErrorName::IndexSizeError,
        Error::NotFound => DOMErrorName::NotFoundError,
        Error::HierarchyRequest => DOMErrorName::HierarchyRequestError,
        Error::InvalidCharacter => DOMErrorName::InvalidCharacterError,
        Error::NotSupported => DOMErrorName::NotSupportedError,
        Error::InvalidState => DOMErrorName::InvalidStateError,
        Error::Syntax => DOMErrorName::SyntaxError,
        Error::NamespaceError => DOMErrorName::NamespaceError,
        Error::InvalidAccess => DOMErrorName::InvalidAccessError,
        Error::Security => DOMErrorName::SecurityError,
        Error::Network => DOMErrorName::NetworkError,
        Error::Abort => DOMErrorName::AbortError,
        Error::Timeout => DOMErrorName::TimeoutError,
        Error::DataClone => DOMErrorName::DataCloneError,
        Error::NoModificationAllowedError => DOMErrorName::NoModificationAllowedError,
        Error::JSFailed => panic!(),
    };
    let exception = DOMException::new(global, code).root();
    let thrown = exception.to_jsval(cx);
    unsafe {
        JS_SetPendingException(cx, thrown);
    }
}

/// Report a pending exception, thereby clearing it.
pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
    unsafe {
        if JS_IsExceptionPending(cx) != 0 {
            let saved = JS_SaveFrameChain(cx);
            with_compartment(cx, obj, || {
                JS_ReportPendingException(cx);
            });
            if saved != 0 {
                JS_RestoreFrameChain(cx);
            }
        }
    }
}

/// Throw an exception to signal that a `JSVal` can not be converted to any of
/// the types in an IDL union type.
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let message = format!("argument could not be converted to any of: {}", names);
    let string = CString::from_slice(message.as_bytes());
    unsafe { ReportError(cx, string.as_ptr()) };
    return 0;
}

/// Format string used to throw `TypeError`s.
static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
    '{' as libc::c_char,
    '0' as libc::c_char,
    '}' as libc::c_char,
    0 as libc::c_char,
];

/// Format string struct used to throw `TypeError`s.
static mut ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
    format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
    argCount: 1,
    exnType: JSEXN_TYPEERR as i16,
};

/// Callback used to throw `TypeError`s.
unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
                            _locale: *const libc::c_char,
                            error_number: libc::c_uint) -> *const JSErrorFormatString
{
    assert_eq!(error_number, 0);
    &ERROR_FORMAT_STRING as *const JSErrorFormatString
}

/// Throw a `TypeError` with the given message.
pub fn throw_type_error(cx: *mut JSContext, error: &str) {
    let error = CString::from_slice(error.as_bytes());
    unsafe {
        JS_ReportErrorNumber(cx,
            Some(get_error_message as
                unsafe extern "C" fn(*mut libc::c_void, *const libc::c_char,
                                     libc::c_uint) -> *const JSErrorFormatString),
            ptr::null_mut(), 0, error.as_ptr());
    }
}
<commit_msg>Clarify the documentation for dom::bindings::error::Error variants.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utilities to throw exceptions from Rust bindings.

use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
use dom::domexception::{DOMException, DOMErrorName};

use js::jsapi::{JSContext, JSBool, JSObject};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::glue::{ReportError};
use js::rust::with_compartment;

use libc;
use std::ffi::CString;
use std::ptr;

/// DOM exceptions that can be thrown by a native DOM method.
#[derive(Debug, Clone)]
pub enum Error {
    /// IndexSizeError DOMException
    IndexSize,
    /// NotFoundError DOMException
    NotFound,
    /// HierarchyRequestError DOMException
    HierarchyRequest,
    /// InvalidCharacterError DOMException
    InvalidCharacter,
    /// NotSupportedError DOMException
    NotSupported,
    /// InvalidStateError DOMException
    InvalidState,
    /// SyntaxError DOMException
    Syntax,
    /// NamespaceError DOMException
    NamespaceError,
    /// InvalidAccessError DOMException
    InvalidAccess,
    /// SecurityError DOMException
    Security,
    /// NetworkError DOMException
    Network,
    /// AbortError DOMException
    Abort,
    /// TimeoutError DOMException
    Timeout,
    /// DataCloneError DOMException
    DataClone,
    /// NoModificationAllowedError DOMException
    NoModificationAllowedError,
    /// A JavaScript exception is already pending.
    JSFailed,
}

/// The return type for IDL operations that can throw DOM exceptions.
pub type Fallible<T> = Result<T, Error>;

/// The return type for IDL operations that can throw DOM exceptions and
/// return `()`.
pub type ErrorResult = Fallible<()>;

/// Set a pending DOM exception for the given `result` on `cx`.
pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
                           result: Error) {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let code = match result {
        Error::IndexSize => DOMErrorName::IndexSizeError,
        Error::NotFound => DOMErrorName::NotFoundError,
        Error::HierarchyRequest => DOMErrorName::HierarchyRequestError,
        Error::InvalidCharacter => DOMErrorName::InvalidCharacterError,
        Error::NotSupported => DOMErrorName::NotSupportedError,
        Error::InvalidState => DOMErrorName::InvalidStateError,
        Error::Syntax => DOMErrorName::SyntaxError,
        Error::NamespaceError => DOMErrorName::NamespaceError,
        Error::InvalidAccess => DOMErrorName::InvalidAccessError,
        Error::Security => DOMErrorName::SecurityError,
        Error::Network => DOMErrorName::NetworkError,
        Error::Abort => DOMErrorName::AbortError,
        Error::Timeout => DOMErrorName::TimeoutError,
        Error::DataClone => DOMErrorName::DataCloneError,
        Error::NoModificationAllowedError => DOMErrorName::NoModificationAllowedError,
        Error::JSFailed => panic!(),
    };
    let exception = DOMException::new(global, code).root();
    let thrown = exception.to_jsval(cx);
    unsafe {
        JS_SetPendingException(cx, thrown);
    }
}

/// Report a pending exception, thereby clearing it.
pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
    unsafe {
        if JS_IsExceptionPending(cx) != 0 {
            let saved = JS_SaveFrameChain(cx);
            with_compartment(cx, obj, || {
                JS_ReportPendingException(cx);
            });
            if saved != 0 {
                JS_RestoreFrameChain(cx);
            }
        }
    }
}

/// Throw an exception to signal that a `JSVal` can not be converted to any of
/// the types in an IDL union type.
pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool {
    assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
    let message = format!("argument could not be converted to any of: {}", names);
    let string = CString::from_slice(message.as_bytes());
    unsafe { ReportError(cx, string.as_ptr()) };
    return 0;
}

/// Format string used to throw `TypeError`s.
static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
    '{' as libc::c_char,
    '0' as libc::c_char,
    '}' as libc::c_char,
    0 as libc::c_char,
];

/// Format string struct used to throw `TypeError`s.
static mut ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
    format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
    argCount: 1,
    exnType: JSEXN_TYPEERR as i16,
};

/// Callback used to throw `TypeError`s.
unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
                            _locale: *const libc::c_char,
                            error_number: libc::c_uint) -> *const JSErrorFormatString
{
    assert_eq!(error_number, 0);
    &ERROR_FORMAT_STRING as *const JSErrorFormatString
}

/// Throw a `TypeError` with the given message.
pub fn throw_type_error(cx: *mut JSContext, error: &str) {
    let error = CString::from_slice(error.as_bytes());
    unsafe {
        JS_ReportErrorNumber(cx,
            Some(get_error_message as
                unsafe extern "C" fn(*mut libc::c_void, *const libc::c_char,
                                     libc::c_uint) -> *const JSErrorFormatString),
            ptr::null_mut(), 0, error.as_ptr());
    }
}
<|endoftext|>


<commit_before>//! Create new `Streams` connected to external inputs.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::{MutableAntichain, Antichain};
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;
use progress::timestamp::RootTimestamp;
use progress::nested::product::Product;

use timely_communication::Allocate;
use {Data, Push};
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter as PushCounter};
use dataflow::channels::pushers::buffer::{Buffer as PushBuffer, AutoflushSession};

use dataflow::operators::Capability;
use dataflow::operators::capability::mint as mint_capability;

use dataflow::{Stream, Scope};
use dataflow::scopes::{Child, Root};

/// Create a new `Stream` and `Handle` through which to supply input.
pub trait UnorderedInput<G: Scope> {
    /// Create a new `Stream` and `Handle` through which to supply input.
    ///
    /// The `new_input` method returns a pair `(Handle, Stream)` where the `Stream` can be used
    /// immediately for timely dataflow construction, and the `Handle` is later used to introduce
    /// data into the timely dataflow computation.
    ///
    /// The `Handle` also provides a means to indicate
    /// to timely dataflow that the input has advanced beyond certain timestamps, allowing timely
    /// to issue progress notifications.
    fn new_unordered_input<D:Data>(&mut self) -> ((UnorderedHandle<G, D>, Capability<G::Timestamp>), Stream<G, D>);
}

impl<G: Scope> UnorderedInput<G> for G {
    fn new_unordered_input<D:Data>(&mut self) -> ((UnorderedHandle<G, D>, Capability<G::Timestamp>), Stream<G, D>) {

        let (output, registrar) = Tee::<G::Timestamp, D>::new();
        let internal = Rc::new(RefCell::new(CountMap::new()));
        let produced = Rc::new(RefCell::new(CountMap::new()));
        let cap = mint_capability(Default::default(), internal.clone());
        let helper = UnorderedHandle::new(PushCounter::new(output, produced.clone()));
        let peers = self.peers();

        let index = self.add_operator(UnorderedOperator {
            internal: internal.clone(),
            produced: produced.clone(),
            peers:    peers,
        });

        return ((helper, cap), Stream::new(Source { index: index, port: 0 }, registrar, self.clone()));
    }
}

struct UnorderedOperator<T:Timestamp> {
    internal:   Rc<RefCell<CountMap<T>>>,
    produced:   Rc<RefCell<CountMap<T>>>,
    peers:     usize,
}

impl<T:Timestamp> Operate<T> for UnorderedOperator<T> {
    fn name(&self) -> String { "Input".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<<T as Timestamp>::Summary>>>,
                                           Vec<CountMap<T>>) {
        let mut internal = CountMap::new();
        // augment the counts for each reserved capability.
        for &(ref time, count) in self.internal.borrow().iter() {
            internal.update(time, count * (self.peers as i64 - 1));
        }

        // drain the changes to empty out, and complete the counts for internal.
        self.internal.borrow_mut().drain_into(&mut internal);
        (Vec::new(), vec![internal])
    }

    fn pull_internal_progress(&mut self,_consumed: &mut [CountMap<T>],
                                         internal: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        self.produced.borrow_mut().drain_into(&mut produced[0]);
        self.internal.borrow_mut().drain_into(&mut internal[0]);
        return false;
    }

    fn notify_me(&self) -> bool { false }
}

/// A handle to an input `Stream`, used to introduce data to a timely dataflow computation.
pub struct UnorderedHandle<G: Scope, D: Data> {
    buffer: PushBuffer<G::Timestamp, D, PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>>,
}

impl<G: Scope, D: Data> UnorderedHandle<G, D> {
    fn new(pusher: PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>) -> UnorderedHandle<G, D> {
        UnorderedHandle {
            buffer: PushBuffer::new(pusher),
        }
    }

    pub fn session<'b>(&'b mut self, cap: Capability<G::Timestamp>) -> AutoflushSession<'b, G::Timestamp, D, PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>> {
        self.buffer.autoflush_session(cap)
    }
}

impl<G: Scope, D: Data> Drop for UnorderedHandle<G, D> {
    fn drop(&mut self) {
        // TODO: explode if not all capabilities were given up?
    }
}
<commit_msg>Minimal documentation for UnorderedInput<commit_after>//! Create new `Streams` connected to external inputs.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::{MutableAntichain, Antichain};
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;
use progress::timestamp::RootTimestamp;
use progress::nested::product::Product;

use timely_communication::Allocate;
use {Data, Push};
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter as PushCounter};
use dataflow::channels::pushers::buffer::{Buffer as PushBuffer, AutoflushSession};

use dataflow::operators::Capability;
use dataflow::operators::capability::mint as mint_capability;

use dataflow::{Stream, Scope};
use dataflow::scopes::{Child, Root};

/// Create a new `Stream` and `Handle` through which to supply input.
pub trait UnorderedInput<G: Scope> {
    /// Create a new capability-based `Stream` and `Handle` through which to supply input. This
    /// input supports multiple open epochs (timestamps) at the same time.
    ///
    /// The `new_unordered_input` method returns `((Handle, Capability), Stream)` where the `Stream` can be used
    /// immediately for timely dataflow construction, `Handle` and `Capability` are later used to introduce
    /// data into the timely dataflow computation.
    ///
    /// The `Capability` returned is for the default value of the timestamp type in use. The
    /// capability can be dropped to inform the system that the input has advanced beyond the
    /// capability's timestamp. To retain the ability to send, a new capability at a later timestamp
    /// should be obtained first, via the `delayed` function for `Capability`.
    ///
    /// To communicate the end-of-input drop all available capabilities.
    fn new_unordered_input<D:Data>(&mut self) -> ((UnorderedHandle<G, D>, Capability<G::Timestamp>), Stream<G, D>);
}

impl<G: Scope> UnorderedInput<G> for G {
    fn new_unordered_input<D:Data>(&mut self) -> ((UnorderedHandle<G, D>, Capability<G::Timestamp>), Stream<G, D>) {

        let (output, registrar) = Tee::<G::Timestamp, D>::new();
        let internal = Rc::new(RefCell::new(CountMap::new()));
        let produced = Rc::new(RefCell::new(CountMap::new()));
        let cap = mint_capability(Default::default(), internal.clone());
        let helper = UnorderedHandle::new(PushCounter::new(output, produced.clone()));
        let peers = self.peers();

        let index = self.add_operator(UnorderedOperator {
            internal: internal.clone(),
            produced: produced.clone(),
            peers:    peers,
        });

        return ((helper, cap), Stream::new(Source { index: index, port: 0 }, registrar, self.clone()));
    }
}

struct UnorderedOperator<T:Timestamp> {
    internal:   Rc<RefCell<CountMap<T>>>,
    produced:   Rc<RefCell<CountMap<T>>>,
    peers:     usize,
}

impl<T:Timestamp> Operate<T> for UnorderedOperator<T> {
    fn name(&self) -> String { "Input".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<<T as Timestamp>::Summary>>>,
                                           Vec<CountMap<T>>) {
        let mut internal = CountMap::new();
        // augment the counts for each reserved capability.
        for &(ref time, count) in self.internal.borrow().iter() {
            internal.update(time, count * (self.peers as i64 - 1));
        }

        // drain the changes to empty out, and complete the counts for internal.
        self.internal.borrow_mut().drain_into(&mut internal);
        (Vec::new(), vec![internal])
    }

    fn pull_internal_progress(&mut self,_consumed: &mut [CountMap<T>],
                                         internal: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        self.produced.borrow_mut().drain_into(&mut produced[0]);
        self.internal.borrow_mut().drain_into(&mut internal[0]);
        return false;
    }

    fn notify_me(&self) -> bool { false }
}

/// A handle to an input `Stream`, used to introduce data to a timely dataflow computation.
pub struct UnorderedHandle<G: Scope, D: Data> {
    buffer: PushBuffer<G::Timestamp, D, PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>>,
}

impl<G: Scope, D: Data> UnorderedHandle<G, D> {
    fn new(pusher: PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>) -> UnorderedHandle<G, D> {
        UnorderedHandle {
            buffer: PushBuffer::new(pusher),
        }
    }

    pub fn session<'b>(&'b mut self, cap: Capability<G::Timestamp>) -> AutoflushSession<'b, G::Timestamp, D, PushCounter<G::Timestamp, D, Tee<G::Timestamp, D>>> {
        self.buffer.autoflush_session(cap)
    }
}

impl<G: Scope, D: Data> Drop for UnorderedHandle<G, D> {
    fn drop(&mut self) {
        // TODO: explode if not all capabilities were given up?
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![feature(plugin, conservative_impl_trait, test)]
#![plugin(tarpc_plugins)]

#[macro_use]
extern crate tarpc;
#[cfg(test)]
extern crate test;
extern crate env_logger;
extern crate futures;

use futures::Future;
#[cfg(test)]
use test::Bencher;
use tarpc::sync::Connect;
use tarpc::util::{FirstSocketAddr, Never};

service! {
    rpc ack();
}

#[derive(Clone)]
struct Server;

impl FutureService for Server {
    type AckFut = futures::Finished<(), Never>;
    fn ack(&self) -> Self::AckFut {
        futures::finished(())
    }
}

#[cfg(test)]
#[bench]
fn latency(bencher: &mut Bencher) {
    let _ = env_logger::init();
    let server = Server.listen("localhost:0".first_socket_addr()).wait().unwrap();
    let client = SyncClient::connect(server.local_addr()).unwrap();

    bencher.iter(|| {
        client.ack().unwrap();
    });
}
<commit_msg>Fix latency bench<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![feature(plugin, conservative_impl_trait, test)]
#![plugin(tarpc_plugins)]

#[macro_use]
extern crate tarpc;
#[cfg(test)]
extern crate test;
extern crate env_logger;
extern crate futures;

use futures::Future;
#[cfg(test)]
use test::Bencher;
use tarpc::sync::Connect;
use tarpc::util::{FirstSocketAddr, Never};

service! {
    rpc ack();
}

#[derive(Clone)]
struct Server;

impl FutureService for Server {
    type AckFut = futures::Finished<(), Never>;
    fn ack(&mut self) -> Self::AckFut {
        futures::finished(())
    }
}

#[cfg(test)]
#[bench]
fn latency(bencher: &mut Bencher) {
    let _ = env_logger::init();
    let addr = Server.listen("localhost:0".first_socket_addr()).wait().unwrap();
    let mut client = SyncClient::connect(addr).unwrap();

    bencher.iter(|| {
        client.ack().unwrap();
    });
}
<|endoftext|>


<commit_before>//! Renderer for patterns.

use hir::{db::HirDatabase, HasVisibility, Name, StructKind};
use itertools::Itertools;

use crate::{
    config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem,
    CompletionItemKind,
};

pub(crate) fn render_struct_pat<'a>(
    ctx: RenderContext<'a>,
    strukt: hir::Struct,
    local_name: Option<Name>,
) -> Option<CompletionItem> {
    let _p = profile::span("render_struct_pat");

    let module = ctx.completion.scope.module()?;
    let fields = strukt.fields(ctx.db());
    let n_fields = fields.len();
    let fields = fields
        .into_iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .collect::<Vec<_>>();

    if fields.is_empty() {
        // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields
        return None;
    }
    let fields_omitted = n_fields - fields.len() > 0;

    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string();
    let mut pat = match strukt.kind(ctx.db()) {
        StructKind::Tuple if ctx.snippet_cap().is_some() => {
            render_tuple_as_pat(&fields, &name, fields_omitted)
        }
        StructKind::Record => {
            render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted)
        }
        _ => return None,
    };

    if ctx.completion.is_param {
        pat.push(':');
        pat.push(' ');
        pat.push_str(&name);
    }
    if ctx.snippet_cap().is_some() {
        pat.push_str("$0");
    }

    let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
        .kind(CompletionItemKind::Binding)
        .set_documentation(ctx.docs(strukt))
        .set_deprecated(ctx.is_deprecated(strukt))
        .detail(&pat);
    if let Some(snippet_cap) = ctx.snippet_cap() {
        completion = completion.insert_snippet(snippet_cap, pat);
    } else {
        completion = completion.insert_text(pat);
    }
    Some(completion.build())
}

pub(crate) fn render_variant_pat<'a>(
    ctx: RenderContext<'a>,
    variant: hir::Variant,
    local_name: Option<Name>,
) -> Option<CompletionItem> {
    let _p = profile::span("render_variant_pat");

    let module = ctx.completion.scope.module()?;
    let fields = variant.fields(ctx.db());
    let n_fields = fields.len();
    let fields = fields
        .into_iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .collect::<Vec<_>>();

    let fields_omitted = n_fields - fields.len() > 0;

    let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string();
    let mut pat = match variant.kind(ctx.db()) {
        StructKind::Tuple if ctx.snippet_cap().is_some() => {
            render_tuple_as_pat(&fields, &name, fields_omitted)
        }
        StructKind::Record => {
            render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted)
        }
        _ => return None,
    };

    if ctx.completion.is_param {
        pat.push(':');
        pat.push(' ');
        pat.push_str(&name);
    }
    if ctx.snippet_cap().is_some() {
        pat.push_str("$0");
    }
    let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
        .kind(CompletionItemKind::Binding)
        .set_documentation(ctx.docs(variant))
        .set_deprecated(ctx.is_deprecated(variant))
        .detail(&pat);
    if let Some(snippet_cap) = ctx.snippet_cap() {
        completion = completion.insert_snippet(snippet_cap, pat);
    } else {
        completion = completion.insert_text(pat);
    }
    Some(completion.build())
}

fn render_record_as_pat(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: &str,
    fields_omitted: bool,
) -> String {
    let fields = fields.iter();
    if snippet_cap.is_some() {
        format!(
            "{name} {{ {}{} }}",
            fields
                .enumerate()
                .map(|(idx, field)| format!("${{{}:{}}}", idx + 1, field.name(db)))
                .format(", "),
            if fields_omitted { ", .." } else { "" },
            name = name
        )
    } else {
        format!(
            "{name} {{ {}{} }}",
            fields.map(|field| field.name(db)).format(", "),
            if fields_omitted { ", .." } else { "" },
            name = name
        )
    }
}

fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String {
    format!(
        "{name}({}{})",
        fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "),
        if fields_omitted { ", .." } else { "" },
        name = name
    )
}
<commit_msg>Reduce code duplication in pattern completion<commit_after>//! Renderer for patterns.

use hir::{db::HirDatabase, HasVisibility, Name, StructKind};
use itertools::Itertools;

use crate::{
    config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem,
    CompletionItemKind,
};

pub(crate) fn render_struct_pat(
    ctx: RenderContext<'_>,
    strukt: hir::Struct,
    local_name: Option<Name>,
) -> Option<CompletionItem> {
    let _p = profile::span("render_struct_pat");

    let module = ctx.completion.scope.module()?;
    let fields = strukt.fields(ctx.db());
    let n_fields = fields.len();
    let fields = fields
        .into_iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .collect::<Vec<_>>();

    if fields.is_empty() {
        // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields
        return None;
    }
    let fields_omitted = n_fields - fields.len() > 0;

    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string();
    let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &fields, fields_omitted)?;

    let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
        .kind(CompletionItemKind::Binding)
        .set_documentation(ctx.docs(strukt))
        .set_deprecated(ctx.is_deprecated(strukt))
        .detail(&pat);
    if let Some(snippet_cap) = ctx.snippet_cap() {
        completion = completion.insert_snippet(snippet_cap, pat);
    } else {
        completion = completion.insert_text(pat);
    }
    Some(completion.build())
}

pub(crate) fn render_variant_pat(
    ctx: RenderContext<'_>,
    variant: hir::Variant,
    local_name: Option<Name>,
) -> Option<CompletionItem> {
    let _p = profile::span("render_variant_pat");

    let module = ctx.completion.scope.module()?;
    let fields = variant.fields(ctx.db());
    let n_fields = fields.len();
    let fields = fields
        .into_iter()
        .filter(|field| field.is_visible_from(ctx.db(), module))
        .collect::<Vec<_>>();

    let fields_omitted = n_fields - fields.len() > 0;

    let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string();
    let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &fields, fields_omitted)?;

    let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
        .kind(CompletionItemKind::Binding)
        .set_documentation(ctx.docs(variant))
        .set_deprecated(ctx.is_deprecated(variant))
        .detail(&pat);
    if let Some(snippet_cap) = ctx.snippet_cap() {
        completion = completion.insert_snippet(snippet_cap, pat);
    } else {
        completion = completion.insert_text(pat);
    }
    Some(completion.build())
}

fn render_pat(
    ctx: &RenderContext<'_>,
    name: &str,
    kind: StructKind,
    fields: &[hir::Field],
    fields_omitted: bool,
) -> Option<String> {
    let mut pat = match kind {
        StructKind::Tuple if ctx.snippet_cap().is_some() => {
            render_tuple_as_pat(&fields, &name, fields_omitted)
        }
        StructKind::Record => {
            render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted)
        }
        _ => return None,
    };

    if ctx.completion.is_param {
        pat.push(':');
        pat.push(' ');
        pat.push_str(&name);
    }
    if ctx.snippet_cap().is_some() {
        pat.push_str("$0");
    }
    Some(pat)
}

fn render_record_as_pat(
    db: &dyn HirDatabase,
    snippet_cap: Option<SnippetCap>,
    fields: &[hir::Field],
    name: &str,
    fields_omitted: bool,
) -> String {
    let fields = fields.iter();
    if snippet_cap.is_some() {
        format!(
            "{name} {{ {}{} }}",
            fields
                .enumerate()
                .map(|(idx, field)| format!("${{{}:{}}}", idx + 1, field.name(db)))
                .format(", "),
            if fields_omitted { ", .." } else { "" },
            name = name
        )
    } else {
        format!(
            "{name} {{ {}{} }}",
            fields.map(|field| field.name(db)).format(", "),
            if fields_omitted { ", .." } else { "" },
            name = name
        )
    }
}

fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String {
    format!(
        "{name}({}{})",
        fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "),
        if fields_omitted { ", .." } else { "" },
        name = name
    )
}
<|endoftext|>


<commit_before>// These methods are described in:
// http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use

use super::Result;

/// Get the current RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn current_rss() -> Result<u64> {
    os::current_rss()
}

#[cfg(target_os = "linux")]
mod os {
    use libc;
    use std::path::Path;
    use super::super::Result;
    use super::super::ProbeError;
    use super::super::file_to_string;

    #[inline]
    pub fn current_rss() -> Result<u64> {
        read_and_get_current_rss(&Path::new("/proc/self/statm"))
    }

    #[inline]
    pub fn read_and_get_current_rss(path: &Path) -> Result<u64> {
        let raw_data = try!(file_to_string(path));
        let segments: Vec<&str> = raw_data.split_whitespace().collect();

        if segments.len() < 2 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of segments".to_owned()))
        }

        let pages: u64 = try!(segments[1].parse().map_err(|_| {
            ProbeError::UnexpectedContent("Could not parse segment".to_owned())
        }));

        // Value is in pages, needs to be multiplied by the page size to get a value in KB. We ask the OS
        // for this information using sysconf.
        let pagesize = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u64;

        Ok(pages * pagesize)
    }
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use super::super::ProbeError;

    #[test]
    fn test_current_rss() {
        assert!(super::current_rss().is_ok());
        // See if it's a sort of sane value, between 1 and 10 mb
        assert!(super::current_rss().unwrap() > 1_000_000);
        assert!(super::current_rss().unwrap() < 10_000_000);
    }

    #[test]
    fn test_read_and_get_current_rss() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm");
        let value = super::os::read_and_get_current_rss(&path).unwrap();
        assert_eq!(4_661_248, value);
    }

    #[test]
    fn test_read_and_get_current_rss_wrong_path() {
        let path = Path::new("/nonsense");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_incomplete() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_incomplete");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_garbage() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_garbage");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }
}
<commit_msg>Add current rss for other pid<commit_after>// These methods are described in:
// http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use

use libc;
use super::Result;

/// Get the current RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn current_rss() -> Result<u64> {
    os::current_rss()
}

/// Get the current RSS memory of a process with given pid in KB
#[cfg(target_os = "linux")]
pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
    os::current_rss_of(pid)
}

#[cfg(target_os = "linux")]
mod os {
    use libc;
    use std::path::Path;
    use super::super::Result;
    use super::super::ProbeError;
    use super::super::file_to_string;

    #[inline]
    pub fn current_rss() -> Result<u64> {
        read_and_get_current_rss(&Path::new("/proc/self/statm"))
    }

    #[inline]
    pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
        read_and_get_current_rss(&Path::new(&format!("/proc/{}/statm", pid)))
    }

    #[inline]
    pub fn read_and_get_current_rss(path: &Path) -> Result<u64> {
        let raw_data = try!(file_to_string(path));
        let segments: Vec<&str> = raw_data.split_whitespace().collect();

        if segments.len() < 2 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of segments".to_owned()))
        }

        let pages: u64 = try!(segments[1].parse().map_err(|_| {
            ProbeError::UnexpectedContent("Could not parse segment".to_owned())
        }));

        // Value is in pages, needs to be multiplied by the page size to get a value in KB. We ask the OS
        // for this information using sysconf.
        let pagesize = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u64;

        Ok(pages * pagesize)
    }
}

#[cfg(test)]
mod tests {
    use libc;
    use std::path::Path;
    use super::super::ProbeError;

    #[test]
    fn test_current_rss() {
        assert!(super::current_rss().is_ok());
        // See if it's a sort of sane value, between 1 and 10 mb
        assert!(super::current_rss().unwrap() > 1_000_000);
        assert!(super::current_rss().unwrap() < 10_000_000);
    }

    #[test]
    fn test_read_and_get_current_rss() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm");
        let value = super::os::read_and_get_current_rss(&path).unwrap();
        assert_eq!(4_661_248, value);
    }

    #[test]
    fn test_read_and_get_current_rss_wrong_path() {
        let path = Path::new("/nonsense");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_incomplete() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_incomplete");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_garbage() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_garbage");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_current_rss_of() {
        let pid = unsafe { libc::getpid() };
        assert!(super::current_rss_of(pid).is_ok());
        // See if it's a sort of sane value, between 1 and 10 mb
        assert!(super::current_rss_of(pid).unwrap() > 1_000_000);
        assert!(super::current_rss_of(pid).unwrap() < 10_000_000);
    }

    #[test]
    fn test_current_rss_of_invalid_pid() {
        assert!(super::current_rss_of(0).is_err());
    }
}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};
use rand_core::le::read_u64_into;
use rand_core::impls::fill_bytes_via_next;
use rand_core::{RngCore, SeedableRng, Error};

/// A splitmix64 random number generator.
///
/// The splitmix algorithm is not suitable for cryptographic purposes, but is
/// very fast and has a 64 bit state.
///
/// The algorithm used here is translated from [the `splitmix64.c`
/// reference source code](http://xoshiro.di.unimi.it/splitmix64.c) by
/// Sebastiano Vigna. For `next_u32`, a more efficient mixing function taken
/// from [`dsiutils`](http://dsiutils.di.unimi.it/) is used.
#[allow(missing_copy_implementations)]
#[derive(Debug, Clone)]
pub struct SplitMix64 {
    x: u64,
}

const PHI: u64 = 0x9e3779b97f4a7c15;

impl RngCore for SplitMix64 {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        self.x = self.x.wrapping_add(PHI);
        let mut z = self.x;
        // David Stafford's
        // (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
        // "Mix4" variant of the 64-bit finalizer in Austin Appleby's
        // MurmurHash3 algorithm.
        z = (z ^ (z >> 33)).wrapping_mul(0x62A9D9ED799705F5);
        z = (z ^ (z >> 28)).wrapping_mul(0xCB24D0A5C88C35B3);
        (z >> 32) as u32
    }

    #[inline]
    fn next_u64(&mut self) -> u64 {
        self.x = self.x.wrapping_add(PHI);
        let mut z = self.x;
        z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
        z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
        z ^ (z >> 31)
    }

    #[inline]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        fill_bytes_via_next(self, dest);
    }

    #[inline]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.fill_bytes(dest);
        Ok(())
    }
}

impl SeedableRng for SplitMix64 {
    type Seed = [u8; 8];

    /// Create a new `SplitMix64`.
    fn from_seed(seed: [u8; 8]) -> SplitMix64 {
        let mut state = [0; 1];
        read_u64_into(&seed, &mut state);
        SplitMix64 {
            x: state[0],
        }
    }

    /// Seed a `SplitMix64` from a `u64`.
    fn seed_from_u64(seed: u64) -> SplitMix64 {
        let mut x = [0; 8];
        LittleEndian::write_u64(&mut x, seed);
        SplitMix64::from_seed(x)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference() {
        let mut rng = SplitMix64::seed_from_u64(1477776061723855037);
        // These values were produced with the reference implementation:
        // http://xoshiro.di.unimi.it/splitmix64.c
        let expected = vec![
            1985237415132408290, 2979275885539914483, 13511426838097143398,
            8488337342461049707, 15141737807933549159, 17093170987380407015,
            16389528042912955399, 13177319091862933652, 10841969400225389492,
            17094824097954834098, 3336622647361835228, 9678412372263018368,
            11111587619974030187, 7882215801036322410, 5709234165213761869,
            7799681907651786826, 4616320717312661886, 4251077652075509767,
            7836757050122171900, 5054003328188417616, 12919285918354108358,
            16477564761813870717, 5124667218451240549, 18099554314556827626,
            7603784838804469118, 6358551455431362471, 3037176434532249502,
            3217550417701719149, 9958699920490216947, 5965803675992506258,
            12000828378049868312, 12720568162811471118, 245696019213873792,
            8351371993958923852, 14378754021282935786, 5655432093647472106,
            5508031680350692005, 8515198786865082103, 6287793597487164412,
            14963046237722101617, 3630795823534910476, 8422285279403485710,
            10554287778700714153, 10871906555720704584, 8659066966120258468,
            9420238805069527062, 10338115333623340156, 13514802760105037173,
            14635952304031724449, 15419692541594102413,
        ];
        for &e in &expected {
            assert_eq!(rng.next_u64(), e);
        }
    }

    #[test]
    fn next_u32() {
        let mut rng = SplitMix64::seed_from_u64(10);
        // These values were produced with the reference implementation:
        // http://dsiutils.di.unimi.it/dsiutils-2.5.1-src.tar.gz
        let expected = vec![
            3930361779, 4016923089, 4113052479, 925926767, 1755287528,
            802865554, 954171070, 3724185978, 173676273, 1414488795, 12664133,
            1784889697, 1303817078, 261610523, 941280008, 2571813643,
            2954453492, 378291111, 2546873158, 3923319175, 645257028,
            3881821278, 2681538690, 3037029984, 1999958137, 1853970361,
            2989951788, 2126166628, 839962987, 3989679659, 3656977858,
            684284364, 1673258011, 170979192, 3037622326, 1600748179,
            1780764218, 1141430714, 4139736875, 3336905707, 2262051600,
            3830850262, 2430765325, 1073032139, 1668888979, 2716938970,
            4102420032, 40305196, 386350562, 2754480591, 622869439, 2129598760,
            2306038241, 4218338739, 412298926, 3453855056, 3061469690,
            4284292697, 994843708, 1591016681, 414726151, 1238182607, 18073498,
            1237631493, 351884714, 2347486264, 2488990876, 802846256, 645670443,
            957607012, 3126589776, 1966356370, 3036485766, 868696717,
            2808613630, 2070968151, 1025536863, 1743949425, 466212687,
            2994327271, 209776458, 1246125124, 3344380309, 2203947859,
            968313105, 2805485302, 197484837, 3472483632, 3931823935,
            3288490351, 4165666529, 3671080416, 689542830, 1272555356,
            1039141475, 3984640460, 4142959054, 2252788890, 2459379590,
            991872507,
        ];
        for &e in &expected {
            assert_eq!(rng.next_u32(), e);
        }
    }
}
<commit_msg>Fixed xoshiro tests.<commit_after>use byteorder::{ByteOrder, LittleEndian};
use rand_core::le::read_u64_into;
use rand_core::impls::fill_bytes_via_next;
use rand_core::{RngCore, SeedableRng, Error};

/// A splitmix64 random number generator.
///
/// The splitmix algorithm is not suitable for cryptographic purposes, but is
/// very fast and has a 64 bit state.
///
/// The algorithm used here is translated from [the `splitmix64.c`
/// reference source code](http://xoshiro.di.unimi.it/splitmix64.c) by
/// Sebastiano Vigna. For `next_u32`, a more efficient mixing function taken
/// from [`dsiutils`](http://dsiutils.di.unimi.it/) is used.
#[allow(missing_copy_implementations)]
#[derive(Debug, Clone)]
pub struct SplitMix64 {
    x: u64,
}

const PHI: u64 = 0x9e3779b97f4a7c15;

impl RngCore for SplitMix64 {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        self.x = self.x.wrapping_add(PHI);
        let mut z = self.x;
        // David Stafford's
        // (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
        // "Mix4" variant of the 64-bit finalizer in Austin Appleby's
        // MurmurHash3 algorithm.
        z = (z ^ (z >> 33)).wrapping_mul(0x62A9D9ED799705F5);
        z = (z ^ (z >> 28)).wrapping_mul(0xCB24D0A5C88C35B3);
        (z >> 32) as u32
    }

    #[inline]
    fn next_u64(&mut self) -> u64 {
        self.x = self.x.wrapping_add(PHI);
        let mut z = self.x;
        z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
        z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
        z ^ (z >> 31)
    }

    #[inline]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        fill_bytes_via_next(self, dest);
    }

    #[inline]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.fill_bytes(dest);
        Ok(())
    }
}

impl SeedableRng for SplitMix64 {
    type Seed = [u8; 8];

    /// Create a new `SplitMix64`.
    fn from_seed(seed: [u8; 8]) -> SplitMix64 {
        let mut state = [0; 1];
        read_u64_into(&seed, &mut state);
        SplitMix64 {
            x: state[0],
        }
    }

    /// Seed a `SplitMix64` from a `u64`.
    fn seed_from_u64(seed: u64) -> SplitMix64 {
        let mut x = [0; 8];
        LittleEndian::write_u64(&mut x, seed);
        SplitMix64::from_seed(x)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference() {
        let mut rng = SplitMix64::seed_from_u64(1477776061723855037);
        // These values were produced with the reference implementation:
        // http://xoshiro.di.unimi.it/splitmix64.c
        let expected : [u64 ; 20]= [
            1985237415132408290, 2979275885539914483, 13511426838097143398,
            8488337342461049707, 15141737807933549159, 17093170987380407015,
            16389528042912955399, 13177319091862933652, 10841969400225389492,
            17094824097954834098, 3336622647361835228, 9678412372263018368,
            11111587619974030187, 7882215801036322410, 5709234165213761869,
            7799681907651786826, 4616320717312661886, 4251077652075509767,
            7836757050122171900, 5054003328188417616, 12919285918354108358,
            16477564761813870717, 5124667218451240549, 18099554314556827626,
            7603784838804469118, 6358551455431362471, 3037176434532249502,
            3217550417701719149, 9958699920490216947, 5965803675992506258,
            12000828378049868312, 12720568162811471118, 245696019213873792,
            8351371993958923852, 14378754021282935786, 5655432093647472106,
            5508031680350692005, 8515198786865082103, 6287793597487164412,
            14963046237722101617, 3630795823534910476, 8422285279403485710,
            10554287778700714153, 10871906555720704584, 8659066966120258468,
            9420238805069527062, 10338115333623340156, 13514802760105037173,
            14635952304031724449, 15419692541594102413,
        ];
        for &e in &expected {
            assert_eq!(rng.next_u64(), e);
        }
    }

    #[test]
    fn next_u32() {
        let mut rng = SplitMix64::seed_from_u64(10);
        // These values were produced with the reference implementation:
        // http://dsiutils.di.unimi.it/dsiutils-2.5.1-src.tar.gz
        let expected : [u32 ; 100]= [
            3930361779, 4016923089, 4113052479, 925926767, 1755287528,
            802865554, 954171070, 3724185978, 173676273, 1414488795, 12664133,
            1784889697, 1303817078, 261610523, 941280008, 2571813643,
            2954453492, 378291111, 2546873158, 3923319175, 645257028,
            3881821278, 2681538690, 3037029984, 1999958137, 1853970361,
            2989951788, 2126166628, 839962987, 3989679659, 3656977858,
            684284364, 1673258011, 170979192, 3037622326, 1600748179,
            1780764218, 1141430714, 4139736875, 3336905707, 2262051600,
            3830850262, 2430765325, 1073032139, 1668888979, 2716938970,
            4102420032, 40305196, 386350562, 2754480591, 622869439, 2129598760,
            2306038241, 4218338739, 412298926, 3453855056, 3061469690,
            4284292697, 994843708, 1591016681, 414726151, 1238182607, 18073498,
            1237631493, 351884714, 2347486264, 2488990876, 802846256, 645670443,
            957607012, 3126589776, 1966356370, 3036485766, 868696717,
            2808613630, 2070968151, 1025536863, 1743949425, 466212687,
            2994327271, 209776458, 1246125124, 3344380309, 2203947859,
            968313105, 2805485302, 197484837, 3472483632, 3931823935,
            3288490351, 4165666529, 3671080416, 689542830, 1272555356,
            1039141475, 3984640460, 4142959054, 2252788890, 2459379590,
            991872507,
        ];
        for &e in &expected {
            assert_eq!(rng.next_u32(), e);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A vector type intended to be used for collecting from iterators onto the stack.
//!
//! Space for up to N elements is provided on the stack.  If more elements are collected, Vec is
//! used to store the values on the heap. SmallVec is similar to AccumulateVec, but adds
//! the ability to push elements.
//!
//! The N above is determined by Array's implementor, by way of an associated constant.

use std::ops::{Deref, DerefMut};
use std::iter::{IntoIterator, FromIterator};
use std::fmt::{self, Debug};
use std::mem;
use std::ptr;

use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};

use accumulate_vec::{IntoIter, AccumulateVec};
use array_vec::Array;

pub struct SmallVec(AccumulateVec);

impl Clone for SmallVec
    where A: Array,
          A::Element: Clone {
    fn clone(&self) -> Self {
        SmallVec(self.0.clone())
    }
}

impl Debug for SmallVec
    where A: Array + Debug,
          A::Element: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("SmallVec").field(&self.0).finish()
    }
}

impl SmallVec {
    pub fn new() -> Self {
        SmallVec(AccumulateVec::new())
    }

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

    pub fn with_capacity(cap: usize) -> Self {
        let mut vec = SmallVec::new();
        vec.reserve(cap);
        vec
    }

    pub fn one(el: A::Element) -> Self {
        SmallVec(AccumulateVec::one(el))
    }

    pub fn many<I: IntoIterator<Item=A::Element>>(els: I) -> Self {
        SmallVec(AccumulateVec::many(els))
    }

    pub fn expect_one(self, err: &'static str) -> A::Element {
        assert!(self.len() == 1, err);
        match self.0 {
            AccumulateVec::Array(arr) => arr.into_iter().next().unwrap(),
            AccumulateVec::Heap(vec) => vec.into_iter().next().unwrap(),
        }
    }

    /// Will reallocate onto the heap if needed.
    pub fn push(&mut self, el: A::Element) {
        self.reserve(1);
        match self.0 {
            AccumulateVec::Array(ref mut array) => array.push(el),
            AccumulateVec::Heap(ref mut vec) => vec.push(el),
        }
    }

    pub fn reserve(&mut self, n: usize) {
        match self.0 {
            AccumulateVec::Array(_) => {
                if self.len() + n > A::LEN {
                    let len = self.len();
                    let array = mem::replace(&mut self.0,
                            AccumulateVec::Heap(Vec::with_capacity(len + n)));
                    if let AccumulateVec::Array(array) = array {
                        match self.0 {
                            AccumulateVec::Heap(ref mut vec) => vec.extend(array),
                            _ => unreachable!()
                        }
                    }
                }
            }
            AccumulateVec::Heap(ref mut vec) => vec.reserve(n)
        }
    }

    pub unsafe fn set_len(&mut self, len: usize) {
        match self.0 {
            AccumulateVec::Array(ref mut arr) => arr.set_len(len),
            AccumulateVec::Heap(ref mut vec) => vec.set_len(len),
        }
    }

    pub fn insert(&mut self, index: usize, element: A::Element) {
        let len = self.len();

        // Reserve space for shifting elements to the right
        self.reserve(1);

        assert!(index <= len);

        unsafe {
            // infallible
            // The spot to put the new value
            {
                let p = self.as_mut_ptr().offset(index as isize);
                // Shift everything over to make space. (Duplicating the
                // `index`th element into two consecutive places.)
                ptr::copy(p, p.offset(1), len - index);
                // Write it in, overwriting the first copy of the `index`th
                // element.
                ptr::write(p, element);
            }
            self.set_len(len + 1);
        }
    }

    pub fn truncate(&mut self, len: usize) {
        unsafe {
            while len < self.len() {
                // Decrement len before the drop_in_place(), so a panic on Drop
                // doesn't re-drop the just-failed value.
                let newlen = self.len() - 1;
                self.set_len(newlen);
                ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen));
            }
        }
    }
}

impl Deref for SmallVec {
    type Target = AccumulateVec;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for SmallVec {
    fn deref_mut(&mut self) -> &mut AccumulateVec {
        &mut self.0
    }
}

impl FromIterator for SmallVec {
    fn from_iter(iter: I) -> Self where I: IntoIterator<Item=A::Element> {
        SmallVec(iter.into_iter().collect())
    }
}

impl Extend for SmallVec {
    fn extend<I: IntoIterator<Item=A::Element>>(&mut self, iter: I) {
        if self.is_array() {
            let iter = iter.into_iter();
            self.reserve(iter.size_hint().0);

            for el in iter {
                self.push(el);
            }
        } else {
            match self.0 {
                AccumulateVec::Heap(ref mut vec) => vec.extend(iter),
                _ => unreachable!()
            }
        }
    }
}

impl IntoIterator for SmallVec {
    type Item = A::Element;
    type IntoIter = IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl Default for SmallVec {
    fn default() -> SmallVec {
        SmallVec::new()
    }
}

impl Encodable for SmallVec
    where A: Array,
          A::Element: Encodable {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                s.emit_seq_elt(i, |s| e.encode(s))?;
            }
            Ok(())
        })
    }
}

impl Decodable for SmallVec
    where A: Array,
          A::Element: Decodable {
    fn decode<D: Decoder>(d: &mut D) -> Result<SmallVec, D::Error> {
        d.read_seq(|d, len| {
            (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect()
        })
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use super::*;

    #[bench]
    fn fill_small_vec_1_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_1_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_8_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_8_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_32_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_32_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_1_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_1_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::new();

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_8_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_8_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::new();

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_32_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_32_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::new();

            sv.extend(0..50);
        })
    }
}
<commit_msg>Another SmallVec.extend optimization<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A vector type intended to be used for collecting from iterators onto the stack.
//!
//! Space for up to N elements is provided on the stack.  If more elements are collected, Vec is
//! used to store the values on the heap. SmallVec is similar to AccumulateVec, but adds
//! the ability to push elements.
//!
//! The N above is determined by Array's implementor, by way of an associated constant.

use std::ops::{Deref, DerefMut};
use std::iter::{IntoIterator, FromIterator};
use std::fmt::{self, Debug};
use std::mem;
use std::ptr;

use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};

use accumulate_vec::{IntoIter, AccumulateVec};
use array_vec::Array;

pub struct SmallVec(AccumulateVec);

impl Clone for SmallVec
    where A: Array,
          A::Element: Clone {
    fn clone(&self) -> Self {
        SmallVec(self.0.clone())
    }
}

impl Debug for SmallVec
    where A: Array + Debug,
          A::Element: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("SmallVec").field(&self.0).finish()
    }
}

impl SmallVec {
    pub fn new() -> Self {
        SmallVec(AccumulateVec::new())
    }

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

    pub fn with_capacity(cap: usize) -> Self {
        let mut vec = SmallVec::new();
        vec.reserve(cap);
        vec
    }

    pub fn one(el: A::Element) -> Self {
        SmallVec(AccumulateVec::one(el))
    }

    pub fn many<I: IntoIterator<Item=A::Element>>(els: I) -> Self {
        SmallVec(AccumulateVec::many(els))
    }

    pub fn expect_one(self, err: &'static str) -> A::Element {
        assert!(self.len() == 1, err);
        match self.0 {
            AccumulateVec::Array(arr) => arr.into_iter().next().unwrap(),
            AccumulateVec::Heap(vec) => vec.into_iter().next().unwrap(),
        }
    }

    /// Will reallocate onto the heap if needed.
    pub fn push(&mut self, el: A::Element) {
        self.reserve(1);
        match self.0 {
            AccumulateVec::Array(ref mut array) => array.push(el),
            AccumulateVec::Heap(ref mut vec) => vec.push(el),
        }
    }

    pub fn reserve(&mut self, n: usize) {
        match self.0 {
            AccumulateVec::Array(_) => {
                if self.len() + n > A::LEN {
                    let len = self.len();
                    let array = mem::replace(&mut self.0,
                            AccumulateVec::Heap(Vec::with_capacity(len + n)));
                    if let AccumulateVec::Array(array) = array {
                        match self.0 {
                            AccumulateVec::Heap(ref mut vec) => vec.extend(array),
                            _ => unreachable!()
                        }
                    }
                }
            }
            AccumulateVec::Heap(ref mut vec) => vec.reserve(n)
        }
    }

    pub unsafe fn set_len(&mut self, len: usize) {
        match self.0 {
            AccumulateVec::Array(ref mut arr) => arr.set_len(len),
            AccumulateVec::Heap(ref mut vec) => vec.set_len(len),
        }
    }

    pub fn insert(&mut self, index: usize, element: A::Element) {
        let len = self.len();

        // Reserve space for shifting elements to the right
        self.reserve(1);

        assert!(index <= len);

        unsafe {
            // infallible
            // The spot to put the new value
            {
                let p = self.as_mut_ptr().offset(index as isize);
                // Shift everything over to make space. (Duplicating the
                // `index`th element into two consecutive places.)
                ptr::copy(p, p.offset(1), len - index);
                // Write it in, overwriting the first copy of the `index`th
                // element.
                ptr::write(p, element);
            }
            self.set_len(len + 1);
        }
    }

    pub fn truncate(&mut self, len: usize) {
        unsafe {
            while len < self.len() {
                // Decrement len before the drop_in_place(), so a panic on Drop
                // doesn't re-drop the just-failed value.
                let newlen = self.len() - 1;
                self.set_len(newlen);
                ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen));
            }
        }
    }
}

impl Deref for SmallVec {
    type Target = AccumulateVec;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for SmallVec {
    fn deref_mut(&mut self) -> &mut AccumulateVec {
        &mut self.0
    }
}

impl FromIterator for SmallVec {
    fn from_iter(iter: I) -> Self where I: IntoIterator<Item=A::Element> {
        SmallVec(iter.into_iter().collect())
    }
}

impl Extend for SmallVec {
    fn extend<I: IntoIterator<Item=A::Element>>(&mut self, iter: I) {
        let iter = iter.into_iter();
        self.reserve(iter.size_hint().0);
        match self.0 {
            AccumulateVec::Heap(ref mut vec) => vec.extend(iter),
            _ => iter.for_each(|el| self.push(el))
        }
    }
}

impl IntoIterator for SmallVec {
    type Item = A::Element;
    type IntoIter = IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl Default for SmallVec {
    fn default() -> SmallVec {
        SmallVec::new()
    }
}

impl Encodable for SmallVec
    where A: Array,
          A::Element: Encodable {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                s.emit_seq_elt(i, |s| e.encode(s))?;
            }
            Ok(())
        })
    }
}

impl Decodable for SmallVec
    where A: Array,
          A::Element: Decodable {
    fn decode<D: Decoder>(d: &mut D) -> Result<SmallVec, D::Error> {
        d.read_seq(|d, len| {
            (0..len).map(|i| d.read_seq_elt(i, |d| Decodable::decode(d))).collect()
        })
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use super::*;

    #[bench]
    fn fill_small_vec_1_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_1_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_8_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_8_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_32_10_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(10);

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_32_10_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::new();

            sv.extend(0..10);
        })
    }

    #[bench]
    fn fill_small_vec_1_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_1_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 1]> = SmallVec::new();

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_8_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_8_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 8]> = SmallVec::new();

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_32_50_with_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(50);

            sv.extend(0..50);
        })
    }

    #[bench]
    fn fill_small_vec_32_50_wo_cap(b: &mut Bencher) {
        b.iter(|| {
            let mut sv: SmallVec<[usize; 32]> = SmallVec::new();

            sv.extend(0..50);
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 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::types::{make_ident, TypeName};
use indoc::indoc;
use lazy_static::lazy_static;
use std::collections::HashMap;
use syn::{parse_quote, Type, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
    /// Is a C type whose size is not fixed (e.g. int, short)
    is_ctype: bool,
    /// Whether this is a container type cxx allows. Otherwise,
    /// if we encounter such a type as a generic, we'll replace it with
    /// a concrete instantiation.
    is_cxx_container: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
        is_ctype: bool,
        is_cxx_container: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
            is_ctype,
            is_cxx_container,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }

    fn to_type_path(&self) -> TypePath {
        let segs = self.rs_name.split("::").map(make_ident);
        parse_quote! {
            #(#segs)::*
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<TypeName, TypeName>,
}

lazy_static! {
    /// Database of known types.
    pub(crate) static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

impl TypeDatabase {
    fn get(&self, ty: &TypeName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.by_cppname.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "\n",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types(&self) -> Vec<(TypeName, bool)> {
        self.by_rs_name
            .iter()
            .map(|(tn, td)| (tn.clone(), td.by_value_safe))
            .collect()
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, typ: &TypePath) -> bool {
        let tn = TypeName::from_type_path(typ);
        let td = self.get(&tn);
        if let Some(td) = td {
            td.de_referencicate
        } else {
            false
        }
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn known_type_substitute_path(&self, typ: &TypePath) -> Option<TypePath> {
        let tn = TypeName::from_type_path(typ);
        self.get(&tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &TypeName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &TypeName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &TypeName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    pub(crate) fn is_ctype(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|td| td.is_ctype).unwrap_or(false)
    }

    pub(crate) fn is_cxx_acceptable_generic(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|x| x.is_cxx_container).unwrap_or(false)
    }
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "CxxVector".into(),
        "std::vector".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "SharedPtr".into(),
        "std::shared_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
        false,
        false,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
            false,
            false,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
    ));

    do_insert(TypeDetails::new(
        "Pin".into(),
        "Pin".into(),
        true, // because this is actually Pin<&something>
        PreludePolicy::Exclude,
        false,
        false,
        false,
    ));

    let mut insert_ctype = |cname: &str| {
        let td = TypeDetails::new(
            format!("std::os::raw::c_{}", cname),
            cname.into(),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
        let td = TypeDetails::new(
            format!("std::os::raw::c_u{}", cname),
            format!("unsigned {}", cname),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");
    insert_ctype("char");

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(
            TypeName::new_from_user_input(&td.cpp_name),
            TypeName::new_from_user_input(&td.rs_name),
        );
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = TypeName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
        }
        _ => false,
    }
}
<commit_msg>Insist vectors are wrapped in unique_ptrs.<commit_after>// Copyright 2020 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::types::{make_ident, TypeName};
use indoc::indoc;
use lazy_static::lazy_static;
use std::collections::HashMap;
use syn::{parse_quote, Type, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
    /// Is a C type whose size is not fixed (e.g. int, short)
    is_ctype: bool,
    /// Whether this is a container type cxx allows. Otherwise,
    /// if we encounter such a type as a generic, we'll replace it with
    /// a concrete instantiation.
    is_cxx_container: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
        is_ctype: bool,
        is_cxx_container: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
            is_ctype,
            is_cxx_container,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }

    fn to_type_path(&self) -> TypePath {
        let segs = self.rs_name.split("::").map(make_ident);
        parse_quote! {
            #(#segs)::*
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<TypeName, TypeName>,
}

lazy_static! {
    /// Database of known types.
    pub(crate) static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

impl TypeDatabase {
    fn get(&self, ty: &TypeName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.by_cppname.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "\n",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types(&self) -> Vec<(TypeName, bool)> {
        self.by_rs_name
            .iter()
            .map(|(tn, td)| (tn.clone(), td.by_value_safe))
            .collect()
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, typ: &TypePath) -> bool {
        let tn = TypeName::from_type_path(typ);
        let td = self.get(&tn);
        if let Some(td) = td {
            td.de_referencicate
        } else {
            false
        }
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn known_type_substitute_path(&self, typ: &TypePath) -> Option<TypePath> {
        let tn = TypeName::from_type_path(typ);
        self.get(&tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &TypeName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &TypeName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &TypeName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    pub(crate) fn is_ctype(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|td| td.is_ctype).unwrap_or(false)
    }

    pub(crate) fn is_cxx_acceptable_generic(&self, ty: &TypeName) -> bool {
        self.get(ty).map(|x| x.is_cxx_container).unwrap_or(false)
    }
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "CxxVector".into(),
        "std::vector".into(),
        false,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "SharedPtr".into(),
        "std::shared_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
        false,
        true,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
        false,
        false,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
        false,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
            false,
            false,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
        false,
        false,
    ));

    do_insert(TypeDetails::new(
        "Pin".into(),
        "Pin".into(),
        true, // because this is actually Pin<&something>
        PreludePolicy::Exclude,
        false,
        false,
        false,
    ));

    let mut insert_ctype = |cname: &str| {
        let td = TypeDetails::new(
            format!("std::os::raw::c_{}", cname),
            cname.into(),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
        let td = TypeDetails::new(
            format!("std::os::raw::c_u{}", cname),
            format!("unsigned {}", cname),
            true,
            PreludePolicy::Exclude,
            false,
            true,
            false,
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");
    insert_ctype("char");

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(
            TypeName::new_from_user_input(&td.cpp_name),
            TypeName::new_from_user_input(&td.rs_name),
        );
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = TypeName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
        }
        _ => false,
    }
}
<|endoftext|>