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

use std::collections::HashMap;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

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

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    #[allow(dead_code)]
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// A mutable iterator through Pools.
    #[allow(dead_code)]
    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.items.iter_mut()
    }

    /// Removes the Pool corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // There is guaranteed to be a last because there is at least
            // one index into the items.

            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items.last().unwrap();
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the Pool corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // There is guaranteed to be a last because there is at least
            // one index into the items.

            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items.last().unwrap();
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map.insert(item.name().into(), future_last_index);
        self.uuid_map.insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}
<commit_msg>Add a len() method to Table<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

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

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

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    #[allow(dead_code)]
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// A mutable iterator through Pools.
    #[allow(dead_code)]
    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.items.iter_mut()
    }

    /// Removes the Pool corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // There is guaranteed to be a last because there is at least
            // one index into the items.

            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items.last().unwrap();
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the Pool corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // There is guaranteed to be a last because there is at least
            // one index into the items.

            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items.last().unwrap();
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map.insert(item.name().into(), future_last_index);
        self.uuid_map.insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use neon_runtime::raw::Env;
use neon_runtime::tsfn::ThreadsafeFunction;

use crate::context::{Context, TaskContext};
use crate::result::NeonResult;

type Callback = Box<dyn FnOnce(Env) + Send + 'static>;

/// Channel for scheduling Rust closures to execute on the JavaScript main thread.
///
/// Cloning a `Channel` will create a new channel that shares a backing queue for
/// events.
///
/// # Example
///
/// The following example spawns a standard Rust thread to complete a computation
/// and calls back to a JavaScript function asynchronously with the result.
///
/// ```
/// # use neon::prelude::*;
/// # fn fibonacci(_: f64) -> f64 { todo!() }
/// fn async_fibonacci(mut cx: FunctionContext) -> JsResult<JsUndefined> {
///     // These types (`f64`, `Root<JsFunction>`, `Channel`) may all be sent
///     // across threads.
///     let n = cx.argument::<JsNumber>(0)?.value(&mut cx);
///     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
///     let channel = cx.channel();
///
///     // Spawn a thread to complete the execution. This will _not_ block the
///     // JavaScript event loop.
///     std::thread::spawn(move || {
///         let result = fibonacci(n);
///
///         // Send a closure as a task to be executed by the JavaScript event
///         // loop. This _will_ block the event loop while executing.
///         channel.send(move |mut cx| {
///             let callback = callback.into_inner(&mut cx);
///             let this = cx.undefined();
///             let null = cx.null();
///             let args = vec![
///                 cx.null().upcast::<JsValue>(),
///                 cx.number(result).upcast(),
///             ];
///
///             callback.call(&mut cx, this, args)?;
///
///             Ok(())
///         });
///     });
///
///     Ok(cx.undefined())
/// }
/// ```

pub struct Channel {
    state: Arc<ChannelState>,
    has_ref: bool,
}

impl std::fmt::Debug for Channel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("Channel")
    }
}

impl Channel {
    /// Creates an unbounded channel for scheduling closures on the JavaScript
    /// main thread
    pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
        Self {
            state: Arc::new(ChannelState::new(cx)),
            has_ref: true,
        }
    }

    /// Allow the Node event loop to exit while this `Channel` exists.
    /// _Idempotent_
    pub fn unref<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
        // Already unreferenced
        if !self.has_ref {
            return self;
        }

        self.has_ref = false;
        self.state.unref(cx);
        self
    }

    /// Prevent the Node event loop from exiting while this `Channel` exists. (Default)
    /// _Idempotent_
    pub fn reference<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
        // Already referenced
        if self.has_ref {
            return self;
        }

        self.has_ref = true;
        self.state.reference(cx);
        self
    }

    /// Schedules a closure to execute on the JavaScript thread that created this Channel
    /// Panics if there is a libuv error
    pub fn send<F>(&self, f: F)
    where
        F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
    {
        self.try_send(f).unwrap()
    }

    /// Schedules a closure to execute on the JavaScript thread that created this Channel
    /// Returns an `Error` if the task could not be scheduled.
    pub fn try_send<F>(&self, f: F) -> Result<(), SendError>
    where
        F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
    {
        let callback = Box::new(move |env| {
            let env = unsafe { std::mem::transmute(env) };

            // Note: It is sufficient to use `TaskContext`'s `InheritedHandleScope` because
            // N-API creates a `HandleScope` before calling the callback.
            TaskContext::with_context(env, move |cx| {
                let _ = f(cx);
            });
        });

        self.state.tsfn.call(callback, None).map_err(|_| SendError)
    }

    /// Returns a boolean indicating if this `Channel` will prevent the Node event
    /// loop from exiting.
    pub fn has_ref(&self) -> bool {
        self.has_ref
    }
}

impl Clone for Channel {
    /// Returns a clone of the Channel instance that shares the internal
    /// unbounded queue with the original channel. Scheduling callbacks on the
    /// same queue is faster than using separate channels, but might lead to
    /// starvation if one of the threads posts significantly more callbacks on
    /// the channel than the other one.
    ///
    /// Cloned and referenced Channel instances might trigger additional
    /// event-loop tick when dropped. Channel can be wrapped into an Arc and
    /// shared between different threads/callers to avoid this.
    fn clone(&self) -> Self {
        // Not referenced, we can simply clone the fields
        if !self.has_ref {
            return Self {
                state: self.state.clone(),
                has_ref: false,
            };
        }

        let state = Arc::clone(&self.state);

        // Only need to increase the ref count since the tsfn is already referenced
        state.ref_count.fetch_add(1, Ordering::Relaxed);

        Self {
            state,
            has_ref: true,
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        // Not a referenced event queue
        if !self.has_ref {
            return;
        }

        // It was only us who kept the `ChannelState` alive. No need to unref
        // the `tsfn`, because it is going to be dropped once this function
        // returns.
        if Arc::strong_count(&self.state) == 1 {
            return;
        }

        // The ChannelState is dropped on a worker thread. We have to `unref`
        // the tsfn on the UV thread after all pending closures. Note that in
        // the most of scenarios the optimization in N-API layer would coalesce
        // `send()` with a user-supplied closure and the unref send here into a
        // single UV tick.
        //
        // If this ever has to be optimized a second `Arc` could be used to wrap
        // the `state` and it could be cloned in `try_send` and unref'ed on the
        // UV thread if strong reference count goes to 0.
        let state = Arc::clone(&self.state);

        self.send(move |mut cx| {
            state.unref(&mut cx);
            Ok(())
        });
    }
}

/// Error indicating that a closure was unable to be scheduled to execute on the event loop.
pub struct SendError;

impl std::fmt::Display for SendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "SendError")
    }
}

impl std::fmt::Debug for SendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(self, f)
    }
}

impl std::error::Error for SendError {}

struct ChannelState {
    tsfn: ThreadsafeFunction<Callback>,
    ref_count: AtomicUsize,
}

impl ChannelState {
    fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
        let tsfn = unsafe { ThreadsafeFunction::new(cx.env().to_raw(), Self::callback) };
        Self {
            tsfn,
            ref_count: AtomicUsize::new(1),
        }
    }

    fn reference<'a, C: Context<'a>>(&self, cx: &mut C) {
        // We can use relaxed ordering because `reference()` can only be called
        // on the Event-Loop thread.
        if self.ref_count.fetch_add(1, Ordering::Relaxed) != 0 {
            return;
        }

        unsafe {
            self.tsfn.reference(cx.env().to_raw());
        }
    }

    fn unref<'a, C: Context<'a>>(&self, cx: &mut C) {
        // We can use relaxed ordering because `unref()` can only be called
        // on the Event-Loop thread.
        if self.ref_count.fetch_sub(1, Ordering::Relaxed) != 1 {
            return;
        }

        unsafe {
            self.tsfn.unref(cx.env().to_raw());
        }
    }

    // Monomorphized trampoline funciton for calling the user provided closure
    fn callback(env: Option<Env>, callback: Callback) {
        if let Some(env) = env {
            callback(env);
        } else {
            crate::context::internal::IS_RUNNING.with(|v| {
                *v.borrow_mut() = false;
            });
        }
    }
}
<commit_msg>doc(neon): Add documentation on failure causes to try_send<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use neon_runtime::raw::Env;
use neon_runtime::tsfn::ThreadsafeFunction;

use crate::context::{Context, TaskContext};
use crate::result::NeonResult;

type Callback = Box<dyn FnOnce(Env) + Send + 'static>;

/// Channel for scheduling Rust closures to execute on the JavaScript main thread.
///
/// Cloning a `Channel` will create a new channel that shares a backing queue for
/// events.
///
/// # Example
///
/// The following example spawns a standard Rust thread to complete a computation
/// and calls back to a JavaScript function asynchronously with the result.
///
/// ```
/// # use neon::prelude::*;
/// # fn fibonacci(_: f64) -> f64 { todo!() }
/// fn async_fibonacci(mut cx: FunctionContext) -> JsResult<JsUndefined> {
///     // These types (`f64`, `Root<JsFunction>`, `Channel`) may all be sent
///     // across threads.
///     let n = cx.argument::<JsNumber>(0)?.value(&mut cx);
///     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
///     let channel = cx.channel();
///
///     // Spawn a thread to complete the execution. This will _not_ block the
///     // JavaScript event loop.
///     std::thread::spawn(move || {
///         let result = fibonacci(n);
///
///         // Send a closure as a task to be executed by the JavaScript event
///         // loop. This _will_ block the event loop while executing.
///         channel.send(move |mut cx| {
///             let callback = callback.into_inner(&mut cx);
///             let this = cx.undefined();
///             let null = cx.null();
///             let args = vec![
///                 cx.null().upcast::<JsValue>(),
///                 cx.number(result).upcast(),
///             ];
///
///             callback.call(&mut cx, this, args)?;
///
///             Ok(())
///         });
///     });
///
///     Ok(cx.undefined())
/// }
/// ```

pub struct Channel {
    state: Arc<ChannelState>,
    has_ref: bool,
}

impl std::fmt::Debug for Channel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("Channel")
    }
}

impl Channel {
    /// Creates an unbounded channel for scheduling closures on the JavaScript
    /// main thread
    pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
        Self {
            state: Arc::new(ChannelState::new(cx)),
            has_ref: true,
        }
    }

    /// Allow the Node event loop to exit while this `Channel` exists.
    /// _Idempotent_
    pub fn unref<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
        // Already unreferenced
        if !self.has_ref {
            return self;
        }

        self.has_ref = false;
        self.state.unref(cx);
        self
    }

    /// Prevent the Node event loop from exiting while this `Channel` exists. (Default)
    /// _Idempotent_
    pub fn reference<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
        // Already referenced
        if self.has_ref {
            return self;
        }

        self.has_ref = true;
        self.state.reference(cx);
        self
    }

    /// Schedules a closure to execute on the JavaScript thread that created this Channel
    /// Panics if there is a libuv error
    pub fn send<F>(&self, f: F)
    where
        F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
    {
        self.try_send(f).unwrap()
    }

    /// Schedules a closure to execute on the JavaScript thread that created this Channel
    /// Returns an `Error` if the task could not be scheduled.
    ///
    /// See [`SendError`] for additional details on failure causes.
    pub fn try_send<F>(&self, f: F) -> Result<(), SendError>
    where
        F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
    {
        let callback = Box::new(move |env| {
            let env = unsafe { std::mem::transmute(env) };

            // Note: It is sufficient to use `TaskContext`'s `InheritedHandleScope` because
            // N-API creates a `HandleScope` before calling the callback.
            TaskContext::with_context(env, move |cx| {
                let _ = f(cx);
            });
        });

        self.state.tsfn.call(callback, None).map_err(|_| SendError)
    }

    /// Returns a boolean indicating if this `Channel` will prevent the Node event
    /// loop from exiting.
    pub fn has_ref(&self) -> bool {
        self.has_ref
    }
}

impl Clone for Channel {
    /// Returns a clone of the Channel instance that shares the internal
    /// unbounded queue with the original channel. Scheduling callbacks on the
    /// same queue is faster than using separate channels, but might lead to
    /// starvation if one of the threads posts significantly more callbacks on
    /// the channel than the other one.
    ///
    /// Cloned and referenced Channel instances might trigger additional
    /// event-loop tick when dropped. Channel can be wrapped into an Arc and
    /// shared between different threads/callers to avoid this.
    fn clone(&self) -> Self {
        // Not referenced, we can simply clone the fields
        if !self.has_ref {
            return Self {
                state: self.state.clone(),
                has_ref: false,
            };
        }

        let state = Arc::clone(&self.state);

        // Only need to increase the ref count since the tsfn is already referenced
        state.ref_count.fetch_add(1, Ordering::Relaxed);

        Self {
            state,
            has_ref: true,
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        // Not a referenced event queue
        if !self.has_ref {
            return;
        }

        // It was only us who kept the `ChannelState` alive. No need to unref
        // the `tsfn`, because it is going to be dropped once this function
        // returns.
        if Arc::strong_count(&self.state) == 1 {
            return;
        }

        // The ChannelState is dropped on a worker thread. We have to `unref`
        // the tsfn on the UV thread after all pending closures. Note that in
        // the most of scenarios the optimization in N-API layer would coalesce
        // `send()` with a user-supplied closure and the unref send here into a
        // single UV tick.
        //
        // If this ever has to be optimized a second `Arc` could be used to wrap
        // the `state` and it could be cloned in `try_send` and unref'ed on the
        // UV thread if strong reference count goes to 0.
        let state = Arc::clone(&self.state);

        self.send(move |mut cx| {
            state.unref(&mut cx);
            Ok(())
        });
    }
}

/// Error indicating that a closure was unable to be scheduled to execute on the event loop.
///
/// The most likely cause of a failure is that Node is shutting down. This may occur if the
/// process is forcefully exiting even if the channel is referenced. For example, by calling
/// `process.exit()`.
//
// NOTE: These docs will need to be updated to include `QueueFull` if bounded queues are
// implemented.
pub struct SendError;

impl std::fmt::Display for SendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "SendError")
    }
}

impl std::fmt::Debug for SendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(self, f)
    }
}

impl std::error::Error for SendError {}

struct ChannelState {
    tsfn: ThreadsafeFunction<Callback>,
    ref_count: AtomicUsize,
}

impl ChannelState {
    fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
        let tsfn = unsafe { ThreadsafeFunction::new(cx.env().to_raw(), Self::callback) };
        Self {
            tsfn,
            ref_count: AtomicUsize::new(1),
        }
    }

    fn reference<'a, C: Context<'a>>(&self, cx: &mut C) {
        // We can use relaxed ordering because `reference()` can only be called
        // on the Event-Loop thread.
        if self.ref_count.fetch_add(1, Ordering::Relaxed) != 0 {
            return;
        }

        unsafe {
            self.tsfn.reference(cx.env().to_raw());
        }
    }

    fn unref<'a, C: Context<'a>>(&self, cx: &mut C) {
        // We can use relaxed ordering because `unref()` can only be called
        // on the Event-Loop thread.
        if self.ref_count.fetch_sub(1, Ordering::Relaxed) != 1 {
            return;
        }

        unsafe {
            self.tsfn.unref(cx.env().to_raw());
        }
    }

    // Monomorphized trampoline funciton for calling the user provided closure
    fn callback(env: Option<Env>, callback: Callback) {
        if let Some(env) = env {
            callback(env);
        } else {
            crate::context::internal::IS_RUNNING.with(|v| {
                *v.borrow_mut() = false;
            });
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone, PartialEq)]
pub enum Allergen {
    Eggs = 0x0000_0001,
    Peanuts = 0x0000_0002,
    Shellfish = 0x0000_0004,
    Strawberries = 0x0000_0008,
    Tomatoes = 0x0000_0010,
    Chocolate = 0x0000_0020,
    Pollen = 0x0000_0040,
    Cats = 0x0000_0080,
}

#[derive(Debug)]
pub struct Allergies {
    result: u32,
}

impl Allergies {
    pub fn new(score: u32) -> Allergies {
        Allergies { result: score }
    }

    pub fn is_allergic_to(&self, item: &Allergen) -> bool {
        self.result & (*item).clone() as u32 != 0
    }

    pub fn allergies(&self) -> Vec<Allergen> {
        let mut result: Vec<Allergen> = Vec::new();

        let value = self.result;

        let mut item = Allergen::Eggs as u32;
        if value & item == item {
            result.push(Allergen::Eggs);
        }

        item = Allergen::Peanuts as u32;
        if value & item == item {
            result.push(Allergen::Peanuts);
        }

        item = Allergen::Shellfish as u32;
        if value & item == item {
            result.push(Allergen::Shellfish);
        }

        item = Allergen::Strawberries as u32;
        if value & item == item {
            result.push(Allergen::Strawberries);
        }

        item = Allergen::Tomatoes as u32;
        if value & item == item {
            result.push(Allergen::Tomatoes);
        }

        item = Allergen::Chocolate as u32;
        if value & item == item {
            result.push(Allergen::Chocolate);
        }

        item = Allergen::Pollen as u32;
        if value & item == item {
            result.push(Allergen::Pollen);
        }

        item = Allergen::Cats as u32;
        if value & item == item {
            result.push(Allergen::Cats)
        }

        result
    }
}
<commit_msg>Clean up rust code for allergies<commit_after>#[derive(Debug, Clone, PartialEq)]
#[repr(usize)]
pub enum Allergen {
    Eggs,
    Peanuts,
    Shellfish,
    Strawberries,
    Tomatoes,
    Chocolate,
    Pollen,
    Cats,
    Max,
}

impl From<usize> for Allergen {
    #[inline]
    fn from(t: usize) -> Allergen {
        assert!(t < Allergen::Max as usize);
        unsafe { std::mem::transmute(t) }
    }
}

#[derive(Debug)]
pub struct Allergies(usize);

impl Allergies {
    pub fn new(score: usize) -> Allergies {
        Allergies(score)
    }

    pub fn is_allergic_to(&self, item: &Allergen) -> bool {
        let v = (*item).clone() as usize;

        self.0 & (1usize << v) != 0
    }

    pub fn allergies(&self) -> Vec<Allergen> {
        let lower = Allergen::Eggs as usize;
        let upper = Allergen::Max as usize;

        (lower..upper)
            .filter(|x| self.is_allergic_to(&Allergen::from(*x)))
            .map(|x| Allergen::from(x))
            .collect()
    }
}
<|endoftext|>


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

//! This module implements structured cloning, as defined by [HTML]
//! (https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).

use dom::bindings::conversions::root_from_handleobject;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::reflector::DomObject;
use dom::bindings::root::DomRoot;
use dom::blob::{Blob, BlobImpl};
use dom::globalscope::GlobalScope;
use js::jsapi::{JSAutoCompartment, JSContext};
use js::jsapi::{JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter};
use js::jsapi::{JS_ClearPendingException, JSObject};
use js::jsapi::{JS_ReadBytes, JS_WriteBytes};
use js::jsapi::{JS_ReadUint32Pair, JS_WriteUint32Pair};
use js::jsapi::HandleObject as RawHandleObject;
use js::jsapi::JS_STRUCTURED_CLONE_VERSION;
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
use js::jsapi::TransferableOwnership;
use js::rust::{Handle, HandleValue, MutableHandleValue};
use js::rust::wrappers::{JS_WriteStructuredClone, JS_ReadStructuredClone};
use libc::size_t;
use std::os::raw;
use std::ptr;
use std::slice;

// TODO: Should we add Min and Max const to https://github.com/servo/rust-mozjs/blob/master/src/consts.rs?
// TODO: Determine for sure which value Min and Max should have.
// NOTE: Current values found at https://dxr.mozilla.org/mozilla-central/
// rev/ff04d410e74b69acfab17ef7e73e7397602d5a68/js/public/StructuredClone.h#323
#[repr(u32)]
enum StructuredCloneTags {
    /// To support additional types, add new tags with values incremented from the last one before Max.
    Min = 0xFFFF8000,
    DomBlob = 0xFFFF8001,
    Max = 0xFFFFFFFF,
}

#[cfg(target_pointer_width = "64")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
                       length: usize) {
  let high: u32 = (length >> 32) as u32;
  let low: u32 = length as u32;
  assert!(JS_WriteUint32Pair(w, high, low));
}

#[cfg(target_pointer_width = "32")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
                       length: usize) {
  assert!(JS_WriteUint32Pair(w, length as u32, 0));
}

#[cfg(target_pointer_width = "64")]
unsafe fn read_length(r: *mut JSStructuredCloneReader)
                      -> usize {
  let mut high: u32 = 0;
  let mut low: u32 = 0;
  assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32));
  return (low << high) as usize;
}

#[cfg(target_pointer_width = "32")]
unsafe fn read_length(r: *mut JSStructuredCloneReader)
                      -> usize {
  let mut length: u32 = 0;
  let mut zero: u32 = 0;
  assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32));
  return length as usize;
}

struct StructuredCloneWriter {
    w: *mut JSStructuredCloneWriter,
}

impl StructuredCloneWriter {
    unsafe fn write_slice(&self, v: &[u8]) {
        let type_length = v.len();
        write_length(self.w, type_length);
        assert!(JS_WriteBytes(self.w, v.as_ptr() as *const raw::c_void, type_length));
    }
    unsafe fn write_str(&self, s: &str) {
        self.write_slice(s.as_bytes());
    }
}

struct StructuredCloneReader {
    r: *mut JSStructuredCloneReader,
}

impl StructuredCloneReader {
    unsafe fn read_bytes(&self) -> Vec<u8> {
        let mut bytes = vec![0u8; read_length(self.r)];
        let blob_length = bytes.len();
        assert!(JS_ReadBytes(self.r, bytes.as_mut_ptr() as *mut raw::c_void, blob_length));
        return bytes;
    }
    unsafe fn read_str(&self) -> String {
        let str_buffer = self.read_bytes();
        return String::from_utf8_unchecked(str_buffer);
    }
}

unsafe fn read_blob(cx: *mut JSContext,
                    r: *mut JSStructuredCloneReader)
                    -> *mut JSObject {
    let structured_reader = StructuredCloneReader { r: r };
    let blob_buffer = structured_reader.read_bytes();
    let type_str = structured_reader.read_str();
    let target_global = GlobalScope::from_context(cx);
    let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
    return blob.reflector().get_jsobject().get()
}

unsafe fn write_blob(blob: DomRoot<Blob>,
                     w: *mut JSStructuredCloneWriter)
                     -> Result<(), ()> {
    let structured_writer = StructuredCloneWriter { w: w };
    let blob_vec = blob.get_bytes()?;
    assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0));
    structured_writer.write_slice(&blob_vec);
    structured_writer.write_str(&blob.type_string());
    return Ok(())
}

unsafe extern "C" fn read_callback(cx: *mut JSContext,
                                   r: *mut JSStructuredCloneReader,
                                   tag: u32,
                                   _data: u32,
                                   _closure: *mut raw::c_void)
                                   -> *mut JSObject {
    assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
    assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
    if tag == StructuredCloneTags::DomBlob as u32 {
        return read_blob(cx, r)
    }
    return ptr::null_mut()
}

unsafe extern "C" fn write_callback(_cx: *mut JSContext,
                                    w: *mut JSStructuredCloneWriter,
                                    obj: RawHandleObject,
                                    _closure: *mut raw::c_void)
                                    -> bool {
    if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
        return write_blob(blob, w).is_ok()
    }
    return false
}

unsafe extern "C" fn read_transfer_callback(_cx: *mut JSContext,
                                            _r: *mut JSStructuredCloneReader,
                                            _tag: u32,
                                            _content: *mut raw::c_void,
                                            _extra_data: u64,
                                            _closure: *mut raw::c_void,
                                            _return_object: RawMutableHandleObject)
                                            -> bool {
    false
}

unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext,
                                             _obj: RawHandleObject,
                                             _closure: *mut raw::c_void,
                                             _tag: *mut u32,
                                             _ownership: *mut TransferableOwnership,
                                             _content:  *mut *mut raw::c_void,
                                             _extra_data: *mut u64)
                                             -> bool {
    false
}

unsafe extern "C" fn free_transfer_callback(_tag: u32,
                                            _ownership: TransferableOwnership,
                                            _content: *mut raw::c_void,
                                            _extra_data: u64,
                                            _closure: *mut raw::c_void) {
}

unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {
}

static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
    read: Some(read_callback),
    write: Some(write_callback),
    reportError: Some(report_error_callback),
    readTransfer: Some(read_transfer_callback),
    writeTransfer: Some(write_transfer_callback),
    freeTransfer: Some(free_transfer_callback),
};

/// A buffer for a structured clone.
pub enum StructuredCloneData {
    /// A non-serializable (default) variant
    Struct(*mut u64, size_t),
    /// A variant that can be serialized
    Vector(Vec<u8>)
}

impl StructuredCloneData {
    /// Writes a structured clone. Returns a `DataClone` error if that fails.
    pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
        let mut data = ptr::null_mut();
        let mut nbytes = 0;
        let result = unsafe {
            JS_WriteStructuredClone(cx,
                                    message,
                                    &mut data,
                                    &mut nbytes,
                                    &STRUCTURED_CLONE_CALLBACKS,
                                    ptr::null_mut(),
                                    HandleValue::undefined())
        };
        if !result {
            unsafe {
                JS_ClearPendingException(cx);
            }
            return Err(Error::DataClone);
        }
        Ok(StructuredCloneData::Struct(data, nbytes))
    }

    /// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
    pub fn move_to_arraybuffer(self) -> Vec<u8> {
        match self {
            StructuredCloneData::Struct(data, nbytes) => {
                unsafe {
                    slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
                }
            }
            StructuredCloneData::Vector(msg) => msg
        }
    }

    /// Reads a structured clone.
    ///
    /// Panics if `JS_ReadStructuredClone` fails.
    fn read_clone(global: &GlobalScope,
                  data: *mut u64,
                  nbytes: size_t,
                  rval: MutableHandleValue) {
        let cx = global.get_cx();
        let globalhandle = global.reflector().get_jsobject();
        let _ac = JSAutoCompartment::new(cx, globalhandle.get());
        unsafe {
            assert!(JS_ReadStructuredClone(cx,
                                           data,
                                           nbytes,
                                           JS_STRUCTURED_CLONE_VERSION,
                                           rval,
                                           &STRUCTURED_CLONE_CALLBACKS,
                                           ptr::null_mut()));
        }
    }

    /// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
    pub fn read(self, global: &GlobalScope, rval: MutableHandleValue) {
        match self {
            StructuredCloneData::Vector(mut vec_msg) => {
                let nbytes = vec_msg.len();
                let data = vec_msg.as_mut_ptr() as *mut u64;
                StructuredCloneData::read_clone(global, data, nbytes, rval);
            }
            StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
        }
    }
}

unsafe impl Send for StructuredCloneData {}
<commit_msg>Auto merge of #21218 - gterzian:root_cloned_blobs, r=jdm<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/. */

//! This module implements structured cloning, as defined by [HTML]
//! (https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data).

use dom::bindings::conversions::root_from_handleobject;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::reflector::DomObject;
use dom::bindings::root::DomRoot;
use dom::blob::{Blob, BlobImpl};
use dom::globalscope::GlobalScope;
use js::jsapi::{JSAutoCompartment, JSContext};
use js::jsapi::{JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter};
use js::jsapi::{JS_ClearPendingException, JSObject};
use js::jsapi::{JS_ReadBytes, JS_WriteBytes};
use js::jsapi::{JS_ReadUint32Pair, JS_WriteUint32Pair};
use js::jsapi::HandleObject as RawHandleObject;
use js::jsapi::JS_STRUCTURED_CLONE_VERSION;
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
use js::jsapi::TransferableOwnership;
use js::rust::{Handle, HandleValue, MutableHandleValue};
use js::rust::wrappers::{JS_WriteStructuredClone, JS_ReadStructuredClone};
use libc::size_t;
use std::os::raw;
use std::ptr;
use std::slice;

// TODO: Should we add Min and Max const to https://github.com/servo/rust-mozjs/blob/master/src/consts.rs?
// TODO: Determine for sure which value Min and Max should have.
// NOTE: Current values found at https://dxr.mozilla.org/mozilla-central/
// rev/ff04d410e74b69acfab17ef7e73e7397602d5a68/js/public/StructuredClone.h#323
#[repr(u32)]
enum StructuredCloneTags {
    /// To support additional types, add new tags with values incremented from the last one before Max.
    Min = 0xFFFF8000,
    DomBlob = 0xFFFF8001,
    Max = 0xFFFFFFFF,
}

#[cfg(target_pointer_width = "64")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
                       length: usize) {
  let high: u32 = (length >> 32) as u32;
  let low: u32 = length as u32;
  assert!(JS_WriteUint32Pair(w, high, low));
}

#[cfg(target_pointer_width = "32")]
unsafe fn write_length(w: *mut JSStructuredCloneWriter,
                       length: usize) {
  assert!(JS_WriteUint32Pair(w, length as u32, 0));
}

#[cfg(target_pointer_width = "64")]
unsafe fn read_length(r: *mut JSStructuredCloneReader)
                      -> usize {
  let mut high: u32 = 0;
  let mut low: u32 = 0;
  assert!(JS_ReadUint32Pair(r, &mut high as *mut u32, &mut low as *mut u32));
  return (low << high) as usize;
}

#[cfg(target_pointer_width = "32")]
unsafe fn read_length(r: *mut JSStructuredCloneReader)
                      -> usize {
  let mut length: u32 = 0;
  let mut zero: u32 = 0;
  assert!(JS_ReadUint32Pair(r, &mut length as *mut u32, &mut zero as *mut u32));
  return length as usize;
}

struct StructuredCloneWriter {
    w: *mut JSStructuredCloneWriter,
}

impl StructuredCloneWriter {
    unsafe fn write_slice(&self, v: &[u8]) {
        let type_length = v.len();
        write_length(self.w, type_length);
        assert!(JS_WriteBytes(self.w, v.as_ptr() as *const raw::c_void, type_length));
    }
    unsafe fn write_str(&self, s: &str) {
        self.write_slice(s.as_bytes());
    }
}

struct StructuredCloneReader {
    r: *mut JSStructuredCloneReader,
}

impl StructuredCloneReader {
    unsafe fn read_bytes(&self) -> Vec<u8> {
        let mut bytes = vec![0u8; read_length(self.r)];
        let blob_length = bytes.len();
        assert!(JS_ReadBytes(self.r, bytes.as_mut_ptr() as *mut raw::c_void, blob_length));
        return bytes;
    }
    unsafe fn read_str(&self) -> String {
        let str_buffer = self.read_bytes();
        return String::from_utf8_unchecked(str_buffer);
    }
}

unsafe fn read_blob(cx: *mut JSContext,
                    r: *mut JSStructuredCloneReader,
                    sc_holder: &mut StructuredCloneHolder)
                    -> *mut JSObject {
    let structured_reader = StructuredCloneReader { r: r };
    let blob_buffer = structured_reader.read_bytes();
    let type_str = structured_reader.read_str();
    let target_global = GlobalScope::from_context(cx);
    let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
    let js_object = blob.reflector().get_jsobject().get();
    sc_holder.blob = Some(blob);
    js_object
}

unsafe fn write_blob(blob: DomRoot<Blob>,
                     w: *mut JSStructuredCloneWriter)
                     -> Result<(), ()> {
    let structured_writer = StructuredCloneWriter { w: w };
    let blob_vec = blob.get_bytes()?;
    assert!(JS_WriteUint32Pair(w, StructuredCloneTags::DomBlob as u32, 0));
    structured_writer.write_slice(&blob_vec);
    structured_writer.write_str(&blob.type_string());
    return Ok(())
}

unsafe extern "C" fn read_callback(cx: *mut JSContext,
                                   r: *mut JSStructuredCloneReader,
                                   tag: u32,
                                   _data: u32,
                                   closure: *mut raw::c_void)
                                   -> *mut JSObject {
    assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
    assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
    if tag == StructuredCloneTags::DomBlob as u32 {
        return read_blob(cx, r, &mut *(closure as *mut StructuredCloneHolder))
    }
    return ptr::null_mut()
}

unsafe extern "C" fn write_callback(_cx: *mut JSContext,
                                    w: *mut JSStructuredCloneWriter,
                                    obj: RawHandleObject,
                                    _closure: *mut raw::c_void)
                                    -> bool {
    if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
        return write_blob(blob, w).is_ok()
    }
    return false
}

unsafe extern "C" fn read_transfer_callback(_cx: *mut JSContext,
                                            _r: *mut JSStructuredCloneReader,
                                            _tag: u32,
                                            _content: *mut raw::c_void,
                                            _extra_data: u64,
                                            _closure: *mut raw::c_void,
                                            _return_object: RawMutableHandleObject)
                                            -> bool {
    false
}

unsafe extern "C" fn write_transfer_callback(_cx: *mut JSContext,
                                             _obj: RawHandleObject,
                                             _closure: *mut raw::c_void,
                                             _tag: *mut u32,
                                             _ownership: *mut TransferableOwnership,
                                             _content:  *mut *mut raw::c_void,
                                             _extra_data: *mut u64)
                                             -> bool {
    false
}

unsafe extern "C" fn free_transfer_callback(_tag: u32,
                                            _ownership: TransferableOwnership,
                                            _content: *mut raw::c_void,
                                            _extra_data: u64,
                                            _closure: *mut raw::c_void) {
}

unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {
}

static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
    read: Some(read_callback),
    write: Some(write_callback),
    reportError: Some(report_error_callback),
    readTransfer: Some(read_transfer_callback),
    writeTransfer: Some(write_transfer_callback),
    freeTransfer: Some(free_transfer_callback),
};

struct StructuredCloneHolder {
    blob: Option<DomRoot<Blob>>
}

/// A buffer for a structured clone.
pub enum StructuredCloneData {
    /// A non-serializable (default) variant
    Struct(*mut u64, size_t),
    /// A variant that can be serialized
    Vector(Vec<u8>)
}

impl StructuredCloneData {
    /// Writes a structured clone. Returns a `DataClone` error if that fails.
    pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
        let mut data = ptr::null_mut();
        let mut nbytes = 0;
        let result = unsafe {
            JS_WriteStructuredClone(cx,
                                    message,
                                    &mut data,
                                    &mut nbytes,
                                    &STRUCTURED_CLONE_CALLBACKS,
                                    ptr::null_mut(),
                                    HandleValue::undefined())
        };
        if !result {
            unsafe {
                JS_ClearPendingException(cx);
            }
            return Err(Error::DataClone);
        }
        Ok(StructuredCloneData::Struct(data, nbytes))
    }

    /// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
    pub fn move_to_arraybuffer(self) -> Vec<u8> {
        match self {
            StructuredCloneData::Struct(data, nbytes) => {
                unsafe {
                    slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
                }
            }
            StructuredCloneData::Vector(msg) => msg
        }
    }

    /// Reads a structured clone.
    ///
    /// Panics if `JS_ReadStructuredClone` fails.
    fn read_clone(global: &GlobalScope,
                  data: *mut u64,
                  nbytes: size_t,
                  rval: MutableHandleValue) {
        let cx = global.get_cx();
        let globalhandle = global.reflector().get_jsobject();
        let _ac = JSAutoCompartment::new(cx, globalhandle.get());
        let mut sc_holder = StructuredCloneHolder { blob: None };
        let sc_holder_ptr = &mut sc_holder as *mut _;
        unsafe {
            assert!(JS_ReadStructuredClone(cx,
                                           data,
                                           nbytes,
                                           JS_STRUCTURED_CLONE_VERSION,
                                           rval,
                                           &STRUCTURED_CLONE_CALLBACKS,
                                           sc_holder_ptr as *mut raw::c_void));
        }
    }

    /// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
    pub fn read(self, global: &GlobalScope, rval: MutableHandleValue) {
        match self {
            StructuredCloneData::Vector(mut vec_msg) => {
                let nbytes = vec_msg.len();
                let data = vec_msg.as_mut_ptr() as *mut u64;
                StructuredCloneData::read_clone(global, data, nbytes, rval);
            }
            StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
        }
    }
}

unsafe impl Send for StructuredCloneData {}
<|endoftext|>


<commit_before>use crate::utils::sugg::Sugg;
use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq};
use if_chain::if_chain;
use rustc::hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::ast::{LitKind, NodeId};
use syntax_pos::symbol::Symbol;

/// **What it does:** Checks slow zero-filled vector initialization
///
/// **Why is this bad?** This structures are non-idiomatic and less efficient than simply using
/// `vec![len; 0]`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let mut vec1 = Vec::with_capacity(len);
/// vec1.resize(len, 0);
///
/// let mut vec2 = Vec::with_capacity(len);
/// vec2.extend(repeat(0).take(len))
/// ```
declare_clippy_lint! {
    pub SLOW_VECTOR_INITIALIZATION,
    perf,
    "slow vector initialization"
}

#[derive(Copy, Clone, Default)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SLOW_VECTOR_INITIALIZATION,)
    }
}

/// `VecAllocation` contains data regarding a vector allocated with `with_capacity` and then
/// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or
/// `vec = Vec::with_capacity(0)`
struct VecAllocation<'tcx> {
    /// Symbol of the local variable name
    variable_name: Symbol,

    /// Reference to the expression which allocates the vector
    allocation_expr: &'tcx Expr,

    /// Reference to the expression used as argument on `with_capacity` call. This is used
    /// to only match slow zero-filling idioms of the same length than vector initialization.
    len_expr: &'tcx Expr,
}

/// Type of slow initialization
enum InitializationType<'tcx> {
    /// Extend is a slow initialization with the form `vec.extend(repeat(0).take(..))`
    Extend(&'tcx Expr),

    /// Resize is a slow initialization with the form `vec.resize(.., 0)`
    Resize(&'tcx Expr),
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
        if_chain! {
            if let ExprKind::Assign(ref left, ref right) = expr.node;

            // Extract variable name
            if let ExprKind::Path(QPath::Resolved(_, ref path)) = left.node;
            if let Some(variable_name) = path.segments.get(0);

            // Extract len argument
            if let Some(ref len_arg) = Self::is_vec_with_capacity(right);

            then {
                let vi = VecAllocation {
                    variable_name: variable_name.ident.name,
                    allocation_expr: right,
                    len_expr: len_arg,
                };

                Self::search_initialization(cx, vi, expr.id);
            }
        }
    }

    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
        // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
        if_chain! {
            if let StmtKind::Local(ref local) = stmt.node;
            if let PatKind::Binding(BindingAnnotation::Mutable, _, variable_name, None) = local.pat.node;
            if let Some(ref init) = local.init;
            if let Some(ref len_arg) = Self::is_vec_with_capacity(init);

            then {
                let vi = VecAllocation {
                    variable_name: variable_name.name,
                    allocation_expr: init,
                    len_expr: len_arg,
                };

                Self::search_initialization(cx, vi, stmt.id);
            }
        }
    }
}

impl Pass {
    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
    fn is_vec_with_capacity(expr: &Expr) -> Option<&Expr> {
        if_chain! {
            if let ExprKind::Call(ref func, ref args) = expr.node;
            if let ExprKind::Path(ref path) = func.node;
            if match_qpath(path, &["Vec", "with_capacity"]);
            if args.len() == 1;

            then {
                return Some(&args[0]);
            }
        }

        None
    }

    /// Search initialization for the given vector
    fn search_initialization<'tcx>(cx: &LateContext<'_, 'tcx>, vec_alloc: VecAllocation<'tcx>, parent_node: NodeId) {
        let enclosing_body = get_enclosing_block(cx, parent_node);

        if enclosing_body.is_none() {
            return;
        }

        let mut v = VectorInitializationVisitor {
            cx,
            vec_alloc,
            slow_expression: None,
            initialization_found: false,
        };

        v.visit_block(enclosing_body.unwrap());

        if let Some(ref allocation_expr) = v.slow_expression {
            Self::lint_initialization(cx, allocation_expr, &v.vec_alloc);
        }
    }

    fn lint_initialization<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        initialization: &InitializationType<'tcx>,
        vec_alloc: &VecAllocation<'_>,
    ) {
        match initialization {
            InitializationType::Extend(e) | InitializationType::Resize(e) => Self::emit_lint(
                cx,
                e,
                vec_alloc,
                "slow zero-filling initialization",
                SLOW_VECTOR_INITIALIZATION,
            ),
        };
    }

    fn emit_lint<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        slow_fill: &Expr,
        vec_alloc: &VecAllocation<'_>,
        msg: &str,
        lint: &'static Lint,
    ) {
        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");

        span_lint_and_then(cx, lint, slow_fill.span, msg, |db| {
            db.span_suggestion_with_applicability(
                vec_alloc.allocation_expr.span,
                "consider replace allocation with",
                format!("vec![0; {}]", len_expr),
                Applicability::Unspecified,
            );
        });
    }
}

/// `VectorInitializationVisitor` searches for unsafe or slow vector initializations for the given
/// vector.
struct VectorInitializationVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,

    /// Contains the information
    vec_alloc: VecAllocation<'tcx>,

    /// Contains, if found, the slow initialization expression
    slow_expression: Option<InitializationType<'tcx>>,

    /// true if the initialization of the vector has been found on the visited block
    initialization_found: bool,
}

impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
    /// Checks if the given expression is extending a vector with `repeat(0).take(..)`
    fn search_slow_extend_filling(&mut self, expr: &'tcx Expr) {
        if_chain! {
            if self.initialization_found;
            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
            if let ExprKind::Path(ref qpath_subj) = args[0].node;
            if match_qpath(&qpath_subj, &[&self.vec_alloc.variable_name.to_string()]);
            if path.ident.name == "extend";
            if let Some(ref extend_arg) = args.get(1);
            if self.is_repeat_take(extend_arg);

            then {
                self.slow_expression = Some(InitializationType::Extend(expr));
            }
        }
    }

    /// Checks if the given expression is resizing a vector with 0
    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr) {
        if_chain! {
            if self.initialization_found;
            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
            if let ExprKind::Path(ref qpath_subj) = args[0].node;
            if match_qpath(&qpath_subj, &[&self.vec_alloc.variable_name.to_string()]);
            if path.ident.name == "resize";
            if let (Some(ref len_arg), Some(fill_arg)) = (args.get(1), args.get(2));

            // Check that is filled with 0
            if let ExprKind::Lit(ref lit) = fill_arg.node;
            if let LitKind::Int(0, _) = lit.node;

            // Check that len expression is equals to `with_capacity` expression
            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);

            then {
                self.slow_expression = Some(InitializationType::Resize(expr));
            }
        }
    }

    /// Returns `true` if give expression is `repeat(0).take(...)`
    fn is_repeat_take(&self, expr: &Expr) -> bool {
        if_chain! {
            if let ExprKind::MethodCall(ref take_path, _, ref take_args) = expr.node;
            if take_path.ident.name == "take";

            // Check that take is applied to `repeat(0)`
            if let Some(ref repeat_expr) = take_args.get(0);
            if self.is_repeat_zero(repeat_expr);

            // Check that len expression is equals to `with_capacity` expression
            if let Some(ref len_arg) = take_args.get(1);
            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);

            then {
                return true;
            }
        }

        false
    }

    /// Returns `true` if given expression is `repeat(0)`
    fn is_repeat_zero(&self, expr: &Expr) -> bool {
        if_chain! {
            if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.node;
            if let ExprKind::Path(ref qpath_repeat) = fn_expr.node;
            if match_qpath(&qpath_repeat, &["repeat"]);
            if let Some(ref repeat_arg) = repeat_args.get(0);
            if let ExprKind::Lit(ref lit) = repeat_arg.node;
            if let LitKind::Int(0, _) = lit.node;

            then {
                return true
            }
        }

        false
    }
}

impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
    fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
        if self.initialization_found {
            match stmt.node {
                StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
                    self.search_slow_extend_filling(expr);
                    self.search_slow_resize_filling(expr);
                },
                _ => (),
            }

            self.initialization_found = false;
        } else {
            walk_stmt(self, stmt);
        }
    }

    fn visit_block(&mut self, block: &'tcx Block) {
        if self.initialization_found {
            if let Some(ref s) = block.stmts.get(0) {
                self.visit_stmt(s)
            }

            self.initialization_found = false;
        } else {
            walk_block(self, block);
        }
    }

    fn visit_expr(&mut self, expr: &'tcx Expr) {
        // Skip all the expressions previous to the vector initialization
        if self.vec_alloc.allocation_expr.id == expr.id {
            self.initialization_found = true;
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}
<commit_msg>Fix documentation for `slow_vector_initialization`<commit_after>use crate::utils::sugg::Sugg;
use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq};
use if_chain::if_chain;
use rustc::hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::ast::{LitKind, NodeId};
use syntax_pos::symbol::Symbol;

/// **What it does:** Checks slow zero-filled vector initialization
///
/// **Why is this bad?** These structures are non-idiomatic and less efficient than simply using
/// `vec![0; len]`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let mut vec1 = Vec::with_capacity(len);
/// vec1.resize(len, 0);
///
/// let mut vec2 = Vec::with_capacity(len);
/// vec2.extend(repeat(0).take(len))
/// ```
declare_clippy_lint! {
    pub SLOW_VECTOR_INITIALIZATION,
    perf,
    "slow vector initialization"
}

#[derive(Copy, Clone, Default)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SLOW_VECTOR_INITIALIZATION,)
    }
}

/// `VecAllocation` contains data regarding a vector allocated with `with_capacity` and then
/// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or
/// `vec = Vec::with_capacity(0)`
struct VecAllocation<'tcx> {
    /// Symbol of the local variable name
    variable_name: Symbol,

    /// Reference to the expression which allocates the vector
    allocation_expr: &'tcx Expr,

    /// Reference to the expression used as argument on `with_capacity` call. This is used
    /// to only match slow zero-filling idioms of the same length than vector initialization.
    len_expr: &'tcx Expr,
}

/// Type of slow initialization
enum InitializationType<'tcx> {
    /// Extend is a slow initialization with the form `vec.extend(repeat(0).take(..))`
    Extend(&'tcx Expr),

    /// Resize is a slow initialization with the form `vec.resize(.., 0)`
    Resize(&'tcx Expr),
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
        if_chain! {
            if let ExprKind::Assign(ref left, ref right) = expr.node;

            // Extract variable name
            if let ExprKind::Path(QPath::Resolved(_, ref path)) = left.node;
            if let Some(variable_name) = path.segments.get(0);

            // Extract len argument
            if let Some(ref len_arg) = Self::is_vec_with_capacity(right);

            then {
                let vi = VecAllocation {
                    variable_name: variable_name.ident.name,
                    allocation_expr: right,
                    len_expr: len_arg,
                };

                Self::search_initialization(cx, vi, expr.id);
            }
        }
    }

    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
        // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
        if_chain! {
            if let StmtKind::Local(ref local) = stmt.node;
            if let PatKind::Binding(BindingAnnotation::Mutable, _, variable_name, None) = local.pat.node;
            if let Some(ref init) = local.init;
            if let Some(ref len_arg) = Self::is_vec_with_capacity(init);

            then {
                let vi = VecAllocation {
                    variable_name: variable_name.name,
                    allocation_expr: init,
                    len_expr: len_arg,
                };

                Self::search_initialization(cx, vi, stmt.id);
            }
        }
    }
}

impl Pass {
    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
    fn is_vec_with_capacity(expr: &Expr) -> Option<&Expr> {
        if_chain! {
            if let ExprKind::Call(ref func, ref args) = expr.node;
            if let ExprKind::Path(ref path) = func.node;
            if match_qpath(path, &["Vec", "with_capacity"]);
            if args.len() == 1;

            then {
                return Some(&args[0]);
            }
        }

        None
    }

    /// Search initialization for the given vector
    fn search_initialization<'tcx>(cx: &LateContext<'_, 'tcx>, vec_alloc: VecAllocation<'tcx>, parent_node: NodeId) {
        let enclosing_body = get_enclosing_block(cx, parent_node);

        if enclosing_body.is_none() {
            return;
        }

        let mut v = VectorInitializationVisitor {
            cx,
            vec_alloc,
            slow_expression: None,
            initialization_found: false,
        };

        v.visit_block(enclosing_body.unwrap());

        if let Some(ref allocation_expr) = v.slow_expression {
            Self::lint_initialization(cx, allocation_expr, &v.vec_alloc);
        }
    }

    fn lint_initialization<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        initialization: &InitializationType<'tcx>,
        vec_alloc: &VecAllocation<'_>,
    ) {
        match initialization {
            InitializationType::Extend(e) | InitializationType::Resize(e) => Self::emit_lint(
                cx,
                e,
                vec_alloc,
                "slow zero-filling initialization",
                SLOW_VECTOR_INITIALIZATION,
            ),
        };
    }

    fn emit_lint<'tcx>(
        cx: &LateContext<'_, 'tcx>,
        slow_fill: &Expr,
        vec_alloc: &VecAllocation<'_>,
        msg: &str,
        lint: &'static Lint,
    ) {
        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");

        span_lint_and_then(cx, lint, slow_fill.span, msg, |db| {
            db.span_suggestion_with_applicability(
                vec_alloc.allocation_expr.span,
                "consider replace allocation with",
                format!("vec![0; {}]", len_expr),
                Applicability::Unspecified,
            );
        });
    }
}

/// `VectorInitializationVisitor` searches for unsafe or slow vector initializations for the given
/// vector.
struct VectorInitializationVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,

    /// Contains the information
    vec_alloc: VecAllocation<'tcx>,

    /// Contains, if found, the slow initialization expression
    slow_expression: Option<InitializationType<'tcx>>,

    /// true if the initialization of the vector has been found on the visited block
    initialization_found: bool,
}

impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
    /// Checks if the given expression is extending a vector with `repeat(0).take(..)`
    fn search_slow_extend_filling(&mut self, expr: &'tcx Expr) {
        if_chain! {
            if self.initialization_found;
            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
            if let ExprKind::Path(ref qpath_subj) = args[0].node;
            if match_qpath(&qpath_subj, &[&self.vec_alloc.variable_name.to_string()]);
            if path.ident.name == "extend";
            if let Some(ref extend_arg) = args.get(1);
            if self.is_repeat_take(extend_arg);

            then {
                self.slow_expression = Some(InitializationType::Extend(expr));
            }
        }
    }

    /// Checks if the given expression is resizing a vector with 0
    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr) {
        if_chain! {
            if self.initialization_found;
            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
            if let ExprKind::Path(ref qpath_subj) = args[0].node;
            if match_qpath(&qpath_subj, &[&self.vec_alloc.variable_name.to_string()]);
            if path.ident.name == "resize";
            if let (Some(ref len_arg), Some(fill_arg)) = (args.get(1), args.get(2));

            // Check that is filled with 0
            if let ExprKind::Lit(ref lit) = fill_arg.node;
            if let LitKind::Int(0, _) = lit.node;

            // Check that len expression is equals to `with_capacity` expression
            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);

            then {
                self.slow_expression = Some(InitializationType::Resize(expr));
            }
        }
    }

    /// Returns `true` if give expression is `repeat(0).take(...)`
    fn is_repeat_take(&self, expr: &Expr) -> bool {
        if_chain! {
            if let ExprKind::MethodCall(ref take_path, _, ref take_args) = expr.node;
            if take_path.ident.name == "take";

            // Check that take is applied to `repeat(0)`
            if let Some(ref repeat_expr) = take_args.get(0);
            if self.is_repeat_zero(repeat_expr);

            // Check that len expression is equals to `with_capacity` expression
            if let Some(ref len_arg) = take_args.get(1);
            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);

            then {
                return true;
            }
        }

        false
    }

    /// Returns `true` if given expression is `repeat(0)`
    fn is_repeat_zero(&self, expr: &Expr) -> bool {
        if_chain! {
            if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.node;
            if let ExprKind::Path(ref qpath_repeat) = fn_expr.node;
            if match_qpath(&qpath_repeat, &["repeat"]);
            if let Some(ref repeat_arg) = repeat_args.get(0);
            if let ExprKind::Lit(ref lit) = repeat_arg.node;
            if let LitKind::Int(0, _) = lit.node;

            then {
                return true
            }
        }

        false
    }
}

impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
    fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
        if self.initialization_found {
            match stmt.node {
                StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
                    self.search_slow_extend_filling(expr);
                    self.search_slow_resize_filling(expr);
                },
                _ => (),
            }

            self.initialization_found = false;
        } else {
            walk_stmt(self, stmt);
        }
    }

    fn visit_block(&mut self, block: &'tcx Block) {
        if self.initialization_found {
            if let Some(ref s) = block.stmts.get(0) {
                self.visit_stmt(s)
            }

            self.initialization_found = false;
        } else {
            walk_block(self, block);
        }
    }

    fn visit_expr(&mut self, expr: &'tcx Expr) {
        // Skip all the expressions previous to the vector initialization
        if self.vec_alloc.allocation_expr.id == expr.id {
            self.initialization_found = true;
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    fs,
    path::PathBuf,
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
};

pub fn project(fixture: &str) -> Server {
    static INIT: Once = Once::new();
    INIT.call_once(|| Logger::with_env_or_str(crate::LOG).start().unwrap());

    let tmp_dir = TempDir::new().unwrap();
    let mut paths = vec![];

    for entry in parse_fixture(fixture) {
        let path = tmp_dir.path().join(entry.meta);
        fs::create_dir_all(path.parent().unwrap()).unwrap();
        fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
        paths.push((path, entry.text));
    }
    Server::new(tmp_dir, paths)
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Option<Worker<RawMessage, RawMessage>>,
}

impl Server {
    fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();
        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(true, path, true, &mut msg_receiver, &mut msg_sender).unwrap()
            },
        );
        let res = Server {
            req_id: Cell::new(1),
            dir,
            messages: Default::default(),
            worker: Some(worker),
        };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        match find_mismatch(&expected_resp, &actual) {
            Some((expected_part, actual_part)) => panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            ),
            None => {}
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.as_ref().unwrap().sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_for_feedback(&self, feedback: &str) {
        self.wait_for_feedback_n(feedback, 1)
    }
    pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) {
        let f = |msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == "internalFeedback" => {
                return n.clone().cast::<req::InternalFeedback>().unwrap() == feedback;
            }
            _ => false,
        };
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if f(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if f(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.as_ref().unwrap().receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap();
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(50);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<commit_msg>Fix the build<commit_after>use std::{
    cell::{Cell, RefCell},
    fs,
    path::PathBuf,
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
};

pub fn project(fixture: &str) -> Server {
    static INIT: Once = Once::new();
    INIT.call_once(|| {
        let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
    });

    let tmp_dir = TempDir::new().unwrap();
    let mut paths = vec![];

    for entry in parse_fixture(fixture) {
        let path = tmp_dir.path().join(entry.meta);
        fs::create_dir_all(path.parent().unwrap()).unwrap();
        fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
        paths.push((path, entry.text));
    }
    Server::new(tmp_dir, paths)
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Option<Worker<RawMessage, RawMessage>>,
}

impl Server {
    fn new(dir: TempDir, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();
        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(true, path, true, &mut msg_receiver, &mut msg_sender).unwrap()
            },
        );
        let res = Server {
            req_id: Cell::new(1),
            dir,
            messages: Default::default(),
            worker: Some(worker),
        };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        match find_mismatch(&expected_resp, &actual) {
            Some((expected_part, actual_part)) => panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            ),
            None => {}
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.as_ref().unwrap().sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_for_feedback(&self, feedback: &str) {
        self.wait_for_feedback_n(feedback, 1)
    }
    pub fn wait_for_feedback_n(&self, feedback: &str, n: usize) {
        let f = |msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == "internalFeedback" => {
                return n.clone().cast::<req::InternalFeedback>().unwrap() == feedback;
            }
            _ => false,
        };
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if f(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if f(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.as_ref().unwrap().receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.as_ref().unwrap().sender().send(RawMessage::Notification(not)).unwrap();
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(50);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<|endoftext|>