<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use proc_macro2::Span;
use syn::Result as ParseResult;
use syn::{
    parse::{Parse, ParseStream},
    Token,
};

use crate::type_config::TypeConfig;

#[derive(PartialEq, Clone, Debug, Hash)]
pub enum UnsafePolicy {
    AllFunctionsSafe,
    AllFunctionsUnsafe,
}

impl Parse for UnsafePolicy {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        if input.parse::<Option<Token![unsafe]>>()?.is_some() {
            return Ok(UnsafePolicy::AllFunctionsSafe);
        }
        let r = match input.parse::<Option<syn::Ident>>()? {
            Some(id) => {
                if id == "unsafe_ffi" {
                    Ok(UnsafePolicy::AllFunctionsSafe)
                } else {
                    Err(syn::Error::new(id.span(), "expected unsafe_ffi"))
                }
            }
            None => Ok(UnsafePolicy::AllFunctionsUnsafe),
        };
        if !input.is_empty() {
            return Err(syn::Error::new(
                Span::call_site(),
                "unexpected tokens within safety directive",
            ));
        }
        r
    }
}

#[derive(Hash, Debug)]
pub struct IncludeCppConfig {
    pub inclusions: Vec<String>,
    pub exclude_utilities: bool,
    pub unsafe_policy: UnsafePolicy,
    pub type_config: TypeConfig,
    pub parse_only: bool,
}

impl Parse for IncludeCppConfig {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        // Takes as inputs:
        // 1. List of headers to include
        // 2. List of #defines to include
        // 3. Allowlist

        let mut inclusions = Vec::new();
        let mut parse_only = false;
        let mut exclude_utilities = false;
        let mut type_config = TypeConfig::new();
        let mut unsafe_policy = UnsafePolicy::AllFunctionsUnsafe;

        while !input.is_empty() {
            if input.parse::<Option<syn::Token![#]>>()?.is_some() {
                let ident: syn::Ident = input.parse()?;
                if ident != "include" {
                    return Err(syn::Error::new(ident.span(), "expected include"));
                }
                let hdr: syn::LitStr = input.parse()?;
                inclusions.push(hdr.value());
            } else {
                let ident: syn::Ident = input.parse()?;
                input.parse::<Option<syn::Token![!]>>()?;
                if ident == "generate" || ident == "generate_pod" {
                    let args;
                    syn::parenthesized!(args in input);
                    let generate: syn::LitStr = args.parse()?;
                    type_config.add_to_allowlist(generate.value());
                    if ident == "generate_pod" {
                        type_config.note_pod_request(generate.value());
                    }
                } else if ident == "block" {
                    let args;
                    syn::parenthesized!(args in input);
                    let generate: syn::LitStr = args.parse()?;
                    type_config.add_to_blocklist(generate.value());
                } else if ident == "parse_only" {
                    parse_only = true;
                } else if ident == "exclude_utilities" {
                    exclude_utilities = true;
                } else if ident == "safety" {
                    let args;
                    syn::parenthesized!(args in input);
                    unsafe_policy = args.parse()?;
                } else {
                    return Err(syn::Error::new(
                        ident.span(),
                        "expected generate, generate_pod, nested_type, safety or exclude_utilities",
                    ));
                }
            }
            if input.is_empty() {
                break;
            }
        }
        if !exclude_utilities {
            type_config.add_to_allowlist("make_string".to_string());
        }

        Ok(IncludeCppConfig {
            inclusions,
            exclude_utilities,
            unsafe_policy,
            type_config,
            parse_only,
        })
    }
}

#[cfg(test)]
mod parse_tests {
    use crate::config::UnsafePolicy;
    use syn::parse_quote;
    #[test]
    fn test_safety_unsafe() {
        let us: UnsafePolicy = parse_quote! {
            unsafe
        };
        assert_eq!(us, UnsafePolicy::AllFunctionsSafe)
    }

    #[test]
    fn test_safety_unsafe_ffi() {
        let us: UnsafePolicy = parse_quote! {
            unsafe_ffi
        };
        assert_eq!(us, UnsafePolicy::AllFunctionsSafe)
    }

    #[test]
    fn test_safety_safe() {
        let us: UnsafePolicy = parse_quote! {};
        assert_eq!(us, UnsafePolicy::AllFunctionsUnsafe)
    }
}
<commit_msg>Remove duplicated code.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use proc_macro2::Span;
use syn::Result as ParseResult;
use syn::{
    parse::{Parse, ParseStream},
    Token,
};

use crate::type_config::TypeConfig;

#[derive(PartialEq, Clone, Debug, Hash)]
pub enum UnsafePolicy {
    AllFunctionsSafe,
    AllFunctionsUnsafe,
}

impl Parse for UnsafePolicy {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        if input.parse::<Option<Token![unsafe]>>()?.is_some() {
            return Ok(UnsafePolicy::AllFunctionsSafe);
        }
        let r = match input.parse::<Option<syn::Ident>>()? {
            Some(id) => {
                if id == "unsafe_ffi" {
                    Ok(UnsafePolicy::AllFunctionsSafe)
                } else {
                    Err(syn::Error::new(id.span(), "expected unsafe_ffi"))
                }
            }
            None => Ok(UnsafePolicy::AllFunctionsUnsafe),
        };
        if !input.is_empty() {
            return Err(syn::Error::new(
                Span::call_site(),
                "unexpected tokens within safety directive",
            ));
        }
        r
    }
}

#[derive(Hash, Debug)]
pub struct IncludeCppConfig {
    pub inclusions: Vec<String>,
    pub exclude_utilities: bool,
    pub unsafe_policy: UnsafePolicy,
    pub type_config: TypeConfig,
    pub parse_only: bool,
}

impl Parse for IncludeCppConfig {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        // Takes as inputs:
        // 1. List of headers to include
        // 2. List of #defines to include
        // 3. Allowlist

        let mut inclusions = Vec::new();
        let mut parse_only = false;
        let mut exclude_utilities = false;
        let mut type_config = TypeConfig::new();
        let mut unsafe_policy = UnsafePolicy::AllFunctionsUnsafe;

        while !input.is_empty() {
            let has_hexathorpe = input.parse::<Option<syn::Token![#]>>()?.is_some();
            let ident: syn::Ident = input.parse()?;
            if has_hexathorpe {
                if ident != "include" {
                    return Err(syn::Error::new(ident.span(), "expected include"));
                }
                let hdr: syn::LitStr = input.parse()?;
                inclusions.push(hdr.value());
            } else {
                input.parse::<Option<syn::Token![!]>>()?;
                if ident == "generate" || ident == "generate_pod" {
                    let args;
                    syn::parenthesized!(args in input);
                    let generate: syn::LitStr = args.parse()?;
                    type_config.add_to_allowlist(generate.value());
                    if ident == "generate_pod" {
                        type_config.note_pod_request(generate.value());
                    }
                } else if ident == "block" {
                    let args;
                    syn::parenthesized!(args in input);
                    let generate: syn::LitStr = args.parse()?;
                    type_config.add_to_blocklist(generate.value());
                } else if ident == "parse_only" {
                    parse_only = true;
                } else if ident == "exclude_utilities" {
                    exclude_utilities = true;
                } else if ident == "safety" {
                    let args;
                    syn::parenthesized!(args in input);
                    unsafe_policy = args.parse()?;
                } else {
                    return Err(syn::Error::new(
                        ident.span(),
                        "expected generate, generate_pod, nested_type, safety or exclude_utilities",
                    ));
                }
            }
            if input.is_empty() {
                break;
            }
        }
        if !exclude_utilities {
            type_config.add_to_allowlist("make_string".to_string());
        }

        Ok(IncludeCppConfig {
            inclusions,
            exclude_utilities,
            unsafe_policy,
            type_config,
            parse_only,
        })
    }
}

#[cfg(test)]
mod parse_tests {
    use crate::config::UnsafePolicy;
    use syn::parse_quote;
    #[test]
    fn test_safety_unsafe() {
        let us: UnsafePolicy = parse_quote! {
            unsafe
        };
        assert_eq!(us, UnsafePolicy::AllFunctionsSafe)
    }

    #[test]
    fn test_safety_unsafe_ffi() {
        let us: UnsafePolicy = parse_quote! {
            unsafe_ffi
        };
        assert_eq!(us, UnsafePolicy::AllFunctionsSafe)
    }

    #[test]
    fn test_safety_safe() {
        let us: UnsafePolicy = parse_quote! {};
        assert_eq!(us, UnsafePolicy::AllFunctionsUnsafe)
    }
}
<|endoftext|>


<commit_before>#!/bin/bash
#![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc
pushd $(dirname "$0")/../
source scripts/config.sh
RUSTC="$(pwd)/build/bin/cg_clif"
popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/

//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
//! profiles.
//!
//! Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>
//!
//! This file is specially crafted to be both a valid bash script and valid rust source file. If
//! executed as bash script this will run the rust source using cg_clif in JIT mode.

use std::io::Write;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let profile_name = std::env::var("PROFILE").unwrap();
    let output_name = std::env::var("OUTPUT").unwrap();
    if profile_name.is_empty() || output_name.is_empty() {
        println!("Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>");
        std::process::exit(1);
    }
    let profile = std::fs::read_to_string(profile_name)
        .map_err(|err| format!("Failed to read profile {}", err))?;
    let mut output = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(output_name)?;

    for line in profile.lines() {
        let mut stack = &line[..line.rfind(" ").unwrap()];
        let count = &line[line.rfind(" ").unwrap() + 1..];

        // Filter away uninteresting samples
        if !stack.contains("rustc_codegen_cranelift") {
            continue;
        }

        if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items")
            || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph")
            || stack.contains("rustc_symbol_mangling::test::report_symbol_names")
        {
            continue;
        }

        // Trim start
        if let Some(index) = stack.find("rustc_interface::passes::configure_and_expand") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::passes::analysis") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::passes::start_codegen") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::queries::Linker::link") {
            stack = &stack[index..];
        }

        if let Some(index) = stack.find("rustc_codegen_cranelift::driver::aot::module_codegen") {
            stack = &stack[index..];
        }

        // Trim end
        const MALLOC: &str = "malloc";
        if let Some(index) = stack.find(MALLOC) {
            stack = &stack[..index + MALLOC.len()];
        }

        const FREE: &str = "free";
        if let Some(index) = stack.find(FREE) {
            stack = &stack[..index + FREE.len()];
        }

        const TYPECK_ITEM_BODIES: &str = "rustc_typeck::check::typeck_item_bodies";
        if let Some(index) = stack.find(TYPECK_ITEM_BODIES) {
            stack = &stack[..index + TYPECK_ITEM_BODIES.len()];
        }

        const COLLECT_AND_PARTITION_MONO_ITEMS: &str =
            "rustc_monomorphize::partitioning::collect_and_partition_mono_items";
        if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) {
            stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()];
        }

        const ASSERT_DEP_GRAPH: &str = "rustc_incremental::assert_dep_graph::assert_dep_graph";
        if let Some(index) = stack.find(ASSERT_DEP_GRAPH) {
            stack = &stack[..index + ASSERT_DEP_GRAPH.len()];
        }

        const REPORT_SYMBOL_NAMES: &str = "rustc_symbol_mangling::test::report_symbol_names";
        if let Some(index) = stack.find(REPORT_SYMBOL_NAMES) {
            stack = &stack[..index + REPORT_SYMBOL_NAMES.len()];
        }

        const ENCODE_METADATA: &str = "rustc_metadata::encode_metadata";
        if let Some(index) = stack.find(ENCODE_METADATA) {
            stack = &stack[..index + ENCODE_METADATA.len()];
        }

        const SUBST_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::subst_and_normalize_erasing_regions";
        if let Some(index) = stack.find(SUBST_AND_NORMALIZE_ERASING_REGIONS) {
            stack = &stack[..index + SUBST_AND_NORMALIZE_ERASING_REGIONS.len()];
        }

        const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_late_bound_regions";
        if let Some(index) = stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS) {
            stack = &stack[..index + NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()];
        }

        const INST_BUILD: &str = "<cranelift_frontend::frontend::FuncInstBuilder as cranelift_codegen::ir::builder::InstBuilderBase>::build";
        if let Some(index) = stack.find(INST_BUILD) {
            stack = &stack[..index + INST_BUILD.len()];
        }

        output.write_all(stack.as_bytes())?;
        output.write_all(&*b" ")?;
        output.write_all(count.as_bytes())?;
        output.write_all(&*b"\n")?;
    }

    Ok(())
}
<commit_msg>Update compiler/rustc_codegen_cranelift/scripts/filter_profile.rs<commit_after>#!/bin/bash
#![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc
pushd $(dirname "$0")/../
source scripts/config.sh
RUSTC="$(pwd)/build/bin/cg_clif"
popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/

//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
//! profiles.
//!
//! Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>
//!
//! This file is specially crafted to be both a valid bash script and valid rust source file. If
//! executed as bash script this will run the rust source using cg_clif in JIT mode.

use std::io::Write;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let profile_name = std::env::var("PROFILE").unwrap();
    let output_name = std::env::var("OUTPUT").unwrap();
    if profile_name.is_empty() || output_name.is_empty() {
        println!("Usage: ./filter_profile.rs <profile in stackcollapse format> <output file>");
        std::process::exit(1);
    }
    let profile = std::fs::read_to_string(profile_name)
        .map_err(|err| format!("Failed to read profile {}", err))?;
    let mut output = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(output_name)?;

    for line in profile.lines() {
        let mut stack = &line[..line.rfind(" ").unwrap()];
        let count = &line[line.rfind(" ").unwrap() + 1..];

        // Filter away uninteresting samples
        if !stack.contains("rustc_codegen_cranelift") {
            continue;
        }

        if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items")
            || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph")
            || stack.contains("rustc_symbol_mangling::test::report_symbol_names")
        {
            continue;
        }

        // Trim start
        if let Some(index) = stack.find("rustc_interface::passes::configure_and_expand") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::passes::analysis") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::passes::start_codegen") {
            stack = &stack[index..];
        } else if let Some(index) = stack.find("rustc_interface::queries::Linker::link") {
            stack = &stack[index..];
        }

        if let Some(index) = stack.find("rustc_codegen_cranelift::driver::aot::module_codegen") {
            stack = &stack[index..];
        }

        // Trim end
        const MALLOC: &str = "malloc";
        if let Some(index) = stack.find(MALLOC) {
            stack = &stack[..index + MALLOC.len()];
        }

        const FREE: &str = "free";
        if let Some(index) = stack.find(FREE) {
            stack = &stack[..index + FREE.len()];
        }

        const TYPECK_ITEM_BODIES: &str = "rustc_typeck::check::typeck_item_bodies";
        if let Some(index) = stack.find(TYPECK_ITEM_BODIES) {
            stack = &stack[..index + TYPECK_ITEM_BODIES.len()];
        }

        const COLLECT_AND_PARTITION_MONO_ITEMS: &str =
            "rustc_monomorphize::partitioning::collect_and_partition_mono_items";
        if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) {
            stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()];
        }

        const ASSERT_DEP_GRAPH: &str = "rustc_incremental::assert_dep_graph::assert_dep_graph";
        if let Some(index) = stack.find(ASSERT_DEP_GRAPH) {
            stack = &stack[..index + ASSERT_DEP_GRAPH.len()];
        }

        const REPORT_SYMBOL_NAMES: &str = "rustc_symbol_mangling::test::report_symbol_names";
        if let Some(index) = stack.find(REPORT_SYMBOL_NAMES) {
            stack = &stack[..index + REPORT_SYMBOL_NAMES.len()];
        }

        const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata";
        if let Some(index) = stack.find(ENCODE_METADATA) {
            stack = &stack[..index + ENCODE_METADATA.len()];
        }

        const SUBST_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::subst_and_normalize_erasing_regions";
        if let Some(index) = stack.find(SUBST_AND_NORMALIZE_ERASING_REGIONS) {
            stack = &stack[..index + SUBST_AND_NORMALIZE_ERASING_REGIONS.len()];
        }

        const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::<impl rustc_middle::ty::context::TyCtxt>::normalize_erasing_late_bound_regions";
        if let Some(index) = stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS) {
            stack = &stack[..index + NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()];
        }

        const INST_BUILD: &str = "<cranelift_frontend::frontend::FuncInstBuilder as cranelift_codegen::ir::builder::InstBuilderBase>::build";
        if let Some(index) = stack.find(INST_BUILD) {
            stack = &stack[..index + INST_BUILD.len()];
        }

        output.write_all(stack.as_bytes())?;
        output.write_all(&*b" ")?;
        output.write_all(count.as_bytes())?;
        output.write_all(&*b"\n")?;
    }

    Ok(())
}
<|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/. */

//! Implements parallel traversals over the DOM and flow trees.
//!
//! This code is highly unsafe. Keep this file small and easy to audit.

#![allow(unsafe_code)]

use context::LayoutContext;
use flow::{self, Flow};
use flow_ref::FlowRef;
use profile_traits::time::{self, TimerMetadata, profile};
use rayon;
use servo_config::opts;
use smallvec::SmallVec;
use std::mem;
use std::sync::atomic::{AtomicIsize, Ordering};
use style::dom::UnsafeNode;
use traversal::{AssignBSizes, AssignISizes, BubbleISizes};
use traversal::{PostorderFlowTraversal, PreorderFlowTraversal};

pub use style::parallel::traverse_dom;

/// Traversal chunk size.
const CHUNK_SIZE: usize = 16;

pub type FlowList = SmallVec<[UnsafeNode; CHUNK_SIZE]>;

#[allow(dead_code)]
fn static_assertion(node: UnsafeNode) {
    unsafe {
        let _: UnsafeFlow = ::std::intrinsics::transmute(node);
    }
}

/// Vtable + pointer representation of a Flow trait object.
pub type UnsafeFlow = (usize, usize);

fn null_unsafe_flow() -> UnsafeFlow {
    (0, 0)
}

pub fn mut_owned_flow_to_unsafe_flow(flow: *mut FlowRef) -> UnsafeFlow {
    unsafe {
        mem::transmute::<&Flow, UnsafeFlow>(&**flow)
    }
}

pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
    unsafe {
        mem::transmute::<&Flow, UnsafeFlow>(flow)
    }
}

/// Information that we need stored in each flow.
pub struct FlowParallelInfo {
    /// The number of children that still need work done.
    pub children_count: AtomicIsize,
    /// The address of the parent flow.
    pub parent: UnsafeFlow,
}

impl FlowParallelInfo {
    pub fn new() -> FlowParallelInfo {
        FlowParallelInfo {
            children_count: AtomicIsize::new(0),
            parent: null_unsafe_flow(),
        }
    }
}

/// Process current flow and potentially traverse its ancestors.
///
/// If we are the last child that finished processing, recursively process
/// our parent. Else, stop. Also, stop at the root.
///
/// Thus, if we start with all the leaves of a tree, we end up traversing
/// the whole tree bottom-up because each parent will be processed exactly
/// once (by the last child that finishes processing).
///
/// The only communication between siblings is that they both
/// fetch-and-subtract the parent's children count.
fn buttom_up_flow(mut unsafe_flow: UnsafeFlow,
                  assign_bsize_traversal: &AssignBSizes) {
    loop {
        // Get a real flow.
        let flow: &mut Flow = unsafe {
            mem::transmute(unsafe_flow)
        };

        // Perform the appropriate traversal.
        if assign_bsize_traversal.should_process(flow) {
            assign_bsize_traversal.process(flow);
        }

        let base = flow::mut_base(flow);

        // Reset the count of children for the next layout traversal.
        base.parallel.children_count.store(base.children.len() as isize,
                                           Ordering::Relaxed);

        // Possibly enqueue the parent.
        let unsafe_parent = base.parallel.parent;
        if unsafe_parent == null_unsafe_flow() {
            // We're done!
            break
        }

        // No, we're not at the root yet. Then are we the last child
        // of our parent to finish processing? If so, we can continue
        // on with our parent; otherwise, we've gotta wait.
        let parent: &mut Flow = unsafe {
            mem::transmute(unsafe_parent)
        };
        let parent_base = flow::mut_base(parent);
        if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 {
            // We were the last child of our parent. Reflow our parent.
            unsafe_flow = unsafe_parent
        } else {
            // Stop.
            break
        }
    }
}

fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
                         pool: &'scope rayon::ThreadPool,
                         scope: &rayon::Scope<'scope>,
                         assign_isize_traversal: &'scope AssignISizes,
                         assign_bsize_traversal: &'scope AssignBSizes)
{
    let mut discovered_child_flows = FlowList::new();

    for unsafe_flow in unsafe_flows {
        let mut had_children = false;
        unsafe {
            // Get a real flow.
            let flow: &mut Flow = mem::transmute(*unsafe_flow);
            flow::mut_base(flow).thread_id =
                pool.current_thread_index().unwrap() as u8;

            if assign_isize_traversal.should_process(flow) {
                // Perform the appropriate traversal.
                assign_isize_traversal.process(flow);
            }

            // Possibly enqueue the children.
            for kid in flow::child_iter_mut(flow) {
                had_children = true;
                discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
            }
        }

        // If there were no more children, start assigning block-sizes.
        if !had_children {
            buttom_up_flow(*unsafe_flow, &assign_bsize_traversal)
        }
    }

    if discovered_child_flows.is_empty() {
        return
    }

    if discovered_child_flows.len() <= CHUNK_SIZE {
        // We can handle all the children in this work unit.
        top_down_flow(&discovered_child_flows,
                      pool,
                      scope,
                      &assign_isize_traversal,
                      &assign_bsize_traversal);
    } else {
        // Spawn a new work unit for each chunk after the first.
        let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE);
        let first_chunk = chunks.next();
        for chunk in chunks {
            let nodes = chunk.iter().cloned().collect::<FlowList>();
            scope.spawn(move |scope| {
                top_down_flow(&nodes, pool, scope, &assign_isize_traversal, &assign_bsize_traversal);
            });
        }
        if let Some(chunk) = first_chunk {
            top_down_flow(chunk, pool, scope, &assign_isize_traversal, &assign_bsize_traversal);
        }
    }
}

pub fn traverse_flow_tree_preorder(
        root: &mut Flow,
        profiler_metadata: Option<TimerMetadata>,
        time_profiler_chan: time::ProfilerChan,
        context: &LayoutContext,
        queue: &rayon::ThreadPool) {
    if opts::get().bubble_inline_sizes_separately {
        let bubble_inline_sizes = BubbleISizes { layout_context: &context };
        bubble_inline_sizes.traverse(root);
    }

    let assign_isize_traversal = &AssignISizes { layout_context: &context };
    let assign_bsize_traversal = &AssignBSizes { layout_context: &context };
    let nodes = [borrowed_flow_to_unsafe_flow(root)];

    queue.install(move || {
        rayon::scope(move |scope| {
            profile(time::ProfilerCategory::LayoutParallelWarmup,
                    profiler_metadata, time_profiler_chan, move || {
                        top_down_flow(&nodes, queue, scope, assign_isize_traversal, assign_bsize_traversal);
            });
        });
    });
}
<commit_msg>Fix spelling of `bottom_up_flow`<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/. */

//! Implements parallel traversals over the DOM and flow trees.
//!
//! This code is highly unsafe. Keep this file small and easy to audit.

#![allow(unsafe_code)]

use context::LayoutContext;
use flow::{self, Flow};
use flow_ref::FlowRef;
use profile_traits::time::{self, TimerMetadata, profile};
use rayon;
use servo_config::opts;
use smallvec::SmallVec;
use std::mem;
use std::sync::atomic::{AtomicIsize, Ordering};
use style::dom::UnsafeNode;
use traversal::{AssignBSizes, AssignISizes, BubbleISizes};
use traversal::{PostorderFlowTraversal, PreorderFlowTraversal};

pub use style::parallel::traverse_dom;

/// Traversal chunk size.
const CHUNK_SIZE: usize = 16;

pub type FlowList = SmallVec<[UnsafeNode; CHUNK_SIZE]>;

#[allow(dead_code)]
fn static_assertion(node: UnsafeNode) {
    unsafe {
        let _: UnsafeFlow = ::std::intrinsics::transmute(node);
    }
}

/// Vtable + pointer representation of a Flow trait object.
pub type UnsafeFlow = (usize, usize);

fn null_unsafe_flow() -> UnsafeFlow {
    (0, 0)
}

pub fn mut_owned_flow_to_unsafe_flow(flow: *mut FlowRef) -> UnsafeFlow {
    unsafe {
        mem::transmute::<&Flow, UnsafeFlow>(&**flow)
    }
}

pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
    unsafe {
        mem::transmute::<&Flow, UnsafeFlow>(flow)
    }
}

/// Information that we need stored in each flow.
pub struct FlowParallelInfo {
    /// The number of children that still need work done.
    pub children_count: AtomicIsize,
    /// The address of the parent flow.
    pub parent: UnsafeFlow,
}

impl FlowParallelInfo {
    pub fn new() -> FlowParallelInfo {
        FlowParallelInfo {
            children_count: AtomicIsize::new(0),
            parent: null_unsafe_flow(),
        }
    }
}

/// Process current flow and potentially traverse its ancestors.
///
/// If we are the last child that finished processing, recursively process
/// our parent. Else, stop. Also, stop at the root.
///
/// Thus, if we start with all the leaves of a tree, we end up traversing
/// the whole tree bottom-up because each parent will be processed exactly
/// once (by the last child that finishes processing).
///
/// The only communication between siblings is that they both
/// fetch-and-subtract the parent's children count.
fn bottom_up_flow(mut unsafe_flow: UnsafeFlow,
                  assign_bsize_traversal: &AssignBSizes) {
    loop {
        // Get a real flow.
        let flow: &mut Flow = unsafe {
            mem::transmute(unsafe_flow)
        };

        // Perform the appropriate traversal.
        if assign_bsize_traversal.should_process(flow) {
            assign_bsize_traversal.process(flow);
        }

        let base = flow::mut_base(flow);

        // Reset the count of children for the next layout traversal.
        base.parallel.children_count.store(base.children.len() as isize,
                                           Ordering::Relaxed);

        // Possibly enqueue the parent.
        let unsafe_parent = base.parallel.parent;
        if unsafe_parent == null_unsafe_flow() {
            // We're done!
            break
        }

        // No, we're not at the root yet. Then are we the last child
        // of our parent to finish processing? If so, we can continue
        // on with our parent; otherwise, we've gotta wait.
        let parent: &mut Flow = unsafe {
            mem::transmute(unsafe_parent)
        };
        let parent_base = flow::mut_base(parent);
        if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 {
            // We were the last child of our parent. Reflow our parent.
            unsafe_flow = unsafe_parent
        } else {
            // Stop.
            break
        }
    }
}

fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
                         pool: &'scope rayon::ThreadPool,
                         scope: &rayon::Scope<'scope>,
                         assign_isize_traversal: &'scope AssignISizes,
                         assign_bsize_traversal: &'scope AssignBSizes)
{
    let mut discovered_child_flows = FlowList::new();

    for unsafe_flow in unsafe_flows {
        let mut had_children = false;
        unsafe {
            // Get a real flow.
            let flow: &mut Flow = mem::transmute(*unsafe_flow);
            flow::mut_base(flow).thread_id =
                pool.current_thread_index().unwrap() as u8;

            if assign_isize_traversal.should_process(flow) {
                // Perform the appropriate traversal.
                assign_isize_traversal.process(flow);
            }

            // Possibly enqueue the children.
            for kid in flow::child_iter_mut(flow) {
                had_children = true;
                discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
            }
        }

        // If there were no more children, start assigning block-sizes.
        if !had_children {
            bottom_up_flow(*unsafe_flow, &assign_bsize_traversal)
        }
    }

    if discovered_child_flows.is_empty() {
        return
    }

    if discovered_child_flows.len() <= CHUNK_SIZE {
        // We can handle all the children in this work unit.
        top_down_flow(&discovered_child_flows,
                      pool,
                      scope,
                      &assign_isize_traversal,
                      &assign_bsize_traversal);
    } else {
        // Spawn a new work unit for each chunk after the first.
        let mut chunks = discovered_child_flows.chunks(CHUNK_SIZE);
        let first_chunk = chunks.next();
        for chunk in chunks {
            let nodes = chunk.iter().cloned().collect::<FlowList>();
            scope.spawn(move |scope| {
                top_down_flow(&nodes, pool, scope, &assign_isize_traversal, &assign_bsize_traversal);
            });
        }
        if let Some(chunk) = first_chunk {
            top_down_flow(chunk, pool, scope, &assign_isize_traversal, &assign_bsize_traversal);
        }
    }
}

pub fn traverse_flow_tree_preorder(
        root: &mut Flow,
        profiler_metadata: Option<TimerMetadata>,
        time_profiler_chan: time::ProfilerChan,
        context: &LayoutContext,
        queue: &rayon::ThreadPool) {
    if opts::get().bubble_inline_sizes_separately {
        let bubble_inline_sizes = BubbleISizes { layout_context: &context };
        bubble_inline_sizes.traverse(root);
    }

    let assign_isize_traversal = &AssignISizes { layout_context: &context };
    let assign_bsize_traversal = &AssignBSizes { layout_context: &context };
    let nodes = [borrowed_flow_to_unsafe_flow(root)];

    queue.install(move || {
        rayon::scope(move |scope| {
            profile(time::ProfilerCategory::LayoutParallelWarmup,
                    profiler_metadata, time_profiler_chan, move || {
                        top_down_flow(&nodes, queue, scope, assign_isize_traversal, assign_bsize_traversal);
            });
        });
    });
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::ops::{Deref, DerefMut};

const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// A reference counted buffer of bytes.
///
/// An `IoBuf` is a representation of a byte buffer where sub-slices of it can
/// be handed out efficiently, each with a `'static` lifetime which keeps the
/// data alive. The buffer also supports mutation but may require bytes to be
/// copied to complete the operation.
pub struct IoBuf {
    buf: Arc<Vec<u8>>,
    start: usize,
    end: usize,
}

/// An RAII object returned from `get_mut` which provides mutable access to the
/// underlying `Vec<u8>`.
pub struct IoBufMut<'a> {
    buf: &'a mut Vec<u8>,
    end: &'a mut usize,
}

impl IoBuf {
    /// Creates a new IoBuf with no data and the default capacity.
    pub fn new() -> IoBuf {
        IoBuf::with_capacity(DEFAULT_BUF_SIZE)
    }

    /// Creates a new IoBuf with `cap` capacity.
    pub fn with_capacity(cap: usize) -> IoBuf {
        IoBuf {
            buf: Arc::new(Vec::with_capacity(cap)),
            start: 0,
            end: 0,
        }
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    fn set_start(&mut self, start: usize) -> &mut IoBuf {
        assert!(start < self.buf.as_ref().len());
        assert!(start <= self.end);
        self.start = start;
        self
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `end` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    fn set_end(&mut self, end: usize) -> &mut IoBuf {
        assert!(end < self.buf.len());
        assert!(self.start <= end);
        self.end = end;
        self
    }

    /// Returns the number of bytes contained in this `IoBuf`.
    pub fn len(&self) -> usize {
        self.end - self.start
    }

    /// Returns the inner contents of this `IoBuf` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned `IoBuf`
    /// contains elements `[at, len)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn split_off(&mut self, at: usize) -> IoBuf {
        let mut other = IoBuf { buf: self.buf.clone(), ..*self };
        let idx = self.start + at;
        other.set_start(idx);
        self.set_end(idx);
        return other
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned `IoBuf`
    /// contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> IoBuf {
        let mut other = IoBuf { buf: self.buf.clone(), ..*self };
        let idx = self.start + at;
        other.set_end(idx);
        self.set_start(idx);
        return other
    }

    /// Returns a mutable reference to the underlying growable buffer of bytes.
    ///
    /// If this `IoBuf` is the only instance pointing at the underlying buffer
    /// of bytes, a direct mutable reference will be returned. Otherwise the
    /// contents of this `IoBuf` will be reallocated in a fresh `Vec<u8>`
    /// allocation with the same capacity as this allocation, and that
    /// allocation will be returned.
    ///
    /// This operation **is not O(1)** as it may clone the entire contents of
    /// this buffer.
    ///
    /// The returned `IoBufMut` type implement `Deref` and `DerefMut` to
    /// `Vec<u8>` can the byte buffer can be manipulated using the standard
    /// `Vec<u8>` methods.
    pub fn get_mut(&mut self) -> IoBufMut {
        // Fast path if we can get mutable access to our own current
        // buffer.
        //
        // TODO: this should be a match or an if-let
        if Arc::get_mut(&mut self.buf).is_some() {
            let buf = Arc::get_mut(&mut self.buf).unwrap();
            buf.drain(..self.start);
            self.start = 0;
            return IoBufMut { buf: buf, end: &mut self.end }
        }

        // If we couldn't get access above then we give ourself a new buffer
        // here.
        let mut v = Vec::with_capacity(self.buf.capacity());
        v.extend_from_slice(self.as_ref());
        self.start = 0;
        self.buf = Arc::new(v);
        IoBufMut {
            buf: Arc::get_mut(&mut self.buf).unwrap(),
            end: &mut self.end,
        }
    }
}

impl AsRef<[u8]> for IoBuf {
    fn as_ref(&self) -> &[u8] {
        &self.buf[self.start..self.end]
    }
}

impl<'a> Deref for IoBufMut<'a> {
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8> {
        self.buf
    }
}

impl<'a> DerefMut for IoBufMut<'a> {
    fn deref_mut(&mut self) -> &mut Vec<u8> {
        self.buf
    }
}

impl<'a> Drop for IoBufMut<'a> {
    fn drop(&mut self) {
        *self.end = self.buf.len();
    }
}
<commit_msg>Fix some iobuf assertions<commit_after>use std::sync::Arc;
use std::ops::{Deref, DerefMut};

const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// A reference counted buffer of bytes.
///
/// An `IoBuf` is a representation of a byte buffer where sub-slices of it can
/// be handed out efficiently, each with a `'static` lifetime which keeps the
/// data alive. The buffer also supports mutation but may require bytes to be
/// copied to complete the operation.
pub struct IoBuf {
    buf: Arc<Vec<u8>>,
    start: usize,
    end: usize,
}

/// An RAII object returned from `get_mut` which provides mutable access to the
/// underlying `Vec<u8>`.
pub struct IoBufMut<'a> {
    buf: &'a mut Vec<u8>,
    end: &'a mut usize,
}

impl IoBuf {
    /// Creates a new IoBuf with no data and the default capacity.
    pub fn new() -> IoBuf {
        IoBuf::with_capacity(DEFAULT_BUF_SIZE)
    }

    /// Creates a new IoBuf with `cap` capacity.
    pub fn with_capacity(cap: usize) -> IoBuf {
        IoBuf {
            buf: Arc::new(Vec::with_capacity(cap)),
            start: 0,
            end: 0,
        }
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    fn set_start(&mut self, start: usize) -> &mut IoBuf {
        assert!(start <= self.buf.as_ref().len());
        assert!(start <= self.end);
        self.start = start;
        self
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `end` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    fn set_end(&mut self, end: usize) -> &mut IoBuf {
        assert!(end <= self.buf.len());
        assert!(self.start <= end);
        self.end = end;
        self
    }

    /// Returns the number of bytes contained in this `IoBuf`.
    pub fn len(&self) -> usize {
        self.end - self.start
    }

    /// Returns the inner contents of this `IoBuf` as a slice.
    pub fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[0, at)`, and the returned `IoBuf`
    /// contains elements `[at, len)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn split_off(&mut self, at: usize) -> IoBuf {
        let mut other = IoBuf { buf: self.buf.clone(), ..*self };
        let idx = self.start + at;
        other.set_start(idx);
        self.set_end(idx);
        return other
    }

    /// Splits the buffer into two at the given index.
    ///
    /// Afterwards `self` contains elements `[at, len)`, and the returned `IoBuf`
    /// contains elements `[0, at)`.
    ///
    /// This is an O(1) operation that just increases the reference count and
    /// sets a few indexes.
    ///
    /// # Panics
    ///
    /// Panics if `at > len`
    pub fn drain_to(&mut self, at: usize) -> IoBuf {
        let mut other = IoBuf { buf: self.buf.clone(), ..*self };
        let idx = self.start + at;
        other.set_end(idx);
        self.set_start(idx);
        return other
    }

    /// Returns a mutable reference to the underlying growable buffer of bytes.
    ///
    /// If this `IoBuf` is the only instance pointing at the underlying buffer
    /// of bytes, a direct mutable reference will be returned. Otherwise the
    /// contents of this `IoBuf` will be reallocated in a fresh `Vec<u8>`
    /// allocation with the same capacity as this allocation, and that
    /// allocation will be returned.
    ///
    /// This operation **is not O(1)** as it may clone the entire contents of
    /// this buffer.
    ///
    /// The returned `IoBufMut` type implement `Deref` and `DerefMut` to
    /// `Vec<u8>` can the byte buffer can be manipulated using the standard
    /// `Vec<u8>` methods.
    pub fn get_mut(&mut self) -> IoBufMut {
        // Fast path if we can get mutable access to our own current
        // buffer.
        //
        // TODO: this should be a match or an if-let
        if Arc::get_mut(&mut self.buf).is_some() {
            let buf = Arc::get_mut(&mut self.buf).unwrap();
            buf.drain(..self.start);
            self.start = 0;
            return IoBufMut { buf: buf, end: &mut self.end }
        }

        // If we couldn't get access above then we give ourself a new buffer
        // here.
        let mut v = Vec::with_capacity(self.buf.capacity());
        v.extend_from_slice(self.as_ref());
        self.start = 0;
        self.buf = Arc::new(v);
        IoBufMut {
            buf: Arc::get_mut(&mut self.buf).unwrap(),
            end: &mut self.end,
        }
    }
}

impl AsRef<[u8]> for IoBuf {
    fn as_ref(&self) -> &[u8] {
        &self.buf[self.start..self.end]
    }
}

impl<'a> Deref for IoBufMut<'a> {
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8> {
        self.buf
    }
}

impl<'a> DerefMut for IoBufMut<'a> {
    fn deref_mut(&mut self) -> &mut Vec<u8> {
        self.buf
    }
}

impl<'a> Drop for IoBufMut<'a> {
    fn drop(&mut self) {
        *self.end = self.buf.len();
    }
}
<|endoftext|>


<commit_before>use assert_matches::assert_matches;
use futures::future::lazy;
use futures::io::{AsyncWrite, Cursor};
use futures::task::Poll;
use std::pin::Pin;

#[test]
fn cursor_asyncwrite_vec() {
    let mut cursor = Cursor::new(vec![0; 5]);
    futures::executor::block_on(lazy(|cx| {
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(2)));
    }));
    assert_eq!(cursor.into_inner(), [1, 2, 3, 4, 5, 6, 6, 7]);
}

#[test]
fn cursor_asyncwrite_box() {
    let mut cursor = Cursor::new(vec![0; 5].into_boxed_slice());
    futures::executor::block_on(lazy(|cx| {
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(1)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(0)));
    }));
    assert_eq!(&*cursor.into_inner(), [1, 2, 3, 4, 5]);
}
<commit_msg>futures: tests/io_cursor.rs :  Avoid breaking w/o features<commit_after>#[cfg(all(feature = "std", feature = "executor"))]
#[test]
fn cursor_asyncwrite_vec() {
    use assert_matches::assert_matches;
    use futures::future::lazy;
    use futures::io::{AsyncWrite, Cursor};
    use futures::task::Poll;
    use std::pin::Pin;

    let mut cursor = Cursor::new(vec![0; 5]);
    futures::executor::block_on(lazy(|cx| {
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(2)));
    }));
    assert_eq!(cursor.into_inner(), [1, 2, 3, 4, 5, 6, 6, 7]);
}

#[cfg(all(feature = "std", feature = "executor"))]
#[test]
fn cursor_asyncwrite_box() {
    use assert_matches::assert_matches;
    use futures::future::lazy;
    use futures::io::{AsyncWrite, Cursor};
    use futures::task::Poll;
    use std::pin::Pin;

    let mut cursor = Cursor::new(vec![0; 5].into_boxed_slice());
    futures::executor::block_on(lazy(|cx| {
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[1, 2]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[3, 4]), Poll::Ready(Ok(2)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[5, 6]), Poll::Ready(Ok(1)));
        assert_matches!(Pin::new(&mut cursor).poll_write(cx, &[6, 7]), Poll::Ready(Ok(0)));
    }));
    assert_eq!(&*cursor.into_inner(), [1, 2, 3, 4, 5]);
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate hyper;
extern crate debug;

use std::io::util::copy;
use std::io::net::ip::Ipv4Addr;
use std::sync::Arc;

use hyper::{Get, Post};
use hyper::server::{Server, Handler, Incoming, Request, Response};
use hyper::header::common::ContentLength;

trait ConcurrentHandler: Send + Sync {
    fn handle(&self, req: Request, res: Response);
}

struct Concurrent<H: ConcurrentHandler> { handler: Arc<H> }

impl<H: ConcurrentHandler> Handler for Concurrent<H> {
    fn handle(self, mut incoming: Incoming) {
        for (mut req, mut res) in incoming {
            let clone = self.handler.clone();
            spawn(proc() { clone.handle(req, res) })
        }
    }
}

macro_rules! try_abort(
    ($e:expr) => {{
        match $e {
            Ok(v) => v,
            Err(..) => return
        }
    }}
)

struct Echo;

impl ConcurrentHandler for Echo {
    fn handle(&self, mut req: Request, mut res: Response) {
        match req.uri {
            hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
                (&Get, "/") | (&Get, "/echo") => {
                    let out = b"Try POST /echo";

                    res.headers.set(ContentLength(out.len()));
                    try_abort!(res.write(out));
                    try_abort!(res.end());
                    return;
                },
                (&Post, "/echo") => (), // fall through, fighting mutable borrows
                _ => {
                    res.status = hyper::status::NotFound;
                    try_abort!(res.end());
                    return;
                }
            },
            _ => {
                try_abort!(res.end());
                return;
            }
        }
        try_abort!(copy(&mut req, &mut res));
        try_abort!(res.end());
    }
}

fn main() {
    let server = Server::http(Ipv4Addr(127, 0, 0, 1), 3000);
    server.listen(Concurrent { handler: Arc::new(Echo) }).unwrap();
}
<commit_msg>Fix concurrent server example for new Response representation.<commit_after>#![feature(macro_rules)]

extern crate hyper;
extern crate debug;

use std::io::util::copy;
use std::io::net::ip::Ipv4Addr;
use std::sync::Arc;

use hyper::{Get, Post};
use hyper::server::{Server, Handler, Incoming, Request, Response, Fresh};
use hyper::header::common::ContentLength;

trait ConcurrentHandler: Send + Sync {
    fn handle(&self, req: Request, res: Response<Fresh>);
}

struct Concurrent<H: ConcurrentHandler> { handler: Arc<H> }

impl<H: ConcurrentHandler> Handler for Concurrent<H> {
    fn handle(self, mut incoming: Incoming) {
        for (mut req, mut res) in incoming {
            let clone = self.handler.clone();
            spawn(proc() { clone.handle(req, res) })
        }
    }
}

macro_rules! try_abort(
    ($e:expr) => {{
        match $e {
            Ok(v) => v,
            Err(..) => return
        }
    }}
)

struct Echo;

impl ConcurrentHandler for Echo {
    fn handle(&self, mut req: Request, mut res: Response<Fresh>) {
        match req.uri {
            hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
                (&Get, "/") | (&Get, "/echo") => {
                    let out = b"Try POST /echo";

                    res.headers_mut().set(ContentLength(out.len()));
                    let mut res = try_abort!(res.start());
                    try_abort!(res.write(out));
                    try_abort!(res.end());
                    return;
                },
                (&Post, "/echo") => (), // fall through, fighting mutable borrows
                _ => {
                    *res.status_mut() = hyper::status::NotFound;
                    try_abort!(res.start().and_then(|res| res.end()));
                    return;
                }
            },
            _ => {
                try_abort!(res.start().and_then(|res| res.end()));
                return;
            }
        }
        let mut res = try_abort!(res.start());
        try_abort!(copy(&mut req, &mut res));
        try_abort!(res.end());
    }
}

fn main() {
    let server = Server::http(Ipv4Addr(127, 0, 0, 1), 3000);
    server.listen(Concurrent { handler: Arc::new(Echo) }).unwrap();
}
<|endoftext|>


<commit_before>use std::error::Error;
use diesel::prelude::*;
use schema::{images, tags, images_tags, images_collections, collections};
use schema::images::dsl::*;
use super::super::models::{ImagesTag, NewImagesTag, Tag, Image, NewImage, Collection,
                           ImagesCollection};
use super::super::db_manager;
use super::super::diesel;
use super::file_storage;
use std::fs::File;

pub fn create(new_image: &NewImage) -> Result<Image, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result: Image = try!(diesel::insert(new_image)
                                 .into(images::table)
                                 .get_result(conn));
    Ok(result)
}

pub fn create_image_file(image_id: i32, data: &[u8]) -> Result<Image, Box<Error>> {
    let img = try!(find(image_id));
    try!(file_storage::store_image(img.id, data));
    Ok(img)
}

pub fn create_sidecar_file(image_id: i32, sidecar: &[u8]) -> Result<Image, Box<Error>> {
    let img = try!(find(image_id));
    try!(file_storage::store_sidecar_file(img.id, sidecar));
    Ok(img)
}

pub fn get_all() -> Result<Vec<Image>, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(images.load(conn));
    Ok(result)
}

pub fn find(image_id: i32) -> Result<Image, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    Ok(img)
}

pub fn find_image_file(image_id: i32) -> Result<File, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    let data = try!(file_storage::load_image(img.id));
    Ok(data)
}

pub fn find_sidecar_file(image_id: i32) -> Result<File, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    let data = try!(file_storage::load_sidecar_file(img.id));
    Ok(data)
}

pub fn find_range(size: i64, offset: i64) -> Result<Vec<Image>, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(images.limit(size).offset(offset).load(conn));
    Ok(result)
}

pub fn update(image: &Image) -> Result<Image, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(diesel::update(images.find(image.id))
                          .set((title.eq(image.title.clone()),
                                description.eq(image.description.clone()),
                                license.eq(image.license.clone()),
                                side_car_file.eq(image.side_car_file.clone()),
                                raw_image_id.eq(image.raw_image_id.clone())))
                          .get_result(conn));
    Ok(result)
}

pub fn add_tag_to_image(image: &Image, tag: &Tag) -> Result<ImagesTag, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let new_image_tag = NewImagesTag {
        image_id: image.id,
        tag_id: tag.id,
    };
    let result = try!(diesel::insert(&new_image_tag)
                          .into(images_tags::table)
                          .get_result(conn));
    Ok(result)
}

pub fn get_tags_of_image(image: &Image) -> Result<Vec<Tag>, Box<Error>> {
    use diesel::pg::expression::dsl::any;
    let ref conn = *try!(db_manager::POOL.get());
    let image_tag_ids = ImagesTag::belonging_to(image).select(images_tags::tag_id);
    Ok(try!(tags::table
                .filter(tags::id.eq(any(image_tag_ids)))
                .load::<Tag>(conn)))
}

pub fn get_collections_of_image(image: &Image) -> Result<Vec<Collection>, Box<Error>> {
    use diesel::pg::expression::dsl::any;
    let ref conn = *try!(db_manager::POOL.get());
    let image_collection_ids = ImagesCollection::belonging_to(image)
        .select(images_collections::collection_id);
    Ok(try!(collections::table
                .filter(collections::id.eq(any(image_collection_ids)))
                .load::<Collection>(conn)))
}

#[cfg(test)]
mod tests {
    use super::*;
    use models::NewRawImage;
    use super::super::raw_image_service;
    use diesel::pg::data_types::PgDate;

    #[test]
    fn test_create() {
        // create raw image
        let image = b"Hello, wurst!";
        let raw_img = NewRawImage {
            user_id: 999,
            camera: "megapixelzoom".to_string(),
            latitude: 0.22,
            longitude: 0.32,
        };
        let raw = match raw_image_service::create(&raw_img) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        // do the test
        let image = b"Hello, wurst image!";
        let sidecar = b"I am a sidecar file!";
        let test_img = NewImage {
            title: "test image".to_string(),
            description: "desc of test image".to_string(),
            license: "MIT".to_string(),
            side_car_file: "carly".to_string(),
            raw_image_id: raw.id,
        };
        let img = match create(&test_img) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        let img = match create_image_file(img.id, image) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        let img = match create_sidecar_file(img.id, sidecar) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find(img.id) {
            Ok(i) => assert_eq!(img.id, i.id),
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find_image_file(img.id) {
            Ok(_) => (),
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find_sidecar_file(img.id) {
            Ok(_) => (),
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
    }
}
<commit_msg>Add find sidecar file test<commit_after>use std::error::Error;
use diesel::prelude::*;
use schema::{images, tags, images_tags, images_collections, collections};
use schema::images::dsl::*;
use super::super::models::{ImagesTag, NewImagesTag, Tag, Image, NewImage, Collection,
                           ImagesCollection};
use super::super::db_manager;
use super::super::diesel;
use super::file_storage;
use std::fs::File;

pub fn create(new_image: &NewImage) -> Result<Image, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result: Image = try!(diesel::insert(new_image)
                                 .into(images::table)
                                 .get_result(conn));
    Ok(result)
}

pub fn create_image_file(image_id: i32, data: &[u8]) -> Result<Image, Box<Error>> {
    let img = try!(find(image_id));
    try!(file_storage::store_image(img.id, data));
    Ok(img)
}

pub fn create_sidecar_file(image_id: i32, sidecar: &[u8]) -> Result<Image, Box<Error>> {
    let img = try!(find(image_id));
    try!(file_storage::store_sidecar_file(img.id, sidecar));
    Ok(img)
}

pub fn get_all() -> Result<Vec<Image>, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(images.load(conn));
    Ok(result)
}

pub fn find(image_id: i32) -> Result<Image, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    Ok(img)
}

pub fn find_image_file(image_id: i32) -> Result<File, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    let data = try!(file_storage::load_image(img.id));
    Ok(data)
}

pub fn find_sidecar_file(image_id: i32) -> Result<File, Box<Error>> {
    use schema::images::dsl::*;
    let ref conn = *try!(db_manager::POOL.get());
    let img: Image = try!(images.find(image_id).first(conn));
    let data = try!(file_storage::load_sidecar_file(img.id));
    Ok(data)
}

pub fn find_range(size: i64, offset: i64) -> Result<Vec<Image>, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(images.limit(size).offset(offset).load(conn));
    Ok(result)
}

pub fn update(image: &Image) -> Result<Image, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let result = try!(diesel::update(images.find(image.id))
                          .set((title.eq(image.title.clone()),
                                description.eq(image.description.clone()),
                                license.eq(image.license.clone()),
                                side_car_file.eq(image.side_car_file.clone()),
                                raw_image_id.eq(image.raw_image_id.clone())))
                          .get_result(conn));
    Ok(result)
}

pub fn add_tag_to_image(image: &Image, tag: &Tag) -> Result<ImagesTag, Box<Error>> {
    let ref conn = *try!(db_manager::POOL.get());
    let new_image_tag = NewImagesTag {
        image_id: image.id,
        tag_id: tag.id,
    };
    let result = try!(diesel::insert(&new_image_tag)
                          .into(images_tags::table)
                          .get_result(conn));
    Ok(result)
}

pub fn get_tags_of_image(image: &Image) -> Result<Vec<Tag>, Box<Error>> {
    use diesel::pg::expression::dsl::any;
    let ref conn = *try!(db_manager::POOL.get());
    let image_tag_ids = ImagesTag::belonging_to(image).select(images_tags::tag_id);
    Ok(try!(tags::table
                .filter(tags::id.eq(any(image_tag_ids)))
                .load::<Tag>(conn)))
}

pub fn get_collections_of_image(image: &Image) -> Result<Vec<Collection>, Box<Error>> {
    use diesel::pg::expression::dsl::any;
    let ref conn = *try!(db_manager::POOL.get());
    let image_collection_ids = ImagesCollection::belonging_to(image)
        .select(images_collections::collection_id);
    Ok(try!(collections::table
                .filter(collections::id.eq(any(image_collection_ids)))
                .load::<Collection>(conn)))
}

#[cfg(test)]
mod tests {
    use super::*;
    use models::NewRawImage;
    use super::super::raw_image_service;
    use diesel::pg::data_types::PgDate;
    use std::fs::File;
    use std::io;
    use std::io::prelude::*;

    #[test]
    fn test_create() {
        // create raw image
        let image = b"Hello, wurst!";
        let raw_img = NewRawImage {
            user_id: 999,
            camera: "megapixelzoom".to_string(),
            latitude: 0.22,
            longitude: 0.32,
        };
        let raw = match raw_image_service::create(&raw_img) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        // do the test
        let image = b"Hello, wurst image!";
        let sidecar = b"I am a sidecar file!";
        let test_img = NewImage {
            title: "test image".to_string(),
            description: "desc of test image".to_string(),
            license: "MIT".to_string(),
            side_car_file: "carly".to_string(),
            raw_image_id: raw.id,
        };
        let img = match create(&test_img) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        let img = match create_image_file(img.id, image) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        let img = match create_sidecar_file(img.id, sidecar) {
            Ok(i) => i,
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find(img.id) {
            Ok(i) => assert_eq!(img.id, i.id),
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find_image_file(img.id) {
            Ok(_) => (),
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
        match find_sidecar_file(img.id) {
            Ok(sf) => {
                let mut test = sf;
                let mut bytes = vec![];
                match test.read_to_end(&mut bytes) {
                    Ok(b) => b,
                    Err(x) => {
                        println!("err: {}", x);
                        panic!();
                    }
                };
                assert_eq!(sidecar, bytes.as_slice())
            }
            Err(x) => {
                println!("err: {}", x);
                panic!();
            }
        };
    }
}
<|endoftext|>


<commit_before>use std::net::{UdpSocket,SocketAddr};
use std::io::{self,Write,Error,ErrorKind};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::str;

use network::buffer::Buffer;

lazy_static! {
  pub static ref METRICS: Mutex<ProxyMetrics> = Mutex::new(ProxyMetrics::new(String::from("sozu")));
}

pub struct ProxyMetrics {
  buffer: Buffer,
  prefix: String,
  remote: Option<(SocketAddr, UdpSocket)>,
}

impl ProxyMetrics {
  pub fn new(prefix: String) -> Self {
    ProxyMetrics {
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote:   None,
    }
  }

  pub fn run() -> thread::JoinHandle<()> {
    thread::spawn(move || {
      loop {
        thread::sleep(Duration::from_millis(500));
        METRICS.lock().unwrap().send();
      }
    })
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.remote = Some((addr, socket));
  }

  pub fn send(&mut self) -> io::Result<usize> {
    if self.buffer.available_data() > 0 {
      if let Some((ref addr, ref socket)) = self.remote {
        match socket.send_to(self.buffer.data(), addr) {
          Ok(sz) => {
            self.buffer.consume(sz);
            Ok(sz)
          },
          Err(e) => {
            Err(e)
          }
        }
      } else {
        Err(Error::new(ErrorKind::NotConnected, "metrics socket not set up"))
      }
    } else {
      Err(Error::new(ErrorKind::Other, "no data to send"))
    }
  }

  fn emit(&mut self, metric: &str) -> io::Result<usize> {
    self.buffer.write(metric.as_bytes())
  }

  pub fn count(&mut self, key: &str, count: i64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|c\n", &self.prefix, key, count))
  }

  pub fn incr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, 1)
  }

  pub fn decr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, -1)
  }

  pub fn time(&mut self, key: &str, time: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|ms\n", self.prefix, key, time))
  }

  pub fn gauge(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|g\n", self.prefix, key, value))
  }

  pub fn meter(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|m\n", self.prefix, key, value))
  }
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().count($key, $value);)
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().incr($key);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().decr($key);)
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().time($key, $value);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().gauge($key, $value);)
);

#[macro_export]
macro_rules! meter (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().meter($key, $value);)
);
<commit_msg>move metrics formatting and sending to macros<commit_after>use std::net::{UdpSocket,SocketAddr};
use std::io::{self,Write,Error,ErrorKind};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::str;

use network::buffer::Buffer;

lazy_static! {
  pub static ref METRICS: Mutex<ProxyMetrics> = Mutex::new(ProxyMetrics::new(String::from("sozu")));
}

pub struct ProxyMetrics {
  pub buffer: Buffer,
  pub prefix: String,
  remote: Option<(SocketAddr, UdpSocket)>,
}

impl ProxyMetrics {
  pub fn new(prefix: String) -> Self {
    ProxyMetrics {
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote:   None,
    }
  }

  pub fn run() -> thread::JoinHandle<()> {
    thread::spawn(move || {
      loop {
        thread::sleep(Duration::from_millis(500));
        METRICS.lock().unwrap().send();
      }
    })
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.remote = Some((addr, socket));
  }

  pub fn send(&mut self) -> io::Result<usize> {
    if self.buffer.available_data() >= 512 {
      if let Some((ref addr, ref socket)) = self.remote {
        match socket.send_to(self.buffer.data(), addr) {
          Ok(sz) => {
            self.buffer.consume(sz);
            Ok(sz)
          },
          Err(e) => {
            Err(e)
          }
        }
      } else {
        Err(Error::new(ErrorKind::NotConnected, "metrics socket not set up"))
      }
    } else {
      Err(Error::new(ErrorKind::Other, "no data to send"))
    }
  }

  fn emit(&mut self, metric: &str) -> io::Result<usize> {
    self.buffer.write(metric.as_bytes())
  }

  pub fn count(&mut self, key: &str, count: i64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|c\n", &self.prefix, key, count))
  }

  pub fn incr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, 1)
  }

  pub fn decr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, -1)
  }

  pub fn time(&mut self, key: &str, time: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|ms\n", self.prefix, key, time))
  }

  pub fn gauge(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|g\n", self.prefix, key, value))
  }

  pub fn meter(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|m\n", self.prefix, key, value))
  }
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => {
    let mut metrics = ::network::metrics::METRICS.lock().unwrap();
    metrics.buffer.write_fmt(format_args!("{}.{}:{}|c\n", *$crate::logging::TAG, $key, $value));
    metrics.send();
  }
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (count!($key, 1);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (count!($key, -1);)
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => {
    let mut metrics = ::network::metrics::METRICS.lock().unwrap();
    metrics.buffer.write_fmt(format_args!("{}.{}:{}|ms\n", *$crate::logging::TAG, $key, $value));
    metrics.send();
  }
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => {
    let mut metrics = ::network::metrics::METRICS.lock().unwrap();
    metrics.buffer.write_fmt(format_args!("{}.{}:{}|g\n", *$crate::logging::TAG, $key, $value));
    metrics.send();
  }
);

#[macro_export]
macro_rules! meter (
  ($key:expr, $value: expr) =>  {
    let mut metrics = ::network::metrics::METRICS.lock().unwrap();
    metrics.buffer.write_fmt(format_args!("{}.{}:{}|m\n", *$crate::logging::TAG, $key, $value));
    metrics.send();
  }
);
<|endoftext|>


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

use dom::bindings::codegen::Bindings::BlobBinding;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::trace::JSTraceable;
use num::ToPrimitive;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::cmp::{max, min};
use std::sync::Arc;
use util::str::DOMString;

#[derive(Clone, JSTraceable)]
pub struct DataSlice {
    bytes: Arc<Vec<u8>>,
    bytes_start: usize,
    bytes_end: usize
}

impl DataSlice {
    pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
        let size = bytes.len() as i64;
        let relativeStart: i64 = match start {
            None => 0,
            Some(start) => {
                if start < 0 {
                    max(size + start, 0)
                } else {
                    min(start, size)
                }
            }
        };
        let relativeEnd: i64 = match end {
            None => size,
            Some(end) => {
                if end < 0 {
                    max(size + end, 0)
                } else {
                    min(end, size)
                }
            }
        };

        let span: i64 = max(relativeEnd - relativeStart, 0);
        let start = relativeStart.to_usize().unwrap();
        let end = (relativeStart + span).to_usize().unwrap();

        DataSlice {
            bytes: bytes,
            bytes_start: start,
            bytes_end: end
        }
    }

    pub fn get_bytes(&self) -> &[u8] {
        &self.bytes[self.bytes_start..self.bytes_end]
    }

    pub fn size(&self) -> u64 {
        (self.bytes_end as u64) - (self.bytes_start as u64)
    }
}

// https://w3c.github.io/FileAPI/#blob
#[dom_struct]
pub struct Blob {
    reflector_: Reflector,
    #[ignore_heap_size_of = "No clear owner"]
    data: DataSlice,
    typeString: String,
    isClosed_: Cell<bool>,
}

fn is_ascii_printable(string: &str) -> bool {
    // Step 5.1 in Sec 5.1 of File API spec
    // https://w3c.github.io/FileAPI/#constructorBlob
    string.chars().all(|c| c >= '\x20' && c <= '\x7E')
}

impl Blob {
    pub fn new_inherited(bytes: Arc<Vec<u8>>,
                         bytes_start: Option<i64>,
                         bytes_end: Option<i64>,
                         typeString: &str) -> Blob {
        Blob {
            reflector_: Reflector::new(),
            data: DataSlice::new(bytes, bytes_start, bytes_end),
            typeString: typeString.to_owned(),
            isClosed_: Cell::new(false),
        }
    }

    pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> {
        let boxed_blob = box Blob::new_inherited(Arc::new(bytes), None, None, typeString);
        reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    fn new_sliced(global: GlobalRef,
                  bytes: Arc<Vec<u8>>,
                  bytes_start: Option<i64>,
                  bytes_end: Option<i64>,
                  typeString: &str) -> Root<Blob> {

      let boxed_blob = box Blob::new_inherited(bytes, bytes_start, bytes_end, typeString);
      reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor(global: GlobalRef) -> Fallible<Root<Blob>> {
        Ok(Blob::new(global, Vec::new(), ""))
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor_(global: GlobalRef,
                        blobParts: DOMString,
                        blobPropertyBag: &BlobBinding::BlobPropertyBag)
                        -> Fallible<Root<Blob>> {
        // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob
        // FIXME(ajeffrey): convert directly from a DOMString to a Vec<u8>
        let bytes: Vec<u8> = String::from(blobParts).into_bytes();
        let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
            &*blobPropertyBag.type_
        } else {
            ""
        };
        Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase()))
    }

    pub fn get_data(&self) -> &DataSlice {
        &self.data
    }
}

impl BlobMethods for Blob {
    // https://w3c.github.io/FileAPI/#dfn-size
    fn Size(&self) -> u64 {
        self.data.size()
    }

    // https://w3c.github.io/FileAPI/#dfn-type
    fn Type(&self) -> DOMString {
        DOMString::from(self.typeString.clone())
    }

    // https://w3c.github.io/FileAPI/#slice-method-algo
    fn Slice(&self,
             start: Option<i64>,
             end: Option<i64>,
             contentType: Option<DOMString>)
             -> Root<Blob> {

        let relativeContentType = match contentType {
            None => DOMString::new(),
            Some(mut str) => {
                if is_ascii_printable(&str) {
                    str.make_ascii_lowercase();
                    str
                } else {
                    DOMString::new()
                }
            }
        };
        let global = self.global();
        let bytes = self.data.bytes.clone();
        Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType)
    }

    // https://w3c.github.io/FileAPI/#dfn-isClosed
    fn IsClosed(&self) -> bool {
        self.isClosed_.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-close
    fn Close(&self) {
        // Step 1
        if self.isClosed_.get() {
            return;
        }

        // Step 2
        self.isClosed_.set(true);

        // TODO Step 3 if Blob URL Store is implemented

    }
}
<commit_msg>Auto merge of #9967 - saurvs:master, r=Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::BlobBinding;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::trace::JSTraceable;
use num::ToPrimitive;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::cmp::{max, min};
use std::sync::Arc;
use util::str::DOMString;

#[derive(Clone, JSTraceable)]
pub struct DataSlice {
    bytes: Arc<Vec<u8>>,
    bytes_start: usize,
    bytes_end: usize
}

impl DataSlice {
    pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
        let size = bytes.len() as i64;
        let relativeStart: i64 = match start {
            None => 0,
            Some(start) => {
                if start < 0 {
                    max(size + start, 0)
                } else {
                    min(start, size)
                }
            }
        };
        let relativeEnd: i64 = match end {
            None => size,
            Some(end) => {
                if end < 0 {
                    max(size + end, 0)
                } else {
                    min(end, size)
                }
            }
        };

        let span: i64 = max(relativeEnd - relativeStart, 0);
        let start = relativeStart.to_usize().unwrap();
        let end = (relativeStart + span).to_usize().unwrap();

        DataSlice {
            bytes: bytes,
            bytes_start: start,
            bytes_end: end
        }
    }

    pub fn get_bytes(&self) -> &[u8] {
        &self.bytes[self.bytes_start..self.bytes_end]
    }

    pub fn size(&self) -> u64 {
        (self.bytes_end as u64) - (self.bytes_start as u64)
    }
}

// https://w3c.github.io/FileAPI/#blob
#[dom_struct]
pub struct Blob {
    reflector_: Reflector,
    #[ignore_heap_size_of = "No clear owner"]
    data: DataSlice,
    typeString: String,
    isClosed_: Cell<bool>,
}

fn is_ascii_printable(string: &str) -> bool {
    // Step 5.1 in Sec 5.1 of File API spec
    // https://w3c.github.io/FileAPI/#constructorBlob
    string.chars().all(|c| c >= '\x20' && c <= '\x7E')
}

impl Blob {
    pub fn new_inherited(bytes: Arc<Vec<u8>>,
                         bytes_start: Option<i64>,
                         bytes_end: Option<i64>,
                         typeString: &str) -> Blob {
        Blob {
            reflector_: Reflector::new(),
            data: DataSlice::new(bytes, bytes_start, bytes_end),
            typeString: typeString.to_owned(),
            isClosed_: Cell::new(false),
        }
    }

    pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> {
        let boxed_blob = box Blob::new_inherited(Arc::new(bytes), None, None, typeString);
        reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    fn new_sliced(global: GlobalRef,
                  bytes: Arc<Vec<u8>>,
                  bytes_start: Option<i64>,
                  bytes_end: Option<i64>,
                  typeString: &str) -> Root<Blob> {

      let boxed_blob = box Blob::new_inherited(bytes, bytes_start, bytes_end, typeString);
      reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor(global: GlobalRef) -> Fallible<Root<Blob>> {
        Ok(Blob::new(global, Vec::new(), ""))
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor_(global: GlobalRef,
                        blobParts: DOMString,
                        blobPropertyBag: &BlobBinding::BlobPropertyBag)
                        -> Fallible<Root<Blob>> {
        // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob
        let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
            &*blobPropertyBag.type_
        } else {
            ""
        };
        Ok(Blob::new(global, blobParts.into(), &typeString.to_ascii_lowercase()))
    }

    pub fn get_data(&self) -> &DataSlice {
        &self.data
    }
}

impl BlobMethods for Blob {
    // https://w3c.github.io/FileAPI/#dfn-size
    fn Size(&self) -> u64 {
        self.data.size()
    }

    // https://w3c.github.io/FileAPI/#dfn-type
    fn Type(&self) -> DOMString {
        DOMString::from(self.typeString.clone())
    }

    // https://w3c.github.io/FileAPI/#slice-method-algo
    fn Slice(&self,
             start: Option<i64>,
             end: Option<i64>,
             contentType: Option<DOMString>)
             -> Root<Blob> {

        let relativeContentType = match contentType {
            None => DOMString::new(),
            Some(mut str) => {
                if is_ascii_printable(&str) {
                    str.make_ascii_lowercase();
                    str
                } else {
                    DOMString::new()
                }
            }
        };
        let global = self.global();
        let bytes = self.data.bytes.clone();
        Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType)
    }

    // https://w3c.github.io/FileAPI/#dfn-isClosed
    fn IsClosed(&self) -> bool {
        self.isClosed_.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-close
    fn Close(&self) {
        // Step 1
        if self.isClosed_.get() {
            return;
        }

        // Step 2
        self.isClosed_.set(true);

        // TODO Step 3 if Blob URL Store is implemented

    }
}
<|endoftext|>