<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

/// This wraps around `futures::stream::futures_unorderd::FuturesUnordered` to provide similar
/// functionality except that there's limit on concurrency. This allows us to manage more futures
/// without activation too many of them at the same time.
use futures::{
    stream::{FusedStream, FuturesUnordered},
    task::{Context, Poll},
    Future, Stream, StreamExt,
};
use std::{collections::VecDeque, fmt::Debug, pin::Pin};

#[must_use = "streams do nothing unless polled"]
pub struct FuturesUnorderedX<T: Future> {
    queued: VecDeque<T>,
    in_progress: FuturesUnordered<T>,
    queued_outputs: VecDeque<T::Output>,
    max_in_progress: usize,
}

impl<T: Future> Unpin for FuturesUnorderedX<T> {}

impl<Fut: Future> FuturesUnorderedX<Fut> {
    /// Constructs a new, empty `FuturesOrderedX`
    ///
    /// The returned `FuturesOrderedX` does not contain any futures and, in this
    /// state, `FuturesOrdered::poll_next` will return `Poll::Ready(None)`.
    pub fn new(max_in_progress: usize) -> FuturesUnorderedX<Fut> {
        assert!(max_in_progress > 0);
        FuturesUnorderedX {
            queued: VecDeque::new(),
            in_progress: FuturesUnordered::new(),
            queued_outputs: VecDeque::new(),
            max_in_progress,
        }
    }

    /// Returns the number of futures contained in the queue.
    ///
    /// This represents the total number of in-flight futures, including those whose outputs queued
    /// for polling, those currently being processing and those in queued due to concurrency limit.
    pub fn len(&self) -> usize {
        self.queued.len() + self.in_progress.len() + self.queued_outputs.len()
    }

    /// Returns `true` if the queue contains no futures
    pub fn is_empty(&self) -> bool {
        self.queued.is_empty() && self.in_progress.is_empty() && self.queued_outputs.is_empty()
    }

    /// Push a future into the queue.
    ///
    /// This function submits the given future to the internal set for managing.
    /// This function will not call `poll` on the submitted future. The caller
    /// must ensure that `FuturesOrdered::poll` is called in order to receive
    /// task notifications.
    pub fn push(&mut self, future: Fut) {
        if self.in_progress.len() < self.max_in_progress {
            self.in_progress.push(future);
        } else {
            self.queued.push_back(future);
        }
    }
}

impl<Fut: Future> Stream for FuturesUnorderedX<Fut> {
    type Item = Fut::Output;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        // Collect outputs from newly finished futures from the underlying `FuturesUnordered`.
        while let Poll::Ready(Some(output)) = self.in_progress.poll_next_unpin(cx) {
            self.queued_outputs.push_back(output);
            // Concurrency is now below `self.max_in_progress`, kick off a queued one, if any.
            if let Some(future) = self.queued.pop_front() {
                self.in_progress.push(future)
            }
        }

        if let Some(output) = self.queued_outputs.pop_front() {
            Poll::Ready(Some(output))
        } else if self.in_progress.is_empty() {
            Poll::Ready(None)
        } else {
            Poll::Pending
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<Fut: Future> Debug for FuturesUnorderedX<Fut> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "FuturesOrderedX {{ ... }}")
    }
}

impl<Fut: Future> FusedStream for FuturesUnorderedX<Fut> {
    fn is_terminated(&self) -> bool {
        self.in_progress.is_terminated() && self.queued_outputs.is_empty()
    }
}

impl<Fut: Future> Extend<Fut> for FuturesUnorderedX<Fut> {
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = Fut>,
    {
        for item in iter.into_iter() {
            self.push(item);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::FuturesUnorderedX;
    use futures::StreamExt;
    use proptest::{collection::vec, prelude::*};
    use std::{
        cmp::min,
        sync::{
            atomic::{AtomicBool, AtomicUsize, Ordering},
            Arc,
        },
    };
    use tokio::{runtime::Runtime, time::Duration};

    proptest! {
        #[test]
        fn test_run(
            sleeps_ms in vec(0u64..10, 0..100),
            max_in_progress in 1usize..100,
        ) {
            let rt = Runtime::new().unwrap();
            rt.block_on(async {
                let num_sleeps = sleeps_ms.len();
                let mut futures = FuturesUnorderedX::new(max_in_progress);
                assert!(futures.is_empty());

                let n_running = Arc::new(AtomicUsize::new(0));
                let seen_max_concurrency = Arc::new(AtomicBool::new(false));
                for (n, sleep_ms) in sleeps_ms.into_iter().enumerate() {
                    let _n_running = n_running.clone();
                    let _seen_max_concurrency = seen_max_concurrency.clone();

                    futures.push(async move {
                        _n_running.fetch_add(1, Ordering::Relaxed);

                        // yield
                        tokio::time::sleep(Duration::from_millis(sleep_ms)).await;

                        let r = _n_running.fetch_sub(1, Ordering::Relaxed);
                        assert!(r > 0 && r <= min(max_in_progress, num_sleeps));
                        if r == max_in_progress {
                            _seen_max_concurrency.store(true, Ordering::Relaxed);
                        }

                        n
                    })
                }

                assert!(num_sleeps > 0 || futures.is_empty());
                let mut outputs = futures.collect::<Vec<_>>().await;
                if max_in_progress <= num_sleeps {
                    assert!(seen_max_concurrency.load(Ordering::Relaxed));
                }

                outputs.sort_unstable();
                assert_eq!(outputs, (0..num_sleeps).collect::<Vec<_>>());
            });
        }
    }
}
<commit_msg>[storage] try to fix flaky futures_unordered_x test<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

/// This wraps around `futures::stream::futures_unorderd::FuturesUnordered` to provide similar
/// functionality except that there's limit on concurrency. This allows us to manage more futures
/// without activation too many of them at the same time.
use futures::{
    stream::{FusedStream, FuturesUnordered},
    task::{Context, Poll},
    Future, Stream, StreamExt,
};
use std::{collections::VecDeque, fmt::Debug, pin::Pin};

#[must_use = "streams do nothing unless polled"]
pub struct FuturesUnorderedX<T: Future> {
    queued: VecDeque<T>,
    in_progress: FuturesUnordered<T>,
    queued_outputs: VecDeque<T::Output>,
    max_in_progress: usize,
}

impl<T: Future> Unpin for FuturesUnorderedX<T> {}

impl<Fut: Future> FuturesUnorderedX<Fut> {
    /// Constructs a new, empty `FuturesOrderedX`
    ///
    /// The returned `FuturesOrderedX` does not contain any futures and, in this
    /// state, `FuturesOrdered::poll_next` will return `Poll::Ready(None)`.
    pub fn new(max_in_progress: usize) -> FuturesUnorderedX<Fut> {
        assert!(max_in_progress > 0);
        FuturesUnorderedX {
            queued: VecDeque::new(),
            in_progress: FuturesUnordered::new(),
            queued_outputs: VecDeque::new(),
            max_in_progress,
        }
    }

    /// Returns the number of futures contained in the queue.
    ///
    /// This represents the total number of in-flight futures, including those whose outputs queued
    /// for polling, those currently being processing and those in queued due to concurrency limit.
    pub fn len(&self) -> usize {
        self.queued.len() + self.in_progress.len() + self.queued_outputs.len()
    }

    /// Returns `true` if the queue contains no futures
    pub fn is_empty(&self) -> bool {
        self.queued.is_empty() && self.in_progress.is_empty() && self.queued_outputs.is_empty()
    }

    /// Push a future into the queue.
    ///
    /// This function submits the given future to the internal set for managing.
    /// This function will not call `poll` on the submitted future. The caller
    /// must ensure that `FuturesOrdered::poll` is called in order to receive
    /// task notifications.
    pub fn push(&mut self, future: Fut) {
        if self.in_progress.len() < self.max_in_progress {
            self.in_progress.push(future);
        } else {
            self.queued.push_back(future);
        }
    }
}

impl<Fut: Future> Stream for FuturesUnorderedX<Fut> {
    type Item = Fut::Output;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        // Collect outputs from newly finished futures from the underlying `FuturesUnordered`.
        while let Poll::Ready(Some(output)) = self.in_progress.poll_next_unpin(cx) {
            self.queued_outputs.push_back(output);
            // Concurrency is now below `self.max_in_progress`, kick off a queued one, if any.
            if let Some(future) = self.queued.pop_front() {
                self.in_progress.push(future)
            }
        }

        if let Some(output) = self.queued_outputs.pop_front() {
            Poll::Ready(Some(output))
        } else if self.in_progress.is_empty() {
            Poll::Ready(None)
        } else {
            Poll::Pending
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<Fut: Future> Debug for FuturesUnorderedX<Fut> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "FuturesOrderedX {{ ... }}")
    }
}

impl<Fut: Future> FusedStream for FuturesUnorderedX<Fut> {
    fn is_terminated(&self) -> bool {
        self.in_progress.is_terminated() && self.queued_outputs.is_empty()
    }
}

impl<Fut: Future> Extend<Fut> for FuturesUnorderedX<Fut> {
    fn extend<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = Fut>,
    {
        for item in iter.into_iter() {
            self.push(item);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::FuturesUnorderedX;
    use futures::StreamExt;
    use proptest::{collection::vec, prelude::*};
    use std::{
        cmp::min,
        sync::{
            atomic::{AtomicBool, AtomicUsize, Ordering},
            Arc,
        },
    };
    use tokio::{runtime::Runtime, time::Duration};

    proptest! {
        #[test]
        fn test_run(
            sleeps_ms in vec(0u64..10, 10..100),
            max_in_progress in 1usize..100,
        ) {
            let rt = Runtime::new().unwrap();
            rt.block_on(async {
                let num_sleeps = sleeps_ms.len();
                let mut futures = FuturesUnorderedX::new(max_in_progress);
                assert!(futures.is_empty());

                let n_running = Arc::new(AtomicUsize::new(0));
                let seen_max_concurrency = Arc::new(AtomicBool::new(false));
                for (n, sleep_ms) in sleeps_ms.into_iter().enumerate() {
                    let _n_running = n_running.clone();
                    let _seen_max_concurrency = seen_max_concurrency.clone();

                    futures.push(async move {
                        _n_running.fetch_add(1, Ordering::Relaxed);

                        // yield
                        tokio::time::sleep(Duration::from_millis(sleep_ms)).await;

                        let r = _n_running.fetch_sub(1, Ordering::Relaxed);
                        assert!(r > 0 && r <= min(max_in_progress, num_sleeps));
                        if r == max_in_progress {
                            _seen_max_concurrency.store(true, Ordering::Relaxed);
                        }

                        n
                    })
                }

                assert!(num_sleeps > 0 || futures.is_empty());
                let mut outputs = futures.collect::<Vec<_>>().await;
                if max_in_progress <= num_sleeps {
                    assert!(seen_max_concurrency.load(Ordering::Relaxed));
                }

                outputs.sort_unstable();
                assert_eq!(outputs, (0..num_sleeps).collect::<Vec<_>>());
            });
        }
    }
}
<|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/. */

/*!
A GPU based renderer for the web.

It serves as an experimental render backend for [Servo](https://servo.org/),
but it can also be used as such in a standalone application.

# External dependencies
WebRender currently depends on [FreeType](https://www.freetype.org/)

# Api Structure
The main entry point to WebRender is the [`crate::Renderer`].

By calling [`Renderer::new(...)`](crate::Renderer::new) you get a [`Renderer`], as well as
a [`RenderApiSender`](api::RenderApiSender). Your [`Renderer`] is responsible to render the
previously processed frames onto the screen.

By calling [`yourRenderApiSender.create_api()`](api::RenderApiSender::create_api), you'll
get a [`RenderApi`](api::RenderApi) instance, which is responsible for managing resources
and documents. A worker thread is used internally to untie the workload from the application
thread and therefore be able to make better use of multicore systems.

## Frame

What is referred to as a `frame`, is the current geometry on the screen.
A new Frame is created by calling [`set_display_list()`](api::Transaction::set_display_list)
on the [`RenderApi`](api::RenderApi). When the geometry is processed, the application will be
informed via a [`RenderNotifier`](api::RenderNotifier), a callback which you pass to
[`Renderer::new`].
More information about [stacking contexts][stacking_contexts].

[`set_display_list()`](api::Transaction::set_display_list) also needs to be supplied with
[`BuiltDisplayList`](api::BuiltDisplayList)s. These are obtained by finalizing a
[`DisplayListBuilder`](api::DisplayListBuilder). These are used to draw your geometry. But it
doesn't only contain trivial geometry, it can also store another
[`StackingContext`](api::StackingContext), as they're nestable.

[stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
*/

// Cribbed from the |matches| crate, for simplicity.
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate cstr;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate malloc_size_of_derive;
#[cfg(any(feature = "serde"))]
#[macro_use]
extern crate serde;
#[macro_use]
extern crate thread_profiler;

extern crate wr_malloc_size_of;
use wr_malloc_size_of as malloc_size_of;

#[macro_use]
mod profiler;

mod batch;
mod border;
mod box_shadow;
#[cfg(any(feature = "capture", feature = "replay"))]
mod capture;
mod clip;
mod clip_scroll_tree;
mod debug_colors;
mod debug_font_data;
mod debug_render;
#[cfg(feature = "debugger")]
mod debug_server;
mod device;
mod display_list_flattener;
mod ellipse;
mod filterdata;
mod frame_builder;
mod freelist;
#[cfg(any(target_os = "macos", target_os = "windows"))]
mod gamma_lut;
mod glyph_cache;
mod glyph_rasterizer;
mod gpu_cache;
#[cfg(feature = "pathfinder")]
mod gpu_glyph_renderer;
mod gpu_types;
mod hit_test;
mod image;
mod intern;
mod internal_types;
mod picture;
mod prim_store;
mod print_tree;
mod record;
mod render_backend;
mod render_task;
mod renderer;
mod resource_cache;
mod scene;
mod scene_builder;
mod segment;
mod shade;
mod spatial_node;
mod storage;
mod texture_allocator;
mod texture_cache;
mod tiling;
mod util;

mod shader_source {
    include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
}

pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER};

mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::font;
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub use platform::unix::font;
    #[cfg(target_os = "windows")]
    pub use platform::windows::font;

    #[cfg(target_os = "macos")]
    pub mod macos {
        pub mod font;
    }
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub mod unix {
        pub mod font;
    }
    #[cfg(target_os = "windows")]
    pub mod windows {
        pub mod font;
    }
}

#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate core_text;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate freetype;
#[cfg(all(unix, not(target_os = "macos")))]
extern crate libc;

#[cfg(target_os = "windows")]
extern crate dwrote;

extern crate bincode;
extern crate byteorder;
extern crate fxhash;
extern crate gleam;
extern crate num_traits;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_font_renderer;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_gfx_utils;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_partitioner;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_path_utils;
extern crate plane_split;
extern crate rayon;
#[cfg(feature = "ron")]
extern crate ron;
#[cfg(feature = "debugger")]
extern crate serde_json;
extern crate sha2;
extern crate smallvec;
extern crate time;
#[cfg(feature = "debugger")]
extern crate ws;
#[cfg(feature = "debugger")]
extern crate image as image_loader;
#[cfg(feature = "debugger")]
extern crate base64;
#[cfg(all(feature = "capture", feature = "png"))]
extern crate png;
#[cfg(test)]
extern crate rand;

#[macro_use]
pub extern crate webrender_api;
extern crate webrender_build;

#[doc(hidden)]
pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver};
pub use device::Device;
pub use frame_builder::ChasePrimitive;
pub use profiler::{ProfilerHooks, set_profiler_hooks};
pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};
pub use renderer::{RenderResults, RendererStats, SceneBuilderHooks, ThreadListener, ShaderPrecacheFlags};
pub use renderer::MAX_VERTEX_TEXTURE_WIDTH;
pub use shade::{Shaders, WrShaders};
pub use webrender_api as api;
pub use webrender_api::euclid;
<commit_msg>Bug 1444434 - Add C bindings to the Renderer::get_screenshot_async and Renderer::map_and_recycle_screenshot APIs r=kvark<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/. */

/*!
A GPU based renderer for the web.

It serves as an experimental render backend for [Servo](https://servo.org/),
but it can also be used as such in a standalone application.

# External dependencies
WebRender currently depends on [FreeType](https://www.freetype.org/)

# Api Structure
The main entry point to WebRender is the [`crate::Renderer`].

By calling [`Renderer::new(...)`](crate::Renderer::new) you get a [`Renderer`], as well as
a [`RenderApiSender`](api::RenderApiSender). Your [`Renderer`] is responsible to render the
previously processed frames onto the screen.

By calling [`yourRenderApiSender.create_api()`](api::RenderApiSender::create_api), you'll
get a [`RenderApi`](api::RenderApi) instance, which is responsible for managing resources
and documents. A worker thread is used internally to untie the workload from the application
thread and therefore be able to make better use of multicore systems.

## Frame

What is referred to as a `frame`, is the current geometry on the screen.
A new Frame is created by calling [`set_display_list()`](api::Transaction::set_display_list)
on the [`RenderApi`](api::RenderApi). When the geometry is processed, the application will be
informed via a [`RenderNotifier`](api::RenderNotifier), a callback which you pass to
[`Renderer::new`].
More information about [stacking contexts][stacking_contexts].

[`set_display_list()`](api::Transaction::set_display_list) also needs to be supplied with
[`BuiltDisplayList`](api::BuiltDisplayList)s. These are obtained by finalizing a
[`DisplayListBuilder`](api::DisplayListBuilder). These are used to draw your geometry. But it
doesn't only contain trivial geometry, it can also store another
[`StackingContext`](api::StackingContext), as they're nestable.

[stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
*/

// Cribbed from the |matches| crate, for simplicity.
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate cstr;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate malloc_size_of_derive;
#[cfg(any(feature = "serde"))]
#[macro_use]
extern crate serde;
#[macro_use]
extern crate thread_profiler;

extern crate wr_malloc_size_of;
use wr_malloc_size_of as malloc_size_of;

#[macro_use]
mod profiler;

mod batch;
mod border;
mod box_shadow;
#[cfg(any(feature = "capture", feature = "replay"))]
mod capture;
mod clip;
mod clip_scroll_tree;
mod debug_colors;
mod debug_font_data;
mod debug_render;
#[cfg(feature = "debugger")]
mod debug_server;
mod device;
mod display_list_flattener;
mod ellipse;
mod filterdata;
mod frame_builder;
mod freelist;
#[cfg(any(target_os = "macos", target_os = "windows"))]
mod gamma_lut;
mod glyph_cache;
mod glyph_rasterizer;
mod gpu_cache;
#[cfg(feature = "pathfinder")]
mod gpu_glyph_renderer;
mod gpu_types;
mod hit_test;
mod image;
mod intern;
mod internal_types;
mod picture;
mod prim_store;
mod print_tree;
mod record;
mod render_backend;
mod render_task;
mod renderer;
mod resource_cache;
mod scene;
mod scene_builder;
mod segment;
mod shade;
mod spatial_node;
mod storage;
mod texture_allocator;
mod texture_cache;
mod tiling;
mod util;

mod shader_source {
    include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
}

pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER};

mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::font;
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub use platform::unix::font;
    #[cfg(target_os = "windows")]
    pub use platform::windows::font;

    #[cfg(target_os = "macos")]
    pub mod macos {
        pub mod font;
    }
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub mod unix {
        pub mod font;
    }
    #[cfg(target_os = "windows")]
    pub mod windows {
        pub mod font;
    }
}

#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate core_text;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate freetype;
#[cfg(all(unix, not(target_os = "macos")))]
extern crate libc;

#[cfg(target_os = "windows")]
extern crate dwrote;

extern crate bincode;
extern crate byteorder;
extern crate fxhash;
extern crate gleam;
extern crate num_traits;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_font_renderer;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_gfx_utils;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_partitioner;
#[cfg(feature = "pathfinder")]
extern crate pathfinder_path_utils;
extern crate plane_split;
extern crate rayon;
#[cfg(feature = "ron")]
extern crate ron;
#[cfg(feature = "debugger")]
extern crate serde_json;
extern crate sha2;
extern crate smallvec;
extern crate time;
#[cfg(feature = "debugger")]
extern crate ws;
#[cfg(feature = "debugger")]
extern crate image as image_loader;
#[cfg(feature = "debugger")]
extern crate base64;
#[cfg(all(feature = "capture", feature = "png"))]
extern crate png;
#[cfg(test)]
extern crate rand;

#[macro_use]
pub extern crate webrender_api;
extern crate webrender_build;

#[doc(hidden)]
pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver};
pub use device::Device;
pub use frame_builder::ChasePrimitive;
pub use profiler::{ProfilerHooks, set_profiler_hooks};
pub use renderer::{AsyncPropertySampler, AsyncScreenshotHandle, CpuProfile, DebugFlags};
pub use renderer::{OutputImageHandler, RendererKind, ExternalImage, ExternalImageHandler};
pub use renderer::{ExternalImageSource, GpuProfile, GraphicsApi, GraphicsApiInfo, PipelineInfo};
pub use renderer::{Renderer, RendererOptions, RenderResults, RendererStats, SceneBuilderHooks};
pub use renderer::{ThreadListener, ShaderPrecacheFlags, MAX_VERTEX_TEXTURE_WIDTH};
pub use shade::{Shaders, WrShaders};
pub use webrender_api as api;
pub use webrender_api::euclid;
<|endoftext|>


<commit_before>use analysis::c_type::rustify_pointers;
use analysis::rust_type::*;
use env::Env;
use library::{self, Nullable};

pub struct Info {
    pub parameter: Option<library::Parameter>,
    pub base_tid: Option<library::TypeId>,  //Some only if need downcast
    pub commented: bool,
}

pub fn analyze(env: &Env, func: &library::Function, class_tid: library::TypeId,
    non_nullable_overrides: &[String], used_types: &mut Vec<String>) -> Info {

    let mut parameter = if func.ret.typ == Default::default() { None } else {
        if let Ok(s) = used_rust_type(env, func.ret.typ) {
            used_types.push(s);
        }
        // Since GIRs are bad at specifying return value nullability, assume
        // any returned pointer is nullable unless overridden by the config.
        let mut nullable = func.ret.nullable;
        if !*nullable && can_be_nullable_return(env, func.ret.typ) {
            *nullable = true;
        }
        if *nullable && non_nullable_overrides.binary_search(&func.name).is_ok() {
            *nullable = false;
        }
        Some(library::Parameter {
                nullable: nullable,
                .. func.ret.clone()
            })
    };

    let commented = if func.ret.typ == Default::default() { false } else {
        parameter_rust_type(env, func.ret.typ, func.ret.direction, Nullable(false)).is_err()
    };

    if func.kind == library::FunctionKind::Constructor {
        if let Some(par) = parameter {
            parameter = Some(library::Parameter {
                typ: class_tid,
                nullable: Nullable(false),
                ..par
            });
        }
    }

    let base_tid = if let Some(ref par) = parameter {
        get_base_type_id_from_c_type(env, par)
    } else {
        None
    };

    Info {
        parameter: parameter,
        base_tid: base_tid,
        commented: commented,
    }
}

fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool
{
    use library::Type::*;
    use library::Fundamental::*;
    match env.library.type_(type_id) {
        &Fundamental(fund) => match fund {
            Pointer => true,
            Utf8 => true,
            Filename => true,
            _ => false,
        },
        &Alias(ref alias) => can_be_nullable_return(env, alias.typ),
        &Enumeration(_) => false,
        &Bitfield(_) => false,
        &Record(_) => false,
        &Union(_) => false,
        &Function(_) => true,
        &Interface(_) => true,
        &Class(_) => true,
        _ => true
    }
}

fn get_base_type_id_from_c_type(env: &Env, par: &library::Parameter) -> Option<library::TypeId> {
    match env.type_(par.typ) {
        &library::Type::Class(_) => {
            let (_, inner) = rustify_pointers(&par.c_type);
            let typ = env.library.find_type_by_glib_name(&inner);
            match typ {
                Some(tid) => if tid == par.typ { None } else { typ },
                None => typ
            }
        }
        _ => None,
    }
}
<commit_msg>In return value analysis base_tid now only makes sense for constructors<commit_after>use analysis::rust_type::*;
use env::Env;
use library::{self, Nullable};

pub struct Info {
    pub parameter: Option<library::Parameter>,
    pub base_tid: Option<library::TypeId>,  //Some only if need downcast
    pub commented: bool,
}

pub fn analyze(env: &Env, func: &library::Function, class_tid: library::TypeId,
    non_nullable_overrides: &[String], used_types: &mut Vec<String>) -> Info {

    let mut parameter = if func.ret.typ == Default::default() { None } else {
        if let Ok(s) = used_rust_type(env, func.ret.typ) {
            used_types.push(s);
        }
        // Since GIRs are bad at specifying return value nullability, assume
        // any returned pointer is nullable unless overridden by the config.
        let mut nullable = func.ret.nullable;
        if !*nullable && can_be_nullable_return(env, func.ret.typ) {
            *nullable = true;
        }
        if *nullable && non_nullable_overrides.binary_search(&func.name).is_ok() {
            *nullable = false;
        }
        Some(library::Parameter {
                nullable: nullable,
                .. func.ret.clone()
            })
    };

    let commented = if func.ret.typ == Default::default() { false } else {
        parameter_rust_type(env, func.ret.typ, func.ret.direction, Nullable(false)).is_err()
    };

    let mut base_tid = None;

    if func.kind == library::FunctionKind::Constructor {
        if let Some(par) = parameter {
            if par.typ != class_tid {
                base_tid = Some(par.typ);
            }
            parameter = Some(library::Parameter {
                typ: class_tid,
                nullable: Nullable(false),
                ..par
            });
        }
    }

    Info {
        parameter: parameter,
        base_tid: base_tid,
        commented: commented,
    }
}

fn can_be_nullable_return(env: &Env, type_id: library::TypeId) -> bool
{
    use library::Type::*;
    use library::Fundamental::*;
    match env.library.type_(type_id) {
        &Fundamental(fund) => match fund {
            Pointer => true,
            Utf8 => true,
            Filename => true,
            _ => false,
        },
        &Alias(ref alias) => can_be_nullable_return(env, alias.typ),
        &Enumeration(_) => false,
        &Bitfield(_) => false,
        &Record(_) => false,
        &Union(_) => false,
        &Function(_) => true,
        &Interface(_) => true,
        &Class(_) => true,
        _ => true
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet, BTreeMap};
use std::fmt;
use std::str::FromStr;

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

use core::{Package, PackageId, SourceId, Workspace};
use util::{CargoResult, Graph, Config, internal, ChainError, CargoError};

use super::Resolve;

#[derive(RustcEncodable, RustcDecodable, Debug)]
pub struct EncodableResolve {
    package: Option<Vec<EncodableDependency>>,
    /// `root` is optional to allow forward compatibility.
    root: Option<EncodableDependency>,
    metadata: Option<Metadata>,
}

pub type Metadata = BTreeMap<String, String>;

impl EncodableResolve {
    pub fn into_resolve(self, ws: &Workspace) -> CargoResult<Resolve> {
        let path_deps = build_path_deps(ws);

        let packages = {
            let mut packages = self.package.unwrap_or(Vec::new());
            if let Some(root) = self.root {
                packages.insert(0, root);
            }
            packages
        };

        // `PackageId`s in the lock file don't include the `source` part
        // for workspace members, so we reconstruct proper ids.
        let (live_pkgs, all_pkgs) = {
            let mut live_pkgs = HashMap::new();
            let mut all_pkgs = HashSet::new();
            for pkg in packages.iter() {
                let enc_id = EncodablePackageId {
                    name: pkg.name.clone(),
                    version: pkg.version.clone(),
                    source: pkg.source.clone(),
                };

                if !all_pkgs.insert(enc_id.clone()) {
                    return Err(internal(format!("package `{}` is specified twice in the lockfile",
                                                pkg.name)));
                }
                let id = match pkg.source.as_ref().or(path_deps.get(&pkg.name)) {
                    // We failed to find a local package in the workspace.
                    // It must have been removed and should be ignored.
                    None => continue,
                    Some(source) => try!(PackageId::new(&pkg.name, &pkg.version, source))
                };

                assert!(live_pkgs.insert(enc_id, (id, pkg)).is_none())
            }
            (live_pkgs, all_pkgs)
        };

        let lookup_id = |enc_id: &EncodablePackageId| -> CargoResult<Option<PackageId>> {
            match live_pkgs.get(enc_id) {
                Some(&(ref id, _)) => Ok(Some(id.clone())),
                None => if all_pkgs.contains(enc_id) {
                    // Package is found in the lockfile, but it is
                    // no longer a member of the workspace.
                    Ok(None)
                } else {
                    Err(internal(format!("package `{}` is specified as a dependency, \
                                          but is missing from the package list", enc_id)))
                }
            }
        };

        let g = {
            let mut g = Graph::new();

            for &(ref id, _) in live_pkgs.values() {
                g.add(id.clone(), &[]);
            }

            for &(ref id, ref pkg) in live_pkgs.values() {
                let deps = match pkg.dependencies {
                    Some(ref deps) => deps,
                    None => continue
                };

                for edge in deps.iter() {
                    if let Some(to_depend_on) = try!(lookup_id(edge)) {
                        g.link(id.clone(), to_depend_on);
                    }
                }
            }
            g
        };

        let replacements = {
            let mut replacements = HashMap::new();
            for &(ref id, ref pkg) in live_pkgs.values() {
                if let Some(ref replace) = pkg.replace {
                    assert!(pkg.dependencies.is_none());
                    if let Some(replace_id) = try!(lookup_id(replace)) {
                        replacements.insert(id.clone(), replace_id);
                    }
                }
            }
            replacements
        };

        let mut metadata = self.metadata.unwrap_or(BTreeMap::new());

        // Parse out all package checksums. After we do this we can be in a few
        // situations:
        //
        // * We parsed no checksums. In this situation we're dealing with an old
        //   lock file and we're gonna fill them all in.
        // * We parsed some checksums, but not one for all packages listed. It
        //   could have been the case that some were listed, then an older Cargo
        //   client added more dependencies, and now we're going to fill in the
        //   missing ones.
        // * There are too many checksums listed, indicative of an older Cargo
        //   client removing a package but not updating the checksums listed.
        //
        // In all of these situations they're part of normal usage, so we don't
        // really worry about it. We just try to slurp up as many checksums as
        // possible.
        let mut checksums = HashMap::new();
        let prefix = "checksum ";
        let mut to_remove = Vec::new();
        for (k, v) in metadata.iter().filter(|p| p.0.starts_with(prefix)) {
            to_remove.push(k.to_string());
            let k = &k[prefix.len()..];
            let enc_id: EncodablePackageId = try!(k.parse().chain_error(|| {
                internal("invalid encoding of checksum in lockfile")
            }));
            let id = match lookup_id(&enc_id) {
                Ok(Some(id)) => id,
                _ => continue,
            };

            let v = if v == "<none>" {
                None
            } else {
                Some(v.to_string())
            };
            checksums.insert(id, v);
        }

        for k in to_remove {
            metadata.remove(&k);
        }

        Ok(Resolve {
            graph: g,
            features: HashMap::new(),
            replacements: replacements,
            checksums: checksums,
            metadata: metadata,
        })
    }
}

fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
    // If a crate is *not* a path source, then we're probably in a situation
    // such as `cargo install` with a lock file from a remote dependency. In
    // that case we don't need to fixup any path dependencies (as they're not
    // actually path dependencies any more), so we ignore them.
    let members = ws.members().filter(|p| {
        p.package_id().source_id().is_path()
    }).collect::<Vec<_>>();

    let mut ret = HashMap::new();
    for member in members.iter() {
        ret.insert(member.package_id().name().to_string(),
                   member.package_id().source_id().clone());
    }
    for member in members.iter() {
        build(member, ws.config(), &mut ret);
    }

    return ret;

    fn build(pkg: &Package,
             config: &Config,
             ret: &mut HashMap<String, SourceId>) {
        let deps = pkg.dependencies()
                      .iter()
                      .filter(|d| !ret.contains_key(d.name()))
                      .map(|d| d.source_id())
                      .filter(|id| id.is_path())
                      .filter_map(|id| id.url().to_file_path().ok())
                      .map(|path| path.join("Cargo.toml"))
                      .filter_map(|path| Package::for_path(&path, config).ok())
                      .collect::<Vec<_>>();
        for pkg in deps {
            ret.insert(pkg.name().to_string(),
                       pkg.package_id().source_id().clone());
            build(&pkg, config, ret);
        }
    }
}

#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct EncodableDependency {
    name: String,
    version: String,
    source: Option<SourceId>,
    dependencies: Option<Vec<EncodablePackageId>>,
    replace: Option<EncodablePackageId>,
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
pub struct EncodablePackageId {
    name: String,
    version: String,
    source: Option<SourceId>
}

impl fmt::Display for EncodablePackageId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{} {}", self.name, self.version));
        if let Some(ref s) = self.source {
            try!(write!(f, " ({})", s.to_url()));
        }
        Ok(())
    }
}

impl FromStr for EncodablePackageId {
    type Err = Box<CargoError>;

    fn from_str(s: &str) -> CargoResult<EncodablePackageId> {
        let regex = Regex::new(r"^([^ ]+) ([^ ]+)(?: \(([^\)]+)\))?$").unwrap();
        let captures = try!(regex.captures(s).ok_or_else(|| {
            internal("invalid serialized PackageId")
        }));

        let name = captures.at(1).unwrap();
        let version = captures.at(2).unwrap();

        let source_id = match captures.at(3) {
            Some(s) => Some(try!(SourceId::from_url(s))),
            None => None,
        };

        Ok(EncodablePackageId {
            name: name.to_string(),
            version: version.to_string(),
            source: source_id
        })
    }
}

impl Encodable for EncodablePackageId {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.to_string().encode(s)
    }
}

impl Decodable for EncodablePackageId {
    fn decode<D: Decoder>(d: &mut D) -> Result<EncodablePackageId, D::Error> {
        String::decode(d).and_then(|string| {
            string.parse::<EncodablePackageId>()
                  .map_err(|e| d.error(&e.to_string()))
        })
    }
}

pub struct WorkspaceResolve<'a, 'cfg: 'a> {
    pub ws: &'a Workspace<'cfg>,
    pub resolve: &'a Resolve,
    pub use_root_key: bool,
}

impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let mut ids: Vec<&PackageId> = self.resolve.graph.iter().collect();
        ids.sort();

        let root = self.ws.members().max_by_key(|member| {
            member.name()
        }).unwrap().package_id();

        let encodable = ids.iter().filter_map(|&id| {
            if self.use_root_key && root == id {
                return None
            }

            Some(encodable_resolve_node(id, self.resolve))
        }).collect::<Vec<_>>();

        let mut metadata = self.resolve.metadata.clone();

        for id in ids.iter().filter(|id| !id.source_id().is_path()) {
            let checksum = match self.resolve.checksums[*id] {
                Some(ref s) => &s[..],
                None => "<none>",
            };
            let id = encodable_package_id(id);
            metadata.insert(format!("checksum {}", id.to_string()),
                            checksum.to_string());
        }

        let metadata = if metadata.len() == 0 {None} else {Some(metadata)};

        let root = if self.use_root_key {
            Some(encodable_resolve_node(&root, self.resolve))
        } else {
            None
        };
        EncodableResolve {
            package: Some(encodable),
            root: root,
            metadata: metadata,
        }.encode(s)
    }
}

fn encodable_resolve_node(id: &PackageId, resolve: &Resolve)
                          -> EncodableDependency {
    let (replace, deps) = match resolve.replacement(id) {
        Some(id) => {
            (Some(encodable_package_id(id)), None)
        }
        None => {
            let mut deps = resolve.graph.edges(id)
                                  .into_iter().flat_map(|a| a)
                                  .map(encodable_package_id)
                                  .collect::<Vec<_>>();
            deps.sort();
            (None, Some(deps))
        }
    };

    let source = if id.source_id().is_path() {
        None
    } else {
        Some(id.source_id().clone())
    };

    EncodableDependency {
        name: id.name().to_string(),
        version: id.version().to_string(),
        source: source,
        dependencies: deps,
        replace: replace,
    }
}

fn encodable_package_id(id: &PackageId) -> EncodablePackageId {
    let source = if id.source_id().is_path() {
        None
    } else {
        Some(id.source_id().with_precise(None))
    };
    EncodablePackageId {
        name: id.name().to_string(),
        version: id.version().to_string(),
        source: source,
    }
}
<commit_msg>Replace for loop with iterators<commit_after>use std::collections::{HashMap, HashSet, BTreeMap};
use std::fmt;
use std::str::FromStr;

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

use core::{Package, PackageId, SourceId, Workspace};
use util::{CargoResult, Graph, Config, internal, ChainError, CargoError};

use super::Resolve;

#[derive(RustcEncodable, RustcDecodable, Debug)]
pub struct EncodableResolve {
    package: Option<Vec<EncodableDependency>>,
    /// `root` is optional to allow forward compatibility.
    root: Option<EncodableDependency>,
    metadata: Option<Metadata>,
}

pub type Metadata = BTreeMap<String, String>;

impl EncodableResolve {
    pub fn into_resolve(self, ws: &Workspace) -> CargoResult<Resolve> {
        let path_deps = build_path_deps(ws);

        let packages = {
            let mut packages = self.package.unwrap_or(Vec::new());
            if let Some(root) = self.root {
                packages.insert(0, root);
            }
            packages
        };

        // `PackageId`s in the lock file don't include the `source` part
        // for workspace members, so we reconstruct proper ids.
        let (live_pkgs, all_pkgs) = {
            let mut live_pkgs = HashMap::new();
            let mut all_pkgs = HashSet::new();
            for pkg in packages.iter() {
                let enc_id = EncodablePackageId {
                    name: pkg.name.clone(),
                    version: pkg.version.clone(),
                    source: pkg.source.clone(),
                };

                if !all_pkgs.insert(enc_id.clone()) {
                    return Err(internal(format!("package `{}` is specified twice in the lockfile",
                                                pkg.name)));
                }
                let id = match pkg.source.as_ref().or(path_deps.get(&pkg.name)) {
                    // We failed to find a local package in the workspace.
                    // It must have been removed and should be ignored.
                    None => continue,
                    Some(source) => try!(PackageId::new(&pkg.name, &pkg.version, source))
                };

                assert!(live_pkgs.insert(enc_id, (id, pkg)).is_none())
            }
            (live_pkgs, all_pkgs)
        };

        let lookup_id = |enc_id: &EncodablePackageId| -> CargoResult<Option<PackageId>> {
            match live_pkgs.get(enc_id) {
                Some(&(ref id, _)) => Ok(Some(id.clone())),
                None => if all_pkgs.contains(enc_id) {
                    // Package is found in the lockfile, but it is
                    // no longer a member of the workspace.
                    Ok(None)
                } else {
                    Err(internal(format!("package `{}` is specified as a dependency, \
                                          but is missing from the package list", enc_id)))
                }
            }
        };

        let g = {
            let mut g = Graph::new();

            for &(ref id, _) in live_pkgs.values() {
                g.add(id.clone(), &[]);
            }

            for &(ref id, ref pkg) in live_pkgs.values() {
                let deps = match pkg.dependencies {
                    Some(ref deps) => deps,
                    None => continue
                };

                for edge in deps.iter() {
                    if let Some(to_depend_on) = try!(lookup_id(edge)) {
                        g.link(id.clone(), to_depend_on);
                    }
                }
            }
            g
        };

        let replacements: HashMap<_, _> = try!(live_pkgs.values()
            .filter_map(|&(ref id, pkg)| pkg.replace.as_ref().and_then(|replace| {
                assert!(pkg.dependencies.is_none());
                match lookup_id(replace) {
                    Err(e) => Some(Err(e)),
                    Ok(None) => None,
                    Ok(Some(replace)) => Some(Ok((id.clone(), replace)))
                }
            })).collect());

        let mut metadata = self.metadata.unwrap_or(BTreeMap::new());

        // Parse out all package checksums. After we do this we can be in a few
        // situations:
        //
        // * We parsed no checksums. In this situation we're dealing with an old
        //   lock file and we're gonna fill them all in.
        // * We parsed some checksums, but not one for all packages listed. It
        //   could have been the case that some were listed, then an older Cargo
        //   client added more dependencies, and now we're going to fill in the
        //   missing ones.
        // * There are too many checksums listed, indicative of an older Cargo
        //   client removing a package but not updating the checksums listed.
        //
        // In all of these situations they're part of normal usage, so we don't
        // really worry about it. We just try to slurp up as many checksums as
        // possible.
        let mut checksums = HashMap::new();
        let prefix = "checksum ";
        let mut to_remove = Vec::new();
        for (k, v) in metadata.iter().filter(|p| p.0.starts_with(prefix)) {
            to_remove.push(k.to_string());
            let k = &k[prefix.len()..];
            let enc_id: EncodablePackageId = try!(k.parse().chain_error(|| {
                internal("invalid encoding of checksum in lockfile")
            }));
            let id = match lookup_id(&enc_id) {
                Ok(Some(id)) => id,
                _ => continue,
            };

            let v = if v == "<none>" {
                None
            } else {
                Some(v.to_string())
            };
            checksums.insert(id, v);
        }

        for k in to_remove {
            metadata.remove(&k);
        }

        Ok(Resolve {
            graph: g,
            features: HashMap::new(),
            replacements: replacements,
            checksums: checksums,
            metadata: metadata,
        })
    }
}

fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
    // If a crate is *not* a path source, then we're probably in a situation
    // such as `cargo install` with a lock file from a remote dependency. In
    // that case we don't need to fixup any path dependencies (as they're not
    // actually path dependencies any more), so we ignore them.
    let members = ws.members().filter(|p| {
        p.package_id().source_id().is_path()
    }).collect::<Vec<_>>();

    let mut ret = HashMap::new();
    for member in members.iter() {
        ret.insert(member.package_id().name().to_string(),
                   member.package_id().source_id().clone());
    }
    for member in members.iter() {
        build(member, ws.config(), &mut ret);
    }

    return ret;

    fn build(pkg: &Package,
             config: &Config,
             ret: &mut HashMap<String, SourceId>) {
        let deps = pkg.dependencies()
                      .iter()
                      .filter(|d| !ret.contains_key(d.name()))
                      .map(|d| d.source_id())
                      .filter(|id| id.is_path())
                      .filter_map(|id| id.url().to_file_path().ok())
                      .map(|path| path.join("Cargo.toml"))
                      .filter_map(|path| Package::for_path(&path, config).ok())
                      .collect::<Vec<_>>();
        for pkg in deps {
            ret.insert(pkg.name().to_string(),
                       pkg.package_id().source_id().clone());
            build(&pkg, config, ret);
        }
    }
}

#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct EncodableDependency {
    name: String,
    version: String,
    source: Option<SourceId>,
    dependencies: Option<Vec<EncodablePackageId>>,
    replace: Option<EncodablePackageId>,
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
pub struct EncodablePackageId {
    name: String,
    version: String,
    source: Option<SourceId>
}

impl fmt::Display for EncodablePackageId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{} {}", self.name, self.version));
        if let Some(ref s) = self.source {
            try!(write!(f, " ({})", s.to_url()));
        }
        Ok(())
    }
}

impl FromStr for EncodablePackageId {
    type Err = Box<CargoError>;

    fn from_str(s: &str) -> CargoResult<EncodablePackageId> {
        let regex = Regex::new(r"^([^ ]+) ([^ ]+)(?: \(([^\)]+)\))?$").unwrap();
        let captures = try!(regex.captures(s).ok_or_else(|| {
            internal("invalid serialized PackageId")
        }));

        let name = captures.at(1).unwrap();
        let version = captures.at(2).unwrap();

        let source_id = match captures.at(3) {
            Some(s) => Some(try!(SourceId::from_url(s))),
            None => None,
        };

        Ok(EncodablePackageId {
            name: name.to_string(),
            version: version.to_string(),
            source: source_id
        })
    }
}

impl Encodable for EncodablePackageId {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.to_string().encode(s)
    }
}

impl Decodable for EncodablePackageId {
    fn decode<D: Decoder>(d: &mut D) -> Result<EncodablePackageId, D::Error> {
        String::decode(d).and_then(|string| {
            string.parse::<EncodablePackageId>()
                  .map_err(|e| d.error(&e.to_string()))
        })
    }
}

pub struct WorkspaceResolve<'a, 'cfg: 'a> {
    pub ws: &'a Workspace<'cfg>,
    pub resolve: &'a Resolve,
    pub use_root_key: bool,
}

impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let mut ids: Vec<&PackageId> = self.resolve.graph.iter().collect();
        ids.sort();

        let root = self.ws.members().max_by_key(|member| {
            member.name()
        }).unwrap().package_id();

        let encodable = ids.iter().filter_map(|&id| {
            if self.use_root_key && root == id {
                return None
            }

            Some(encodable_resolve_node(id, self.resolve))
        }).collect::<Vec<_>>();

        let mut metadata = self.resolve.metadata.clone();

        for id in ids.iter().filter(|id| !id.source_id().is_path()) {
            let checksum = match self.resolve.checksums[*id] {
                Some(ref s) => &s[..],
                None => "<none>",
            };
            let id = encodable_package_id(id);
            metadata.insert(format!("checksum {}", id.to_string()),
                            checksum.to_string());
        }

        let metadata = if metadata.len() == 0 {None} else {Some(metadata)};

        let root = if self.use_root_key {
            Some(encodable_resolve_node(&root, self.resolve))
        } else {
            None
        };
        EncodableResolve {
            package: Some(encodable),
            root: root,
            metadata: metadata,
        }.encode(s)
    }
}

fn encodable_resolve_node(id: &PackageId, resolve: &Resolve)
                          -> EncodableDependency {
    let (replace, deps) = match resolve.replacement(id) {
        Some(id) => {
            (Some(encodable_package_id(id)), None)
        }
        None => {
            let mut deps = resolve.graph.edges(id)
                                  .into_iter().flat_map(|a| a)
                                  .map(encodable_package_id)
                                  .collect::<Vec<_>>();
            deps.sort();
            (None, Some(deps))
        }
    };

    let source = if id.source_id().is_path() {
        None
    } else {
        Some(id.source_id().clone())
    };

    EncodableDependency {
        name: id.name().to_string(),
        version: id.version().to_string(),
        source: source,
        dependencies: deps,
        replace: replace,
    }
}

fn encodable_package_id(id: &PackageId) -> EncodablePackageId {
    let source = if id.source_id().is_path() {
        None
    } else {
        Some(id.source_id().with_precise(None))
    };
    EncodablePackageId {
        name: id.name().to_string(),
        version: id.version().to_string(),
        source: source,
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<CString>,
    env: HashMap<String, Option<CString>>,
    cwd: Path,
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", String::from_utf8_lossy(self.program.as_bytes_no_nul())));

        for arg in self.args.iter() {
            try!(write!(f, " {}", String::from_utf8_lossy(arg.as_bytes_no_nul())));
        }

        write!(f, "`")
    }
}

impl ProcessBuilder {
    pub fn arg<T: ToCStr>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.to_c_str());
        self
    }

    pub fn args<T: ToCStr>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args.extend(arguments.iter().map(|t| t.to_c_str()));
        self
    }

    pub fn get_args(&self) -> &[CString] {
        self.args.as_slice()
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env<T: ToCStr>(mut self, key: &str, val: Option<T>) -> ProcessBuilder {
        self.env.insert(key.to_string(), val.map(|t| t.to_c_str()));
        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command.stdout(InheritFd(1))
               .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let command = self.build_command();

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.cwd(&self.cwd);
        for arg in self.args.iter() {
            command.arg(arg.as_bytes_no_nul());
        }
        for (k, v) in self.env.iter() {
            let k = k.as_slice();
            match *v {
                Some(ref v) => { command.env(k, v.as_bytes_no_nul()); }
                None => { command.env_remove(k); }
            }
        }
        command
    }

    fn debug_string(&self) -> String {
        let program = String::from_utf8_lossy(self.program.as_bytes_no_nul());
        let mut program = program.into_string();
        for arg in self.args.iter() {
            program.push_char(' ');
            let s = String::from_utf8_lossy(arg.as_bytes_no_nul());
            program.push_str(s.as_slice());
        }
        program
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: Vec::new(),
        cwd: os::getcwd(),
        env: HashMap::new(),
    }
}
<commit_msg>auto merge of #268 : alexcrichton/cargo/issue-267, r=wycats<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<CString>,
    env: HashMap<String, Option<CString>>,
    cwd: Path,
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", String::from_utf8_lossy(self.program.as_bytes_no_nul())));

        for arg in self.args.iter() {
            try!(write!(f, " {}", String::from_utf8_lossy(arg.as_bytes_no_nul())));
        }

        write!(f, "`")
    }
}

impl ProcessBuilder {
    pub fn arg<T: ToCStr>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.to_c_str());
        self
    }

    pub fn args<T: ToCStr>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args.extend(arguments.iter().map(|t| t.to_c_str()));
        self
    }

    pub fn get_args(&self) -> &[CString] {
        self.args.as_slice()
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env<T: ToCStr>(mut self, key: &str, val: Option<T>) -> ProcessBuilder {
        self.env.insert(key.to_string(), val.map(|t| t.to_c_str()));
        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .stdin(InheritFd(0));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let command = self.build_command();

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.cwd(&self.cwd);
        for arg in self.args.iter() {
            command.arg(arg.as_bytes_no_nul());
        }
        for (k, v) in self.env.iter() {
            let k = k.as_slice();
            match *v {
                Some(ref v) => { command.env(k, v.as_bytes_no_nul()); }
                None => { command.env_remove(k); }
            }
        }
        command
    }

    fn debug_string(&self) -> String {
        let program = String::from_utf8_lossy(self.program.as_bytes_no_nul());
        let mut program = program.into_string();
        for arg in self.args.iter() {
            program.push_char(' ');
            let s = String::from_utf8_lossy(arg.as_bytes_no_nul());
            program.push_str(s.as_slice());
        }
        program
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: Vec::new(),
        cwd: os::getcwd(),
        env: HashMap::new(),
    }
}
<|endoftext|>


<commit_before>
use bsp::i2c;

use mouros_rust_bindings::tasks;

const BMP085_I2C_ADDR: u8 = 0x77;

#[allow(dead_code)]
pub enum Precision {
    UltraLowPower,
    Standard,
    High,
    UltraHigh,
}

impl Precision {
    fn get_oversampling_param(&self) -> u32 {
        match *self {
            Precision::UltraLowPower => 0,
            Precision::Standard => 1,
            Precision::High => 2,
            Precision::UltraHigh => 3,
        }
    }

    fn get_pressure_conversion_time_ms(&self) -> u32 {
        match *self {
            Precision::UltraLowPower => 5,
            Precision::Standard => 8,
            Precision::High => 14,
            Precision::UltraHigh => 26,
        }
    }
}

struct CalibrationData {
    ac1: i32,
    ac2: i32,
    ac3: i32,
    ac4: u32,
    ac5: i32,
    ac6: i32,
    b1: i32,
    b2: i32,
    _mb: i32,
    mc: i32,
    md: i32,
}

pub struct Bmp085 {
    calib: Option<CalibrationData>,
    dev_addr: u8,
    i2c_bus: i2c::Peripheral,
    precision: Precision,
}

impl Bmp085 {
    pub fn new(periph: i2c::Peripheral) -> Bmp085 {
        Bmp085 {
            calib: None,
            dev_addr: BMP085_I2C_ADDR,
            i2c_bus: periph,
            precision: Precision::Standard,
        }
    }

    fn get_calibration_data(&mut self) -> Result<(), ()> {
        let mut set_addr = [0xaa];
        let mut conf_data = [0; 22];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut set_addr),
                i2c::Step::Read(&mut conf_data),
            ],
        );

        self.calib = Some(CalibrationData {
            ac1: ((conf_data[0] as u16) << 8 | conf_data[1] as u16) as i16 as i32,
            ac2: ((conf_data[2] as u16) << 8 | conf_data[3] as u16) as i16 as i32,
            ac3: ((conf_data[4] as u16) << 8 | conf_data[5] as u16) as i16 as i32,
            ac4: (conf_data[6] as u32) << 8 | conf_data[7] as u32,
            ac5: ((conf_data[8] as u16) << 8 | conf_data[9] as u16) as i16 as i32,
            ac6: ((conf_data[10] as u16) << 8 | conf_data[11] as u16) as i16 as i32,
            b1: ((conf_data[12] as u16) << 8 | conf_data[13] as u16) as i16 as i32,
            b2: ((conf_data[14] as u16) << 8 | conf_data[15] as u16) as i16 as i32,
            _mb: ((conf_data[16] as u16) << 8 | conf_data[17] as u16) as i16 as i32,
            mc: ((conf_data[18] as u16) << 8 | conf_data[19] as u16) as i16 as i32,
            md: ((conf_data[20] as u16) << 8 | conf_data[21] as u16) as i16 as i32,
        });

        Ok(())
    }

    fn get_raw_temp_val(&self) -> i32 {
        let mut t_meas_cmd = [0xf4, 0x2e];
        let mut t_data_addr = [0xf6];
        let mut t_data_buf = [0; 2];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [i2c::Step::Write(&mut t_meas_cmd)],
        );

        tasks::sleep(5);

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut t_data_addr),
                i2c::Step::Read(&mut t_data_buf),
            ],
        );

        (((t_data_buf[0] as u32) << 8) | t_data_buf[1] as u32) as i32
    }

    fn get_raw_pressure_val(&self) -> i32 {
        let oss = self.precision.get_oversampling_param();

        let mut p_meas_cmd = [0xf4, (0x34 + (oss << 6)) as u8];
        let mut p_data_addr = [0xf6];
        let mut p_data_buf = [0; 3];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [i2c::Step::Write(&mut p_meas_cmd)],
        );

        tasks::sleep(self.precision.get_pressure_conversion_time_ms());

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut p_data_addr),
                i2c::Step::Read(&mut p_data_buf),
            ],
        );

        (((p_data_buf[0] as u32) << 16 | (p_data_buf[1] as u32) << 8 | p_data_buf[2] as u32) >>
             (8 - oss)) as i32
    }

    pub fn set_precision(&mut self, precision: Precision) {
        self.precision = precision;
    }

    pub fn measure(&mut self) -> Result<(f32, f32), ()> {

        if self.calib.is_none() {
            self.get_calibration_data()?;
        }

        let calib = self.calib.as_ref().ok_or(())?;

        let ut = self.get_raw_temp_val();
        let up = self.get_raw_pressure_val();

        let x1: i32 = (ut - calib.ac6) * calib.ac5 >> 15;
        let x2: i32 = (calib.mc << 11) / (x1 + calib.md);
        let b5: i32 = x1 + x2;

        let t: i32 = (b5 + 8) >> 4;

        let b6: i32 = b5 - 4000;
        let x1: i32 = (calib.b2 * ((b6 * b6) >> 12)) >> 11;
        let x2: i32 = calib.ac2 * b6 >> 11;
        let x3: i32 = x1 + x2;

        let oss = self.precision.get_oversampling_param();

        let b3: i32 = ((((calib.ac1 << 2) + x3) << oss) + 2) >> 2;
        let x1: i32 = calib.ac3 * b6 >> 13;
        let x2: i32 = (calib.b1 * ((b6 * b6) >> 12)) >> 16;
        let x3: i32 = ((x1 + x2) + 2) >> 2;
        let b4: u32 = calib.ac4 * ((x3 + 32768) as u32) >> 15;
        let b7: u32 = ((up - b3) as u32) * (50000 >> oss);

        let p1: i32 = if b7 < 0x80000000 {
            ((b7 << 1) / b4) as i32
        } else {
            ((b7 / b4) << 1) as i32
        };

        let x1: i32 = (p1 >> 8) * (p1 >> 8);
        let x1: i32 = (x1 * 3038) >> 16;
        let x2: i32 = (-7357 * p1) >> 16;

        let p: i32 = p1 + ((x1 + x2 + 3791) >> 4);

        Ok(((t as f32) / 10.0, p as f32))
    }
}
<commit_msg>Started using Results in the BMP085 driver<commit_after>
use bsp::i2c;

use mouros_rust_bindings::tasks;

const BMP085_I2C_ADDR: u8 = 0x77;

#[allow(dead_code)]
pub enum Precision {
    UltraLowPower,
    Standard,
    High,
    UltraHigh,
}

impl Precision {
    fn get_oversampling_param(&self) -> u32 {
        match *self {
            Precision::UltraLowPower => 0,
            Precision::Standard => 1,
            Precision::High => 2,
            Precision::UltraHigh => 3,
        }
    }

    fn get_pressure_conversion_time_ms(&self) -> u32 {
        match *self {
            Precision::UltraLowPower => 5,
            Precision::Standard => 8,
            Precision::High => 14,
            Precision::UltraHigh => 26,
        }
    }
}

struct CalibrationData {
    ac1: i32,
    ac2: i32,
    ac3: i32,
    ac4: u32,
    ac5: i32,
    ac6: i32,
    b1: i32,
    b2: i32,
    _mb: i32,
    mc: i32,
    md: i32,
}

pub struct Bmp085 {
    calib: Option<CalibrationData>,
    dev_addr: u8,
    i2c_bus: i2c::Peripheral,
    precision: Precision,
}

impl Bmp085 {
    pub fn new(periph: i2c::Peripheral) -> Bmp085 {
        Bmp085 {
            calib: None,
            dev_addr: BMP085_I2C_ADDR,
            i2c_bus: periph,
            precision: Precision::Standard,
        }
    }

    fn get_calibration_data(&mut self) -> Result<(), ()> {
        let mut set_addr = [0xaa];
        let mut conf_data = [0; 22];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut set_addr),
                i2c::Step::Read(&mut conf_data),
            ],
        )?;

        self.calib = Some(CalibrationData {
            ac1: ((conf_data[0] as u16) << 8 | conf_data[1] as u16) as i16 as i32,
            ac2: ((conf_data[2] as u16) << 8 | conf_data[3] as u16) as i16 as i32,
            ac3: ((conf_data[4] as u16) << 8 | conf_data[5] as u16) as i16 as i32,
            ac4: (conf_data[6] as u32) << 8 | conf_data[7] as u32,
            ac5: ((conf_data[8] as u16) << 8 | conf_data[9] as u16) as i16 as i32,
            ac6: ((conf_data[10] as u16) << 8 | conf_data[11] as u16) as i16 as i32,
            b1: ((conf_data[12] as u16) << 8 | conf_data[13] as u16) as i16 as i32,
            b2: ((conf_data[14] as u16) << 8 | conf_data[15] as u16) as i16 as i32,
            _mb: ((conf_data[16] as u16) << 8 | conf_data[17] as u16) as i16 as i32,
            mc: ((conf_data[18] as u16) << 8 | conf_data[19] as u16) as i16 as i32,
            md: ((conf_data[20] as u16) << 8 | conf_data[21] as u16) as i16 as i32,
        });

        Ok(())
    }

    fn get_raw_temp_val(&self) -> Result<i32, ()> {
        let mut t_meas_cmd = [0xf4, 0x2e];
        let mut t_data_addr = [0xf6];
        let mut t_data_buf = [0; 2];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [i2c::Step::Write(&mut t_meas_cmd)],
        )?;

        tasks::sleep(5);

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut t_data_addr),
                i2c::Step::Read(&mut t_data_buf),
            ],
        )?;

        Ok((((t_data_buf[0] as u32) << 8) | t_data_buf[1] as u32) as i32)
    }

    fn get_raw_pressure_val(&self) -> Result<i32, ()> {
        let oss = self.precision.get_oversampling_param();

        let mut p_meas_cmd = [0xf4, (0x34 + (oss << 6)) as u8];
        let mut p_data_addr = [0xf6];
        let mut p_data_buf = [0; 3];

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [i2c::Step::Write(&mut p_meas_cmd)],
        )?;

        tasks::sleep(self.precision.get_pressure_conversion_time_ms());

        self.i2c_bus.run_transaction(
            self.dev_addr,
            &mut [
                i2c::Step::Write(&mut p_data_addr),
                i2c::Step::Read(&mut p_data_buf),
            ],
        )?;

        Ok((((p_data_buf[0] as u32) << 16 | (p_data_buf[1] as u32) << 8 | p_data_buf[2] as u32) >> (8 - oss)) as i32)
    }

    pub fn set_precision(&mut self, precision: Precision) {
        self.precision = precision;
    }

    pub fn measure(&mut self) -> Result<(f32, f32), ()> {

        if self.calib.is_none() {
            self.get_calibration_data()?;
        }

        let calib = self.calib.as_ref().ok_or(())?;

        let ut = self.get_raw_temp_val()?;
        let up = self.get_raw_pressure_val()?;

        let x1: i32 = (ut - calib.ac6) * calib.ac5 >> 15;
        let x2: i32 = (calib.mc << 11) / (x1 + calib.md);
        let b5: i32 = x1 + x2;

        let t: i32 = (b5 + 8) >> 4;

        let b6: i32 = b5 - 4000;
        let x1: i32 = (calib.b2 * ((b6 * b6) >> 12)) >> 11;
        let x2: i32 = calib.ac2 * b6 >> 11;
        let x3: i32 = x1 + x2;

        let oss = self.precision.get_oversampling_param();

        let b3: i32 = ((((calib.ac1 << 2) + x3) << oss) + 2) >> 2;
        let x1: i32 = calib.ac3 * b6 >> 13;
        let x2: i32 = (calib.b1 * ((b6 * b6) >> 12)) >> 16;
        let x3: i32 = ((x1 + x2) + 2) >> 2;
        let b4: u32 = calib.ac4 * ((x3 + 32768) as u32) >> 15;
        let b7: u32 = ((up - b3) as u32) * (50000 >> oss);

        let p1: i32 = if b7 < 0x80000000 {
            ((b7 << 1) / b4) as i32
        } else {
            ((b7 / b4) << 1) as i32
        };

        let x1: i32 = (p1 >> 8) * (p1 >> 8);
        let x1: i32 = (x1 * 3038) >> 16;
        let x2: i32 = (-7357 * p1) >> 16;

        let p: i32 = p1 + ((x1 + x2 + 3791) >> 4);

        Ok(((t as f32) / 10.0, p as f32))
    }
}
<|endoftext|>


<commit_before><commit_msg>Writes documentation for board/mod.rs<commit_after><|endoftext|>


<commit_before>//! Random access inspection of the results of a dataflow analysis.

use std::borrow::Borrow;
use std::cmp::Ordering;

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Location};

use super::{Analysis, Direction, Effect, EffectIndex, Results};

/// A `ResultsCursor` that borrows the underlying `Results`.
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;

/// Allows random access inspection of the results of a dataflow analysis.
///
/// This cursor only has linear performance within a basic block when its statements are visited in
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
/// block. The order in which basic blocks are inspected has no impact on performance.
///
/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
where
    A: Analysis<'tcx>,
{
    body: &'mir mir::Body<'tcx>,
    results: R,
    state: BitSet<A::Idx>,

    pos: CursorPosition,

    /// Indicates that `state` has been modified with a custom effect.
    ///
    /// When this flag is set, we need to reset to an entry set before doing a seek.
    state_needs_reset: bool,
}

impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
    A: Analysis<'tcx>,
    R: Borrow<Results<'tcx, A>>,
{
    /// Returns a new cursor for `results` that points to the entry of the `START_BLOCK`.
    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
        ResultsCursor {
            body,
            pos: CursorPosition::block_entry(mir::START_BLOCK),
            state: results.borrow().entry_set_for_block(mir::START_BLOCK).clone(),
            state_needs_reset: false,
            results,
        }
    }

    pub fn body(&self) -> &'mir mir::Body<'tcx> {
        self.body
    }

    /// Returns the `Analysis` used to generate the underlying results.
    pub fn analysis(&self) -> &A {
        &self.results.borrow().analysis
    }

    /// Returns the dataflow state at the current location.
    pub fn get(&self) -> &BitSet<A::Idx> {
        &self.state
    }

    /// Returns `true` if the dataflow state at the current location contains the given element.
    ///
    /// Shorthand for `self.get().contains(elem)`
    pub fn contains(&self, elem: A::Idx) -> bool {
        self.state.contains(elem)
    }

    /// Resets the cursor to hold the dataflow state for the given basic block at fixpoint.
    ///
    /// For forward dataflow analyses, this is the dataflow state prior to the first statement.
    ///
    /// For backward dataflow analyses, this is the dataflow state after the terminator.
    pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
        self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
        self.pos = CursorPosition::block_entry(block);
        self.state_needs_reset = false;
    }

    /// Resets the cursor to hold the state at the entry to the given block.
    ///
    /// For forward analyses, this is the block's state at fixpoint.
    ///
    /// For backward analyses, this is the state that will be propagated to its
    /// predecessors (ignoring edge-specific effects).
    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
        if A::Direction::is_forward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(Location { block, statement_index: 0 }, Effect::Primary)
        }
    }

    /// Resets the cursor to hold the state at the exit of the given block.
    ///
    /// For backward analyses, this is the block's state at fixpoint.
    ///
    /// For forward analyses, this is the state that will be propagated to its
    /// successors (ignoring edge-specific effects).
    pub fn seek_to_block_end(&mut self, block: BasicBlock) {
        if A::Direction::is_backward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(self.body.terminator_loc(block), Effect::Primary)
        }
    }

    /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location *will be* applied.
    pub fn seek_before_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Before)
    }

    /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location will be applied as well.
    pub fn seek_after_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Primary)
    }

    fn seek_after(&mut self, target: Location, effect: Effect) {
        assert!(target <= self.body.terminator_loc(target.block));

        // Reset to the entry of the target block if any of the following are true:
        //   - A custom effect has been applied to the cursor state.
        //   - We are in a different block than the target.
        //   - We are in the same block but have advanced past the target effect.
        if self.state_needs_reset || self.pos.block != target.block {
            self.seek_to_block_entry(target.block);
        } else if let Some(curr_effect) = self.pos.curr_effect_index {
            let mut ord = curr_effect.statement_index.cmp(&target.statement_index);
            if A::Direction::is_backward() {
                ord = ord.reverse()
            }

            match ord.then_with(|| curr_effect.effect.cmp(&effect)) {
                Ordering::Equal => return,
                Ordering::Greater => self.seek_to_block_entry(target.block),
                Ordering::Less => {}
            }
        }

        // At this point, the cursor is in the same block as the target location at an earlier
        // statement.
        debug_assert_eq!(target.block, self.pos.block);

        let block_data = &self.body[target.block];
        let next_effect = if A::Direction::is_forward() {
            #[rustfmt::skip]
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(0),
                EffectIndex::next_in_forward_order,
            )
        } else {
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(block_data.statements.len()),
                EffectIndex::next_in_backward_order,
            )
        };

        let analysis = &self.results.borrow().analysis;
        let target_effect_index = effect.at_index(target.statement_index);

        A::Direction::apply_effects_in_range(
            analysis,
            &mut self.state,
            target.block,
            block_data,
            next_effect..=target_effect_index,
        );

        self.pos =
            CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) };
    }

    /// Applies `f` to the cursor's internal state.
    ///
    /// This can be used, e.g., to apply the call return effect directly to the cursor without
    /// creating an extra copy of the dataflow state.
    pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut BitSet<A::Idx>)) {
        f(&self.results.borrow().analysis, &mut self.state);
        self.state_needs_reset = true;
    }
}

#[derive(Clone, Copy, Debug)]
struct CursorPosition {
    block: BasicBlock,
    curr_effect_index: Option<EffectIndex>,
}

impl CursorPosition {
    fn block_entry(block: BasicBlock) -> CursorPosition {
        CursorPosition { block, curr_effect_index: None }
    }
}
<commit_msg>Initialize the cursor with an empty state<commit_after>//! Random access inspection of the results of a dataflow analysis.

use std::borrow::Borrow;
use std::cmp::Ordering;

use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Location};

use super::{Analysis, Direction, Effect, EffectIndex, Results};

/// A `ResultsCursor` that borrows the underlying `Results`.
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;

/// Allows random access inspection of the results of a dataflow analysis.
///
/// This cursor only has linear performance within a basic block when its statements are visited in
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
/// block. The order in which basic blocks are inspected has no impact on performance.
///
/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
where
    A: Analysis<'tcx>,
{
    body: &'mir mir::Body<'tcx>,
    results: R,
    state: BitSet<A::Idx>,

    pos: CursorPosition,

    /// Indicates that `state` has been modified with a custom effect.
    ///
    /// When this flag is set, we need to reset to an entry set before doing a seek.
    state_needs_reset: bool,
}

impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
where
    A: Analysis<'tcx>,
    R: Borrow<Results<'tcx, A>>,
{
    /// Returns a new cursor that can inspect `results`.
    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
        let bits_per_block = results.borrow().entry_set_for_block(mir::START_BLOCK).domain_size();

        ResultsCursor {
            body,
            results,

            // Initialize to an empty `BitSet` and set `state_needs_reset` to tell the cursor that
            // it needs to reset to block entry before the first seek. The cursor position is
            // immaterial.
            state_needs_reset: true,
            state: BitSet::new_empty(bits_per_block),
            pos: CursorPosition::block_entry(mir::START_BLOCK),
        }
    }

    pub fn body(&self) -> &'mir mir::Body<'tcx> {
        self.body
    }

    /// Returns the `Analysis` used to generate the underlying results.
    pub fn analysis(&self) -> &A {
        &self.results.borrow().analysis
    }

    /// Returns the dataflow state at the current location.
    pub fn get(&self) -> &BitSet<A::Idx> {
        &self.state
    }

    /// Returns `true` if the dataflow state at the current location contains the given element.
    ///
    /// Shorthand for `self.get().contains(elem)`
    pub fn contains(&self, elem: A::Idx) -> bool {
        self.state.contains(elem)
    }

    /// Resets the cursor to hold the dataflow state for the given basic block at fixpoint.
    ///
    /// For forward dataflow analyses, this is the dataflow state prior to the first statement.
    ///
    /// For backward dataflow analyses, this is the dataflow state after the terminator.
    pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
        self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
        self.pos = CursorPosition::block_entry(block);
        self.state_needs_reset = false;
    }

    /// Resets the cursor to hold the state at the entry to the given block.
    ///
    /// For forward analyses, this is the block's state at fixpoint.
    ///
    /// For backward analyses, this is the state that will be propagated to its
    /// predecessors (ignoring edge-specific effects).
    pub fn seek_to_block_start(&mut self, block: BasicBlock) {
        if A::Direction::is_forward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(Location { block, statement_index: 0 }, Effect::Primary)
        }
    }

    /// Resets the cursor to hold the state at the exit of the given block.
    ///
    /// For backward analyses, this is the block's state at fixpoint.
    ///
    /// For forward analyses, this is the state that will be propagated to its
    /// successors (ignoring edge-specific effects).
    pub fn seek_to_block_end(&mut self, block: BasicBlock) {
        if A::Direction::is_backward() {
            self.seek_to_block_entry(block)
        } else {
            self.seek_after(self.body.terminator_loc(block), Effect::Primary)
        }
    }

    /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location *will be* applied.
    pub fn seek_before_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Before)
    }

    /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
    /// applied.
    ///
    /// The "before" effect at the target location will be applied as well.
    pub fn seek_after_primary_effect(&mut self, target: Location) {
        self.seek_after(target, Effect::Primary)
    }

    fn seek_after(&mut self, target: Location, effect: Effect) {
        assert!(target <= self.body.terminator_loc(target.block));

        // Reset to the entry of the target block if any of the following are true:
        //   - A custom effect has been applied to the cursor state.
        //   - We are in a different block than the target.
        //   - We are in the same block but have advanced past the target effect.
        if self.state_needs_reset || self.pos.block != target.block {
            self.seek_to_block_entry(target.block);
        } else if let Some(curr_effect) = self.pos.curr_effect_index {
            let mut ord = curr_effect.statement_index.cmp(&target.statement_index);
            if A::Direction::is_backward() {
                ord = ord.reverse()
            }

            match ord.then_with(|| curr_effect.effect.cmp(&effect)) {
                Ordering::Equal => return,
                Ordering::Greater => self.seek_to_block_entry(target.block),
                Ordering::Less => {}
            }
        }

        // At this point, the cursor is in the same block as the target location at an earlier
        // statement.
        debug_assert_eq!(target.block, self.pos.block);

        let block_data = &self.body[target.block];
        let next_effect = if A::Direction::is_forward() {
            #[rustfmt::skip]
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(0),
                EffectIndex::next_in_forward_order,
            )
        } else {
            self.pos.curr_effect_index.map_or_else(
                || Effect::Before.at_index(block_data.statements.len()),
                EffectIndex::next_in_backward_order,
            )
        };

        let analysis = &self.results.borrow().analysis;
        let target_effect_index = effect.at_index(target.statement_index);

        A::Direction::apply_effects_in_range(
            analysis,
            &mut self.state,
            target.block,
            block_data,
            next_effect..=target_effect_index,
        );

        self.pos =
            CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) };
    }

    /// Applies `f` to the cursor's internal state.
    ///
    /// This can be used, e.g., to apply the call return effect directly to the cursor without
    /// creating an extra copy of the dataflow state.
    pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut BitSet<A::Idx>)) {
        f(&self.results.borrow().analysis, &mut self.state);
        self.state_needs_reset = true;
    }
}

#[derive(Clone, Copy, Debug)]
struct CursorPosition {
    block: BasicBlock,
    curr_effect_index: Option<EffectIndex>,
}

impl CursorPosition {
    fn block_entry(block: BasicBlock) -> CursorPosition {
        CursorPosition { block, curr_effect_index: None }
    }
}
<|endoftext|>


<commit_before>//! Buffer allocation and management.
//!
//! Collection of common traits and implementations around
//! buffer creation and handling from various sources.
//!
//! Allocators provided:
//! - Dumb Buffers through [`crate::backend::drm::DrmDevice`]
//! - Gbm Buffers through [`::gbm::Device`]
//!
//! Buffer types supported:
//! - [DumbBuffers](dumb::DumbBuffer)
//! - [GbmBuffers](::gbm::BufferObject)
//! - [DmaBufs](dmabuf::Dmabuf)
//!
//! Helpers:
//! - [`Swapchain`] to help with buffer management for framebuffers

pub mod dmabuf;
#[cfg(feature = "backend_drm")]
pub mod dumb;
#[cfg(feature = "backend_gbm")]
pub mod gbm;

mod swapchain;
use crate::utils::{Buffer as BufferCoords, Size};
pub use swapchain::{Slot, Swapchain};

pub use drm_fourcc::{
    DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor,
    UnrecognizedFourcc, UnrecognizedVendor,
};

/// Common trait describing common properties of most types of buffers.
pub trait Buffer {
    /// Width of the two-dimensional buffer
    fn width(&self) -> u32 {
        self.size().w as u32
    }
    /// Height of the two-dimensional buffer
    fn height(&self) -> u32 {
        self.size().h as u32
    }
    /// Size of the two-dimensional buffer
    fn size(&self) -> Size<i32, BufferCoords>;
    /// Pixel format of the buffer
    fn format(&self) -> Format;
}

/// Interface to create Buffers
pub trait Allocator<B: Buffer> {
    /// Error type thrown if allocations fail
    type Error: std::error::Error;

    /// Try to create a buffer with the given dimensions and pixel format
    fn create_buffer(
        &mut self,
        width: u32,
        height: u32,
        fourcc: Fourcc,
        modifiers: &[Modifier],
    ) -> Result<B, Self::Error>;
}
<commit_msg>allocator: general impls for Arc<Mutex<_>> and Rc<RefCell<_>><commit_after>//! Buffer allocation and management.
//!
//! Collection of common traits and implementations around
//! buffer creation and handling from various sources.
//!
//! Allocators provided:
//! - Dumb Buffers through [`crate::backend::drm::DrmDevice`]
//! - Gbm Buffers through [`::gbm::Device`]
//!
//! Buffer types supported:
//! - [DumbBuffers](dumb::DumbBuffer)
//! - [GbmBuffers](::gbm::BufferObject)
//! - [DmaBufs](dmabuf::Dmabuf)
//!
//! Helpers:
//! - [`Swapchain`] to help with buffer management for framebuffers

pub mod dmabuf;
#[cfg(feature = "backend_drm")]
pub mod dumb;
#[cfg(feature = "backend_gbm")]
pub mod gbm;

mod swapchain;
use std::{
    cell::RefCell,
    rc::Rc,
    sync::{Arc, Mutex},
};

use crate::utils::{Buffer as BufferCoords, Size};
pub use swapchain::{Slot, Swapchain};

pub use drm_fourcc::{
    DrmFormat as Format, DrmFourcc as Fourcc, DrmModifier as Modifier, DrmVendor as Vendor,
    UnrecognizedFourcc, UnrecognizedVendor,
};

/// Common trait describing common properties of most types of buffers.
pub trait Buffer {
    /// Width of the two-dimensional buffer
    fn width(&self) -> u32 {
        self.size().w as u32
    }
    /// Height of the two-dimensional buffer
    fn height(&self) -> u32 {
        self.size().h as u32
    }
    /// Size of the two-dimensional buffer
    fn size(&self) -> Size<i32, BufferCoords>;
    /// Pixel format of the buffer
    fn format(&self) -> Format;
}

/// Interface to create Buffers
pub trait Allocator<B: Buffer> {
    /// Error type thrown if allocations fail
    type Error: std::error::Error;

    /// Try to create a buffer with the given dimensions and pixel format
    fn create_buffer(
        &mut self,
        width: u32,
        height: u32,
        fourcc: Fourcc,
        modifiers: &[Modifier],
    ) -> Result<B, Self::Error>;
}

// General implementations for interior mutability.

impl<A: Allocator<B>, B: Buffer> Allocator<B> for Arc<Mutex<A>> {
    type Error = A::Error;

    fn create_buffer(
        &mut self,
        width: u32,
        height: u32,
        fourcc: Fourcc,
        modifiers: &[Modifier],
    ) -> Result<B, Self::Error> {
        let mut guard = self.lock().unwrap();
        guard.create_buffer(width, height, fourcc, modifiers)
    }
}

impl<A: Allocator<B>, B: Buffer> Allocator<B> for Rc<RefCell<A>> {
    type Error = A::Error;

    fn create_buffer(
        &mut self,
        width: u32,
        height: u32,
        fourcc: Fourcc,
        modifiers: &[Modifier],
    ) -> Result<B, Self::Error> {
        self.borrow_mut().create_buffer(width, height, fourcc, modifiers)
    }
}
<|endoftext|>