<commit_before>#[test]
fn simple() {
    assert_eq!(4, 4);
}

// A test that won't work on miri (tests disabling tests).
#[test]
#[cfg_attr(miri, ignore)]
fn does_not_work_on_miri() {
    unsafe { std::arch::asm!("") };
}

// Make sure integration tests can access both dependencies and dev-dependencies
#[test]
fn deps() {
    {
        use byteorder::{BigEndian, ByteOrder};
        let _n = <BigEndian as ByteOrder>::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]);
    }
    {
        use byteorder_2::{BigEndian, ByteOrder};
        let _n = <BigEndian as ByteOrder>::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]);
    }
}

#[test]
fn cargo_env() {
    assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test");
    env!("CARGO_BIN_EXE_cargo-miri-test"); // Asserts that this exists.
}

#[test]
#[should_panic(expected = "Explicit panic")]
fn do_panic() // In large, friendly letters :)
{
    panic!("Explicit panic from test!");
}

// A different way of raising a panic
#[test]
#[allow(unconditional_panic)]
#[should_panic(expected = "the len is 0 but the index is 42")]
fn fail_index_check() {
    [][42]
}
<commit_msg>aarch inline asm is not stable yet<commit_after>#[test]
fn simple() {
    assert_eq!(4, 4);
}

// A test that won't work on miri (tests disabling tests).
#[test]
#[cfg_attr(miri, ignore)]
fn does_not_work_on_miri() {
    // Only do this where inline assembly is stable.
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    unsafe {
        std::arch::asm!("foo");
    }
}

// Make sure integration tests can access both dependencies and dev-dependencies
#[test]
fn deps() {
    {
        use byteorder::{BigEndian, ByteOrder};
        let _n = <BigEndian as ByteOrder>::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]);
    }
    {
        use byteorder_2::{BigEndian, ByteOrder};
        let _n = <BigEndian as ByteOrder>::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]);
    }
}

#[test]
fn cargo_env() {
    assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test");
    env!("CARGO_BIN_EXE_cargo-miri-test"); // Asserts that this exists.
}

#[test]
#[should_panic(expected = "Explicit panic")]
fn do_panic() // In large, friendly letters :)
{
    panic!("Explicit panic from test!");
}

// A different way of raising a panic
#[test]
#[allow(unconditional_panic)]
#[should_panic(expected = "the len is 0 but the index is 42")]
fn fail_index_check() {
    [][42]
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::iter::successors;
use syntax::{
    algo::neighbor,
    ast::{self, AstNode},
    Direction,
};

use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};

// Assist: merge_match_arms
//
// Merges the current match arm with the following if their bodies are identical.
//
// ```
// enum Action { Move { distance: u32 }, Stop }
//
// fn handle(action: Action) {
//     match action {
//         $0Action::Move(..) => foo(),
//         Action::Stop => foo(),
//     }
// }
// ```
// ->
// ```
// enum Action { Move { distance: u32 }, Stop }
//
// fn handle(action: Action) {
//     match action {
//         Action::Move(..) | Action::Stop => foo(),
//     }
// }
// ```
pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
    // Don't try to handle arms with guards for now - can add support for this later
    if current_arm.guard().is_some() {
        return None;
    }
    let current_expr = current_arm.expr()?;
    let current_text_range = current_arm.syntax().text_range();
    let current_arm_types = get_arm_types(&ctx, &current_arm);

    // We check if the following match arms match this one. We could, but don't,
    // compare to the previous match arm as well.
    let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next))
        .take_while(|arm| match arm.expr() {
            Some(expr) if arm.guard().is_none() => {
                let same_text = expr.syntax().text() == current_expr.syntax().text();
                if !same_text {
                    return false;
                }

                return are_same_types(&current_arm_types, arm, ctx);
            }
            _ => false,
        })
        .collect::<Vec<_>>();

    if arms_to_merge.len() <= 1 {
        return None;
    }

    acc.add(
        AssistId("merge_match_arms", AssistKind::RefactorRewrite),
        "Merge match arms",
        current_text_range,
        |edit| {
            let pats = if arms_to_merge.iter().any(contains_placeholder) {
                "_".into()
            } else {
                arms_to_merge
                    .iter()
                    .filter_map(ast::MatchArm::pat)
                    .map(|x| x.syntax().to_string())
                    .collect::<Vec<String>>()
                    .join(" | ")
            };

            let arm = format!("{} => {},", pats, current_expr.syntax().text());

            if let [first, .., last] = &*arms_to_merge {
                let start = first.syntax().text_range().start();
                let end = last.syntax().text_range().end();

                edit.replace(TextRange::new(start, end), arm);
            }
        },
    )
}

fn contains_placeholder(a: &ast::MatchArm) -> bool {
    matches!(a.pat(), Some(ast::Pat::WildcardPat(..)))
}

fn are_same_types(
    current_arm_types: &Vec<Option<hir::TypeInfo>>,
    arm: &ast::MatchArm,
    ctx: &AssistContext,
) -> bool {
    let arm_types = get_arm_types(&ctx, &arm);
    for i in 0..arm_types.len() {
        let other_arm_type = &arm_types[i];
        let current_arm_type = &current_arm_types[i];
        if let (Some(other_arm_type), Some(current_arm_type)) = (other_arm_type, current_arm_type) {
            return &other_arm_type.original == &current_arm_type.original;
        }
    }

    return true;
}

fn get_arm_types(ctx: &AssistContext, arm: &ast::MatchArm) -> Vec<Option<hir::TypeInfo>> {
    match arm.pat() {
        Some(ast::Pat::TupleStructPat(tp)) => {
            tp.fields().into_iter().map(|field| ctx.sema.type_of_pat(&field)).collect_vec()
        }
        _ => Vec::new(),
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn merge_match_arms_single_patterns() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32$0 }
        X::B => { 1i32 }
        X::C => { 2i32 }
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B => { 1i32 },
        X::C => { 2i32 }
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_multiple_patterns() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B => {$0 1i32 },
        X::C | X::D => { 1i32 },
        X::E => { 2i32 },
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B | X::C | X::D => { 1i32 },
        X::E => { 2i32 },
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_placeholder_pattern() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32 },
        X::B => { 2i$032 },
        _ => { 2i32 }
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32 },
        _ => { 2i32 },
    }
}
"#,
        );
    }

    #[test]
    fn merges_all_subsequent_arms() {
        check_assist(
            merge_match_arms,
            r#"
enum X { A, B, C, D, E }

fn main() {
    match X::A {
        X::A$0 => 92,
        X::B => 92,
        X::C => 92,
        X::D => 62,
        _ => panic!(),
    }
}
"#,
            r#"
enum X { A, B, C, D, E }

fn main() {
    match X::A {
        X::A | X::B | X::C => 92,
        X::D => 62,
        _ => panic!(),
    }
}
"#,
        )
    }

    #[test]
    fn merge_match_arms_rejects_guards() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X {
    A(i32),
    B,
    C
}

fn main() {
    let x = X::A;
    let y = match x {
        X::A(a) if a > 5 => { $01i32 },
        X::B => { 1i32 },
        X::C => { 2i32 }
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_different_type() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<f64, f32>::Ok(0f64) {
        Ok(x) => $0x.classify(),
        Err(x) => x.classify()
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_different_type_multiple_fields() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64), (f32, f32)>::Ok((0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_multiple_fields() {
        check_assist(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64), (f64, f64)>::Ok((0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
            r#"
fn func() {
    match Result::<(f64, f64), (f64, f64)>::Ok((0f64, 0f64)) {
        Ok(x) | Err(x) => x.1.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_subsequent_arm_with_different_type_in_other() {
        check_assist(
            merge_match_arms,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f32),
    OptionC(f64)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) => $0x.classify(),
        MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f32),
    OptionC(f64)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) | MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_skip_arm_with_different_type_in_between() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f64),
    OptionC(f32)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) => $0x.classify(),
        MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_different_number_of_fields() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64), (f64)>::Ok((0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
        );
    }
}
<commit_msg>fixed test case<commit_after>use itertools::Itertools;
use std::iter::successors;
use syntax::{
    algo::neighbor,
    ast::{self, AstNode},
    Direction,
};

use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};

// Assist: merge_match_arms
//
// Merges the current match arm with the following if their bodies are identical.
//
// ```
// enum Action { Move { distance: u32 }, Stop }
//
// fn handle(action: Action) {
//     match action {
//         $0Action::Move(..) => foo(),
//         Action::Stop => foo(),
//     }
// }
// ```
// ->
// ```
// enum Action { Move { distance: u32 }, Stop }
//
// fn handle(action: Action) {
//     match action {
//         Action::Move(..) | Action::Stop => foo(),
//     }
// }
// ```
pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
    // Don't try to handle arms with guards for now - can add support for this later
    if current_arm.guard().is_some() {
        return None;
    }
    let current_expr = current_arm.expr()?;
    let current_text_range = current_arm.syntax().text_range();
    let current_arm_types = get_arm_types(&ctx, &current_arm);

    // We check if the following match arms match this one. We could, but don't,
    // compare to the previous match arm as well.
    let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next))
        .take_while(|arm| match arm.expr() {
            Some(expr) if arm.guard().is_none() => {
                let same_text = expr.syntax().text() == current_expr.syntax().text();
                if !same_text {
                    return false;
                }

                return are_same_types(&current_arm_types, arm, ctx);
            }
            _ => false,
        })
        .collect::<Vec<_>>();

    if arms_to_merge.len() <= 1 {
        return None;
    }

    acc.add(
        AssistId("merge_match_arms", AssistKind::RefactorRewrite),
        "Merge match arms",
        current_text_range,
        |edit| {
            let pats = if arms_to_merge.iter().any(contains_placeholder) {
                "_".into()
            } else {
                arms_to_merge
                    .iter()
                    .filter_map(ast::MatchArm::pat)
                    .map(|x| x.syntax().to_string())
                    .collect::<Vec<String>>()
                    .join(" | ")
            };

            let arm = format!("{} => {},", pats, current_expr.syntax().text());

            if let [first, .., last] = &*arms_to_merge {
                let start = first.syntax().text_range().start();
                let end = last.syntax().text_range().end();

                edit.replace(TextRange::new(start, end), arm);
            }
        },
    )
}

fn contains_placeholder(a: &ast::MatchArm) -> bool {
    matches!(a.pat(), Some(ast::Pat::WildcardPat(..)))
}

fn are_same_types(
    current_arm_types: &Vec<Option<hir::TypeInfo>>,
    arm: &ast::MatchArm,
    ctx: &AssistContext,
) -> bool {
    let arm_types = get_arm_types(&ctx, &arm);
    for i in 0..arm_types.len() {
        let other_arm_type = &arm_types[i];
        let current_arm_type = &current_arm_types[i];
        if let (Some(other_arm_type), Some(current_arm_type)) = (other_arm_type, current_arm_type) {
            return &other_arm_type.original == &current_arm_type.original;
        }
    }

    return true;
}

fn get_arm_types(ctx: &AssistContext, arm: &ast::MatchArm) -> Vec<Option<hir::TypeInfo>> {
    match arm.pat() {
        Some(ast::Pat::TupleStructPat(tp)) => {
            tp.fields().into_iter().map(|field| ctx.sema.type_of_pat(&field)).collect_vec()
        }
        _ => Vec::new(),
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn merge_match_arms_single_patterns() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32$0 }
        X::B => { 1i32 }
        X::C => { 2i32 }
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B => { 1i32 },
        X::C => { 2i32 }
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_multiple_patterns() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B => {$0 1i32 },
        X::C | X::D => { 1i32 },
        X::E => { 2i32 },
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A | X::B | X::C | X::D => { 1i32 },
        X::E => { 2i32 },
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_placeholder_pattern() {
        check_assist(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32 },
        X::B => { 2i$032 },
        _ => { 2i32 }
    }
}
"#,
            r#"
#[derive(Debug)]
enum X { A, B, C, D, E }

fn main() {
    let x = X::A;
    let y = match x {
        X::A => { 1i32 },
        _ => { 2i32 },
    }
}
"#,
        );
    }

    #[test]
    fn merges_all_subsequent_arms() {
        check_assist(
            merge_match_arms,
            r#"
enum X { A, B, C, D, E }

fn main() {
    match X::A {
        X::A$0 => 92,
        X::B => 92,
        X::C => 92,
        X::D => 62,
        _ => panic!(),
    }
}
"#,
            r#"
enum X { A, B, C, D, E }

fn main() {
    match X::A {
        X::A | X::B | X::C => 92,
        X::D => 62,
        _ => panic!(),
    }
}
"#,
        )
    }

    #[test]
    fn merge_match_arms_rejects_guards() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"
#[derive(Debug)]
enum X {
    A(i32),
    B,
    C
}

fn main() {
    let x = X::A;
    let y = match x {
        X::A(a) if a > 5 => { $01i32 },
        X::B => { 1i32 },
        X::C => { 2i32 }
    }
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_different_type() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<f64, f32>::Ok(0f64) {
        Ok(x) => $0x.classify(),
        Err(x) => x.classify()
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_different_type_multiple_fields() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64), (f32, f32)>::Ok((0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_multiple_fields() {
        check_assist(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64), (f64, f64)>::Ok((0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
            r#"
fn func() {
    match Result::<(f64, f64), (f64, f64)>::Ok((0f64, 0f64)) {
        Ok(x) | Err(x) => x.1.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_subsequent_arm_with_different_type_in_other() {
        check_assist(
            merge_match_arms,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f32),
    OptionC(f64)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) => $0x.classify(),
        MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f32),
    OptionC(f64)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) | MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_skip_arm_with_different_type_in_between() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"
enum MyEnum {
    OptionA(f32),
    OptionB(f64),
    OptionC(f32)
}

fn func(e: MyEnum) {
    match e {
        MyEnum::OptionA(x) => $0x.classify(),
        MyEnum::OptionB(x) => x.classify(),
        MyEnum::OptionC(x) => x.classify(),
    };
}
"#,
        );
    }

    #[test]
    fn merge_match_arms_same_type_different_number_of_fields() {
        check_assist_not_applicable(
            merge_match_arms,
            r#"//- minicore: result
fn func() {
    match Result::<(f64, f64, f64), (f64, f64)>::Ok((0f64, 0f64, 0f64)) {
        Ok(x) => $0x.1.classify(),
        Err(x) => x.1.classify()
    };
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>//! Validity checking for weak lang items

use crate::session::config;
use crate::middle::lang_items;

use rustc_data_structures::fx::FxHashSet;
use rustc_target::spec::PanicStrategy;
use syntax::ast;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
use crate::hir::def_id::DefId;
use crate::hir::intravisit::{Visitor, NestedVisitorMap};
use crate::hir::intravisit;
use crate::hir;
use crate::ty::TyCtxt;

macro_rules! weak_lang_items {
    ($($name:ident, $item:ident, $sym:ident;)*) => (

struct Context<'a, 'tcx> {
    tcx: TyCtxt<'tcx>,
    items: &'a mut lang_items::LanguageItems,
}

/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>,
                             items: &mut lang_items::LanguageItems) {
    // These are never called by user code, they're generated by the compiler.
    // They will never implicitly be added to the `missing` array unless we do
    // so here.
    if items.eh_personality().is_none() {
        items.missing.push(lang_items::EhPersonalityLangItem);
    }
    if tcx.sess.target.target.options.custom_unwind_resume &
       items.eh_unwind_resume().is_none() {
        items.missing.push(lang_items::EhUnwindResumeLangItem);
    }

    {
        let mut cx = Context { tcx, items };
        tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor());
    }
    verify(tcx, items);
}

pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
    lang_items::extract(attrs).and_then(|(name, _)| {
        $(if name == sym::$name {
            Some(sym::$sym)
        } else)* {
            None
        }
    })
}

/// Returns `true` if the specified `lang_item` doesn't actually need to be
/// present for this compilation.
///
/// Not all lang items are always required for each compilation, particularly in
/// the case of panic=abort. In these situations some lang items are injected by
/// crates and don't actually need to be defined in libstd.
pub fn whitelisted(tcx: TyCtxt<'_>, lang_item: lang_items::LangItem) -> bool {
    // If we're not compiling with unwinding, we won't actually need these
    // symbols. Other panic runtimes ensure that the relevant symbols are
    // available to link things together, but they're never exercised.
    if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
        return lang_item == lang_items::EhPersonalityLangItem ||
            lang_item == lang_items::EhUnwindResumeLangItem
    }

    false
}

fn verify<'tcx>(tcx: TyCtxt<'tcx>,
                    items: &lang_items::LanguageItems) {
    // We only need to check for the presence of weak lang items if we're
    // emitting something that's not an rlib.
    let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| {
        match *kind {
            config::CrateType::Dylib |
            config::CrateType::ProcMacro |
            config::CrateType::Cdylib |
            config::CrateType::Executable |
            config::CrateType::Staticlib => true,
            config::CrateType::Rlib => false,
        }
    });
    if !needs_check {
        return
    }

    let mut missing = FxHashSet::default();
    for &cnum in tcx.crates().iter() {
        for &item in tcx.missing_lang_items(cnum).iter() {
            missing.insert(item);
        }
    }

    $(
        if missing.contains(&lang_items::$item) &&
           !whitelisted(tcx, lang_items::$item) &&
           items.$name().is_none() {
            if lang_items::$item == lang_items::PanicImplLangItem {
                tcx.sess.err(&format!("`#[panic_handler]` function required, \
                                       but not found"));
            } else if lang_items::$item == lang_items::OomLangItem {
                tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
                                       but not found"));
            } else {
                tcx.sess.err(&format!("language item required, but not found: `{}`",
                                      stringify!($name)));
            }
        }
    )*
}

impl<'a, 'tcx> Context<'a, 'tcx> {
    fn register(&mut self, name: &str, span: Span) {
        $(if name == stringify!($name) {
            if self.items.$name().is_none() {
                self.items.missing.push(lang_items::$item);
            }
        } else)* {
            span_err!(self.tcx.sess, span, E0264,
                      "unknown external lang item: `{}`",
                      name);
        }
    }
}

impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
        NestedVisitorMap::None
    }

    fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
        if let Some((lang_item, _)) = lang_items::extract(&i.attrs) {
            self.register(&lang_item.as_str(), i.span);
        }
        intravisit::walk_foreign_item(self, i)
    }
}

impl<'tcx> TyCtxt<'tcx> {
    pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
        let lang_items = self.lang_items();
        let did = Some(item_def_id);

        $(lang_items.$name() == did)||*
    }
}

) }

weak_lang_items! {
    panic_impl,         PanicImplLangItem,          rust_begin_unwind;
    eh_personality,     EhPersonalityLangItem,      rust_eh_personality;
    eh_unwind_resume,   EhUnwindResumeLangItem,     rust_eh_unwind_resume;
    oom,                OomLangItem,                rust_oom;
}
<commit_msg>Use `Symbol` in `weak_lang_items!`.<commit_after>//! Validity checking for weak lang items

use crate::session::config;
use crate::middle::lang_items;

use rustc_data_structures::fx::FxHashSet;
use rustc_target::spec::PanicStrategy;
use syntax::ast;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
use crate::hir::def_id::DefId;
use crate::hir::intravisit::{Visitor, NestedVisitorMap};
use crate::hir::intravisit;
use crate::hir;
use crate::ty::TyCtxt;

macro_rules! weak_lang_items {
    ($($name:ident, $item:ident, $sym:ident;)*) => (

struct Context<'a, 'tcx> {
    tcx: TyCtxt<'tcx>,
    items: &'a mut lang_items::LanguageItems,
}

/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>,
                             items: &mut lang_items::LanguageItems) {
    // These are never called by user code, they're generated by the compiler.
    // They will never implicitly be added to the `missing` array unless we do
    // so here.
    if items.eh_personality().is_none() {
        items.missing.push(lang_items::EhPersonalityLangItem);
    }
    if tcx.sess.target.target.options.custom_unwind_resume &
       items.eh_unwind_resume().is_none() {
        items.missing.push(lang_items::EhUnwindResumeLangItem);
    }

    {
        let mut cx = Context { tcx, items };
        tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor());
    }
    verify(tcx, items);
}

pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
    lang_items::extract(attrs).and_then(|(name, _)| {
        $(if name == sym::$name {
            Some(sym::$sym)
        } else)* {
            None
        }
    })
}

/// Returns `true` if the specified `lang_item` doesn't actually need to be
/// present for this compilation.
///
/// Not all lang items are always required for each compilation, particularly in
/// the case of panic=abort. In these situations some lang items are injected by
/// crates and don't actually need to be defined in libstd.
pub fn whitelisted(tcx: TyCtxt<'_>, lang_item: lang_items::LangItem) -> bool {
    // If we're not compiling with unwinding, we won't actually need these
    // symbols. Other panic runtimes ensure that the relevant symbols are
    // available to link things together, but they're never exercised.
    if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
        return lang_item == lang_items::EhPersonalityLangItem ||
            lang_item == lang_items::EhUnwindResumeLangItem
    }

    false
}

fn verify<'tcx>(tcx: TyCtxt<'tcx>,
                    items: &lang_items::LanguageItems) {
    // We only need to check for the presence of weak lang items if we're
    // emitting something that's not an rlib.
    let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| {
        match *kind {
            config::CrateType::Dylib |
            config::CrateType::ProcMacro |
            config::CrateType::Cdylib |
            config::CrateType::Executable |
            config::CrateType::Staticlib => true,
            config::CrateType::Rlib => false,
        }
    });
    if !needs_check {
        return
    }

    let mut missing = FxHashSet::default();
    for &cnum in tcx.crates().iter() {
        for &item in tcx.missing_lang_items(cnum).iter() {
            missing.insert(item);
        }
    }

    $(
        if missing.contains(&lang_items::$item) &&
           !whitelisted(tcx, lang_items::$item) &&
           items.$name().is_none() {
            if lang_items::$item == lang_items::PanicImplLangItem {
                tcx.sess.err(&format!("`#[panic_handler]` function required, \
                                       but not found"));
            } else if lang_items::$item == lang_items::OomLangItem {
                tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
                                       but not found"));
            } else {
                tcx.sess.err(&format!("language item required, but not found: `{}`",
                                      stringify!($name)));
            }
        }
    )*
}

impl<'a, 'tcx> Context<'a, 'tcx> {
    fn register(&mut self, name: Symbol, span: Span) {
        $(if name == sym::$name {
            if self.items.$name().is_none() {
                self.items.missing.push(lang_items::$item);
            }
        } else)* {
            span_err!(self.tcx.sess, span, E0264,
                      "unknown external lang item: `{}`",
                      name);
        }
    }
}

impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
        NestedVisitorMap::None
    }

    fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
        if let Some((lang_item, _)) = lang_items::extract(&i.attrs) {
            self.register(lang_item, i.span);
        }
        intravisit::walk_foreign_item(self, i)
    }
}

impl<'tcx> TyCtxt<'tcx> {
    pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
        let lang_items = self.lang_items();
        let did = Some(item_def_id);

        $(lang_items.$name() == did)||*
    }
}

) }

weak_lang_items! {
    panic_impl,         PanicImplLangItem,          rust_begin_unwind;
    eh_personality,     EhPersonalityLangItem,      rust_eh_personality;
    eh_unwind_resume,   EhUnwindResumeLangItem,     rust_eh_unwind_resume;
    oom,                OomLangItem,                rust_oom;
}
<|endoftext|>


<commit_before>use crate::blob::requests::GetBlobBuilder;
use azure_sdk_core::errors::AzureError;
use azure_sdk_core::lease::LeaseId;
use azure_sdk_core::range::Range;
use azure_sdk_core::{
    BlobNameRequired, BlobNameSupport, ClientRequestIdOption, ClientRequestIdSupport,
    ContainerNameRequired, ContainerNameSupport, LeaseIdOption, LeaseIdSupport, No, RangeRequired,
    RangeSupport, SnapshotOption, SnapshotSupport, TimeoutOption, TimeoutSupport, ToAssign, Yes,
};
use azure_sdk_storage_core::client::Client;
use azure_sdk_storage_core::ClientRequired;
use chrono::{DateTime, Utc};
use futures::stream::Stream;
use std::marker::PhantomData;

#[derive(Debug, Clone)]
pub struct BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    client: &'a Client,
    p_container_name: PhantomData<ContainerNameSet>,
    p_blob_name: PhantomData<BlobNameSet>,
    p_range: PhantomData<RangeSet>,
    container_name: Option<&'a str>,
    blob_name: Option<&'a str>,
    snapshot: Option<DateTime<Utc>>,
    timeout: Option<u64>,
    range: Option<&'a Range>,
    lease_id: Option<&'a LeaseId>,
    client_request_id: Option<&'a str>,
    increment: u64,
}

impl<'a> BlobStreamBuilder<'a, No, No, No> {
    #[inline]
    pub(crate) fn new(client: &'a Client) -> BlobStreamBuilder<'a, No, No, No> {
        BlobStreamBuilder {
            client,
            p_container_name: PhantomData {},
            container_name: None,
            p_blob_name: PhantomData {},
            blob_name: None,
            p_range: PhantomData {},
            range: None,
            snapshot: None,
            timeout: None,
            lease_id: None,
            client_request_id: None,
            increment: 1024 * 1024,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn client(&self) -> &'a Client {
        self.client
    }
}

impl<'a, BlobNameSet, RangeSet> ContainerNameRequired<'a>
    for BlobStreamBuilder<'a, Yes, BlobNameSet, RangeSet>
where
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn container_name(&self) -> &'a str {
        self.container_name.unwrap()
    }
}

impl<'a, ContainerNameSet, RangeSet> BlobNameRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, Yes, RangeSet>
where
    ContainerNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn blob_name(&self) -> &'a str {
        self.blob_name.unwrap()
    }
}

impl<'a, ContainerNameSet, BlobNameSet> RangeRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, Yes>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
{
    #[inline]
    fn range(&self) -> &'a Range {
        self.range.unwrap()
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> SnapshotOption
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn snapshot(&self) -> Option<DateTime<Utc>> {
        self.snapshot
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> TimeoutOption
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn timeout(&self) -> Option<u64> {
        self.timeout
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> LeaseIdOption<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn lease_id(&self) -> Option<&'a LeaseId> {
        self.lease_id
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequestIdOption<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn client_request_id(&self) -> Option<&'a str> {
        self.client_request_id
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ContainerNameSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, Yes, BlobNameSet, RangeSet>;

    #[inline]
    fn with_container_name(self, container_name: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: Some(container_name),
            blob_name: self.blob_name,
            range: self.range,
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> BlobNameSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, Yes, RangeSet>;

    #[inline]
    fn with_blob_name(self, blob_name: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: Some(blob_name),
            range: self.range,
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> RangeSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, Yes>;

    #[inline]
    fn with_range(self, range: &'a Range) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            range: Some(range),
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> SnapshotSupport
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_snapshot(self, snapshot: DateTime<Utc>) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: Some(snapshot),
            timeout: self.timeout,
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> TimeoutSupport
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_timeout(self, timeout: u64) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: Some(timeout),
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> LeaseIdSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_lease_id(self, lease_id: &'a LeaseId) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: self.timeout,
            range: self.range,
            lease_id: Some(lease_id),
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequestIdSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_client_request_id(self, client_request_id: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: self.timeout,
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: Some(client_request_id),
            increment: self.increment,
        }
    }
}

// methods callable regardless
impl<'a, ContainerNameSet, BlobNameSet, RangeSet>
    BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
}

impl<'a> BlobStreamBuilder<'a, Yes, Yes, Yes> {
    #[inline]
    pub fn finalize(self) -> impl Stream<Item = Result<Vec<u8>, AzureError>> + 'a {
        let client = self.client().clone();
        let container_name = self.container_name().clone();
        let client_request_id = self.client_request_id.map(|v| v.to_owned());
        let blob_name = self.blob_name().clone();
        let range = self.range().to_owned();
        let snapshot = self.snapshot.to_owned();
        let timeout = self.timeout.to_owned();
        let lease_id = self.lease_id.cloned();
        let increment = self.increment;

        futures::stream::unfold(Some(range), move |remaining| {
            let client = client.clone();
            let client_request_id = client_request_id.clone();

            async move {
                let remaining = match remaining {
                    Some(range) => range,
                    None => return None,
                };

                let range = if remaining.start + increment > remaining.end {
                    Range::new(remaining.start, remaining.end)
                } else {
                    Range::new(remaining.start, remaining.start + increment)
                };

                let mut req = GetBlobBuilder::new(&client)
                    .with_container_name(&container_name)
                    .with_blob_name(&blob_name)
                    .with_range(&range);

                if let Some(snapshot) = snapshot {
                    req = req.with_snapshot(snapshot);
                }
                if let Some(timeout) = timeout {
                    req = req.with_timeout(timeout);
                }
                if let Some(ref lease_id) = &lease_id {
                    req = req.with_lease_id(lease_id);
                }
                if let Some(ref client_request_id) = &client_request_id {
                    req = req.with_client_request_id(client_request_id);
                }

                let response = match req.finalize().await {
                    Ok(response) => response,
                    Err(err) => return Some((Err(err), None)),
                };

                Some((
                    Ok(response.data),
                    if remaining.end > range.end {
                        Some(Range::new(range.end, remaining.end))
                    } else {
                        None
                    },
                ))
            }
        })
    }
}
<commit_msg>Add with_chunk_size size option for streaming blob<commit_after>use crate::blob::requests::GetBlobBuilder;
use azure_sdk_core::errors::AzureError;
use azure_sdk_core::lease::LeaseId;
use azure_sdk_core::range::Range;
use azure_sdk_core::{
    BlobNameRequired, BlobNameSupport, ClientRequestIdOption, ClientRequestIdSupport,
    ContainerNameRequired, ContainerNameSupport, LeaseIdOption, LeaseIdSupport, No, RangeRequired,
    RangeSupport, SnapshotOption, SnapshotSupport, TimeoutOption, TimeoutSupport, ToAssign, Yes,
};
use azure_sdk_storage_core::client::Client;
use azure_sdk_storage_core::ClientRequired;
use chrono::{DateTime, Utc};
use futures::stream::Stream;
use std::marker::PhantomData;

#[derive(Debug, Clone)]
pub struct BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    client: &'a Client,
    p_container_name: PhantomData<ContainerNameSet>,
    p_blob_name: PhantomData<BlobNameSet>,
    p_range: PhantomData<RangeSet>,
    container_name: Option<&'a str>,
    blob_name: Option<&'a str>,
    snapshot: Option<DateTime<Utc>>,
    timeout: Option<u64>,
    range: Option<&'a Range>,
    lease_id: Option<&'a LeaseId>,
    client_request_id: Option<&'a str>,
    increment: u64,
}

impl<'a> BlobStreamBuilder<'a, No, No, No> {
    #[inline]
    pub(crate) fn new(client: &'a Client) -> BlobStreamBuilder<'a, No, No, No> {
        BlobStreamBuilder {
            client,
            p_container_name: PhantomData {},
            container_name: None,
            p_blob_name: PhantomData {},
            blob_name: None,
            p_range: PhantomData {},
            range: None,
            snapshot: None,
            timeout: None,
            lease_id: None,
            client_request_id: None,
            increment: 1024 * 1024,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    pub fn with_chunk_size(self, increment: u64) -> Self {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            range: self.range,
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn client(&self) -> &'a Client {
        self.client
    }
}

impl<'a, BlobNameSet, RangeSet> ContainerNameRequired<'a>
    for BlobStreamBuilder<'a, Yes, BlobNameSet, RangeSet>
where
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn container_name(&self) -> &'a str {
        self.container_name.unwrap()
    }
}

impl<'a, ContainerNameSet, RangeSet> BlobNameRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, Yes, RangeSet>
where
    ContainerNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn blob_name(&self) -> &'a str {
        self.blob_name.unwrap()
    }
}

impl<'a, ContainerNameSet, BlobNameSet> RangeRequired<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, Yes>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
{
    #[inline]
    fn range(&self) -> &'a Range {
        self.range.unwrap()
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> SnapshotOption
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn snapshot(&self) -> Option<DateTime<Utc>> {
        self.snapshot
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> TimeoutOption
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn timeout(&self) -> Option<u64> {
        self.timeout
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> LeaseIdOption<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn lease_id(&self) -> Option<&'a LeaseId> {
        self.lease_id
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequestIdOption<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    #[inline]
    fn client_request_id(&self) -> Option<&'a str> {
        self.client_request_id
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ContainerNameSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, Yes, BlobNameSet, RangeSet>;

    #[inline]
    fn with_container_name(self, container_name: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: Some(container_name),
            blob_name: self.blob_name,
            range: self.range,
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> BlobNameSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, Yes, RangeSet>;

    #[inline]
    fn with_blob_name(self, blob_name: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: Some(blob_name),
            range: self.range,
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> RangeSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, Yes>;

    #[inline]
    fn with_range(self, range: &'a Range) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            range: Some(range),
            snapshot: self.snapshot,
            timeout: self.timeout,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> SnapshotSupport
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_snapshot(self, snapshot: DateTime<Utc>) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: Some(snapshot),
            timeout: self.timeout,
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> TimeoutSupport
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_timeout(self, timeout: u64) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: Some(timeout),
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> LeaseIdSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_lease_id(self, lease_id: &'a LeaseId) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: self.timeout,
            range: self.range,
            lease_id: Some(lease_id),
            client_request_id: self.client_request_id,
            increment: self.increment,
        }
    }
}

impl<'a, ContainerNameSet, BlobNameSet, RangeSet> ClientRequestIdSupport<'a>
    for BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
    type O = BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>;

    #[inline]
    fn with_client_request_id(self, client_request_id: &'a str) -> Self::O {
        BlobStreamBuilder {
            client: self.client,
            p_container_name: PhantomData {},
            p_blob_name: PhantomData {},
            p_range: PhantomData {},
            container_name: self.container_name,
            blob_name: self.blob_name,
            snapshot: self.snapshot,
            timeout: self.timeout,
            range: self.range,
            lease_id: self.lease_id,
            client_request_id: Some(client_request_id),
            increment: self.increment,
        }
    }
}

// methods callable regardless
impl<'a, ContainerNameSet, BlobNameSet, RangeSet>
    BlobStreamBuilder<'a, ContainerNameSet, BlobNameSet, RangeSet>
where
    ContainerNameSet: ToAssign,
    BlobNameSet: ToAssign,
    RangeSet: ToAssign,
{
}

impl<'a> BlobStreamBuilder<'a, Yes, Yes, Yes> {
    #[inline]
    pub fn finalize(self) -> impl Stream<Item = Result<Vec<u8>, AzureError>> + 'a {
        let client = self.client().clone();
        let container_name = self.container_name().clone();
        let client_request_id = self.client_request_id.map(|v| v.to_owned());
        let blob_name = self.blob_name().clone();
        let range = self.range().to_owned();
        let snapshot = self.snapshot.to_owned();
        let timeout = self.timeout.to_owned();
        let lease_id = self.lease_id.cloned();
        let increment = self.increment;

        futures::stream::unfold(Some(range), move |remaining| {
            let client = client.clone();
            let client_request_id = client_request_id.clone();

            async move {
                let remaining = match remaining {
                    Some(range) => range,
                    None => return None,
                };

                let range = if remaining.start + increment > remaining.end {
                    Range::new(remaining.start, remaining.end)
                } else {
                    Range::new(remaining.start, remaining.start + increment)
                };

                let mut req = GetBlobBuilder::new(&client)
                    .with_container_name(&container_name)
                    .with_blob_name(&blob_name)
                    .with_range(&range);

                if let Some(snapshot) = snapshot {
                    req = req.with_snapshot(snapshot);
                }
                if let Some(timeout) = timeout {
                    req = req.with_timeout(timeout);
                }
                if let Some(ref lease_id) = &lease_id {
                    req = req.with_lease_id(lease_id);
                }
                if let Some(ref client_request_id) = &client_request_id {
                    req = req.with_client_request_id(client_request_id);
                }

                let response = match req.finalize().await {
                    Ok(response) => response,
                    Err(err) => return Some((Err(err), None)),
                };

                Some((
                    Ok(response.data),
                    if remaining.end > range.end {
                        Some(Range::new(range.end, remaining.end))
                    } else {
                        None
                    },
                ))
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod convert;

use std::path::PathBuf;

use convert::FromLossy;

use rrg_macro::ack;

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

impl std::iter::FromIterator<KeyValue> for AttributedDict {

    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = KeyValue>,
    {
        AttributedDict {
            dat: iter.into_iter().collect(),
        }
    }
}

impl<K, V> std::iter::FromIterator<(K, V)> for AttributedDict
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let pair = |(key, value)| KeyValue::pair(key, value);
        iter.into_iter().map(pair).collect()
    }
}

impl FromLossy<std::fs::Metadata> for StatEntry {

    fn from_lossy(metadata: std::fs::Metadata) -> StatEntry {
        use std::convert::{TryFrom, TryInto};
        #[cfg(target_family = "unix")]
        use std::os::unix::fs::MetadataExt;

        // TODO: Fix definition of `StatEntry`.
        // `StatEntry` defines insufficient integer width for some fields. For
        // now we just ignore errors, but the definition should be improved.
        let some = |value: u64| Some(value.try_into().unwrap_or(0));

        let atime_secs = ack! {
            metadata.accessed(),
            error: "failed to obtain file access time"
        }.and_then(|atime| ack! {
            secs(atime),
            error: "failed to convert access time to seconds"
        });

        let mtime_secs = ack! {
            metadata.modified(),
            error: "failed to obtain file modification time"
        }.and_then(|mtime| ack! {
            secs(mtime),
            error: "failed to convert modification time to seconds"
        });

        let btime_secs = ack! {
            metadata.created(),
            error: "failed to obtain file creation time"
        }.and_then(|btime| ack! {
            secs(btime),
            error: "failed to convert creation time to seconds"
        });

        #[cfg(target_family = "unix")]
        let ctime_secs = ack! {
            u64::try_from(metadata.ctime()),
            error: "negative inode change time"
        };

        StatEntry {
            #[cfg(target_family = "unix")]
            st_mode: Some(metadata.mode().into()),
            #[cfg(target_family = "unix")]
            st_ino: some(metadata.ino()),
            #[cfg(target_family = "unix")]
            st_dev: some(metadata.dev()),
            #[cfg(target_family = "unix")]
            st_rdev: some(metadata.rdev()),
            #[cfg(target_family = "unix")]
            st_nlink: some(metadata.nlink()),
            #[cfg(target_family = "unix")]
            st_uid: Some(metadata.uid()),
            #[cfg(target_family = "unix")]
            st_gid: Some(metadata.gid()),
            st_size: Some(metadata.len()),
            st_atime: atime_secs,
            st_mtime: mtime_secs,
            #[cfg(target_family = "unix")]
            st_ctime: ctime_secs,
            st_btime: btime_secs,
            #[cfg(target_family = "unix")]
            st_blocks: some(metadata.blocks()),
            #[cfg(target_family = "unix")]
            st_blksize: some(metadata.blksize()),
            ..Default::default()
        }
    }
}

/// An error type for situations where parsing path specification failed.
#[derive(Clone, Debug)]
pub enum ParsePathSpecError {
    /// Attempted to parse an empty path.
    Empty,
    /// Attempted to parse a path of unknown type.
    UnknownType(i32),
    /// Attempted to parse a path of invalid type.
    InvalidType(path_spec::PathType),
}

impl std::fmt::Display for ParsePathSpecError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use ParsePathSpecError::*;

        match *self {
            Empty => {
                write!(fmt, "empty path")
            }
            UnknownType(value) => {
                write!(fmt, "unknown path type value: {}", value)
            }
            InvalidType(value) => {
                write!(fmt, "invalid path type: {:?}", value)
            }
        }
    }
}

impl std::error::Error for ParsePathSpecError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl std::convert::TryFrom<PathSpec> for PathBuf {

    type Error = ParsePathSpecError;

    fn try_from(spec: PathSpec) -> Result<PathBuf, ParsePathSpecError> {
        use ParsePathSpecError::*;

        let path_type = spec.pathtype.unwrap_or_default();
        match path_spec::PathType::from_i32(path_type) {
            Some(path_spec::PathType::Os) => (),
            Some(path_type) => return Err(InvalidType(path_type)),
            None => return Err(UnknownType(path_type)),
        };

        match spec.path {
            Some(path) if path.len() > 0 => Ok(PathBuf::from(path)),
            _ => Err(ParsePathSpecError::Empty),
        }
    }
}

impl From<PathBuf> for PathSpec {

    fn from(path: PathBuf) -> PathSpec {
        PathSpec {
            path: Some(path.to_string_lossy().into_owned()),
            pathtype: Some(path_spec::PathType::Os.into()),
            ..Default::default()
        }
    }
}

/// An error type for failures that can occur when converting timestamps.
#[derive(Clone, Debug)]
pub enum TimeConversionError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl TimeConversionError {

    /// Creates a conversion error from an integer overflow error.
    pub fn overflow(error: std::num::TryFromIntError) -> TimeConversionError {
        TimeConversionError::Overflow(error)
    }
}

impl std::fmt::Display for TimeConversionError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for TimeConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for TimeConversionError {

    fn from(error: std::time::SystemTimeError) -> TimeConversionError {
        TimeConversionError::Epoch(error)
    }
}

/// Converts system time into epoch nanoseconds.
///
/// Some GRR messages use epoch nanoseconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::nanos;
///
/// assert_eq!(nanos(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn nanos(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    let time_nanos = time.duration_since(std::time::UNIX_EPOCH)?.as_nanos();

    use std::convert::TryInto as _;
    time_nanos.try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    Ok(nanos(time)? / 1_000)
}

/// Converts system time into epoch seconds.
///
/// Some GRR messages use epoch seconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::secs;
///
/// assert_eq!(secs(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn secs(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    Ok(nanos(time)? / 1_000_000_000)
}
<commit_msg>Simplify time conversion utilities.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

pub mod convert;

use std::path::PathBuf;

use convert::FromLossy;

use rrg_macro::ack;

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl From<bool> for DataBlob {

    fn from(value: bool) -> DataBlob {
        DataBlob {
            boolean: Some(value),
            ..Default::default()
        }
    }
}

impl From<i64> for DataBlob {

    fn from(value: i64) -> DataBlob {
        DataBlob {
            integer: Some(value),
            ..Default::default()
        }
    }
}

impl From<f32> for DataBlob {

    fn from(value: f32) -> DataBlob {
        DataBlob {
            float: Some(value),
            ..Default::default()
        }
    }
}

impl From<Vec<u8>> for DataBlob {

    fn from(value: Vec<u8>) -> DataBlob {
        DataBlob {
            data: Some(value),
            ..Default::default()
        }
    }
}

impl From<String> for DataBlob {

    fn from(value: String) -> DataBlob  {
        DataBlob {
            string: Some(value),
            ..Default::default()
        }
    }
}

impl KeyValue {

    /// Creates an empty key-value.
    ///
    /// Both the key and the value are going to be equal to `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::empty();
    /// assert_eq!(entry.k, None);
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn empty() -> KeyValue {
        KeyValue {
            k: None,
            v: None,
        }
    }

    /// Creates a key-value pair.
    ///
    /// Both the key and the value are going to be equal to the given values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::pair(String::from("foo"), 42i64);
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("foo")));
    /// assert_eq!(entry.v.unwrap().integer, Some(42));
    /// ```
    pub fn pair<K, V>(key: K, value: V) -> KeyValue
    where
        K: Into<DataBlob>,
        V: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: Some(value.into()),
        }
    }

    /// Creates a key-only key-value.
    ///
    /// The key is going to be equal to the given value and the key will be
    /// `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg_proto::KeyValue;
    ///
    /// let entry = KeyValue::key(String::from("quux"));
    /// assert_eq!(entry.k.unwrap().string, Some(String::from("quux")));
    /// assert_eq!(entry.v, None);
    /// ```
    pub fn key<K>(key: K) -> KeyValue
    where
        K: Into<DataBlob>,
    {
        KeyValue {
            k: Some(key.into()),
            v: None,
        }
    }
}

impl std::iter::FromIterator<KeyValue> for AttributedDict {

    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = KeyValue>,
    {
        AttributedDict {
            dat: iter.into_iter().collect(),
        }
    }
}

impl<K, V> std::iter::FromIterator<(K, V)> for AttributedDict
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    fn from_iter<I>(iter: I) -> AttributedDict
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let pair = |(key, value)| KeyValue::pair(key, value);
        iter.into_iter().map(pair).collect()
    }
}

impl FromLossy<std::fs::Metadata> for StatEntry {

    fn from_lossy(metadata: std::fs::Metadata) -> StatEntry {
        use std::convert::{TryFrom, TryInto};
        #[cfg(target_family = "unix")]
        use std::os::unix::fs::MetadataExt;

        // TODO: Fix definition of `StatEntry`.
        // `StatEntry` defines insufficient integer width for some fields. For
        // now we just ignore errors, but the definition should be improved.
        let some = |value: u64| Some(value.try_into().unwrap_or(0));

        let atime_secs = ack! {
            metadata.accessed(),
            error: "failed to obtain file access time"
        }.and_then(|atime| ack! {
            secs(atime),
            error: "failed to convert access time to seconds"
        });

        let mtime_secs = ack! {
            metadata.modified(),
            error: "failed to obtain file modification time"
        }.and_then(|mtime| ack! {
            secs(mtime),
            error: "failed to convert modification time to seconds"
        });

        let btime_secs = ack! {
            metadata.created(),
            error: "failed to obtain file creation time"
        }.and_then(|btime| ack! {
            secs(btime),
            error: "failed to convert creation time to seconds"
        });

        #[cfg(target_family = "unix")]
        let ctime_secs = ack! {
            u64::try_from(metadata.ctime()),
            error: "negative inode change time"
        };

        StatEntry {
            #[cfg(target_family = "unix")]
            st_mode: Some(metadata.mode().into()),
            #[cfg(target_family = "unix")]
            st_ino: some(metadata.ino()),
            #[cfg(target_family = "unix")]
            st_dev: some(metadata.dev()),
            #[cfg(target_family = "unix")]
            st_rdev: some(metadata.rdev()),
            #[cfg(target_family = "unix")]
            st_nlink: some(metadata.nlink()),
            #[cfg(target_family = "unix")]
            st_uid: Some(metadata.uid()),
            #[cfg(target_family = "unix")]
            st_gid: Some(metadata.gid()),
            st_size: Some(metadata.len()),
            st_atime: atime_secs,
            st_mtime: mtime_secs,
            #[cfg(target_family = "unix")]
            st_ctime: ctime_secs,
            st_btime: btime_secs,
            #[cfg(target_family = "unix")]
            st_blocks: some(metadata.blocks()),
            #[cfg(target_family = "unix")]
            st_blksize: some(metadata.blksize()),
            ..Default::default()
        }
    }
}

/// An error type for situations where parsing path specification failed.
#[derive(Clone, Debug)]
pub enum ParsePathSpecError {
    /// Attempted to parse an empty path.
    Empty,
    /// Attempted to parse a path of unknown type.
    UnknownType(i32),
    /// Attempted to parse a path of invalid type.
    InvalidType(path_spec::PathType),
}

impl std::fmt::Display for ParsePathSpecError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use ParsePathSpecError::*;

        match *self {
            Empty => {
                write!(fmt, "empty path")
            }
            UnknownType(value) => {
                write!(fmt, "unknown path type value: {}", value)
            }
            InvalidType(value) => {
                write!(fmt, "invalid path type: {:?}", value)
            }
        }
    }
}

impl std::error::Error for ParsePathSpecError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl std::convert::TryFrom<PathSpec> for PathBuf {

    type Error = ParsePathSpecError;

    fn try_from(spec: PathSpec) -> Result<PathBuf, ParsePathSpecError> {
        use ParsePathSpecError::*;

        let path_type = spec.pathtype.unwrap_or_default();
        match path_spec::PathType::from_i32(path_type) {
            Some(path_spec::PathType::Os) => (),
            Some(path_type) => return Err(InvalidType(path_type)),
            None => return Err(UnknownType(path_type)),
        };

        match spec.path {
            Some(path) if path.len() > 0 => Ok(PathBuf::from(path)),
            _ => Err(ParsePathSpecError::Empty),
        }
    }
}

impl From<PathBuf> for PathSpec {

    fn from(path: PathBuf) -> PathSpec {
        PathSpec {
            path: Some(path.to_string_lossy().into_owned()),
            pathtype: Some(path_spec::PathType::Os.into()),
            ..Default::default()
        }
    }
}

/// An error type for failures that can occur when converting timestamps.
#[derive(Clone, Debug)]
pub enum TimeConversionError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl TimeConversionError {

    /// Creates a conversion error from an integer overflow error.
    pub fn overflow(error: std::num::TryFromIntError) -> TimeConversionError {
        TimeConversionError::Overflow(error)
    }
}

impl std::fmt::Display for TimeConversionError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for TimeConversionError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use TimeConversionError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for TimeConversionError {

    fn from(error: std::time::SystemTimeError) -> TimeConversionError {
        TimeConversionError::Epoch(error)
    }
}

/// Converts system time into epoch nanoseconds.
///
/// Some GRR messages use epoch nanoseconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::nanos;
///
/// assert_eq!(nanos(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn nanos(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = time.duration_since(std::time::UNIX_EPOCH)?;
    duration.as_nanos().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    use std::convert::TryInto as _;

    let duration = std::time::Duration::from_nanos(nanos(time)?);
    duration.as_micros().try_into().map_err(TimeConversionError::overflow)
}

/// Converts system time into epoch seconds.
///
/// Some GRR messages use epoch seconds for representing timestamps. In such
/// cases this function can be useful to convert from more idiomatic types.
///
/// # Examples
///
/// ```
/// use rrg_proto::secs;
///
/// assert_eq!(secs(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn secs(time: std::time::SystemTime) -> Result<u64, TimeConversionError> {
    let duration = std::time::Duration::from_nanos(nanos(time)?);
    Ok(duration.as_secs())
}
<|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/. */

extern crate hyper;

use ipc_channel::ipc;
use net_traits::LoadConsumer::Channel;
use net_traits::ProgressMsg::{Payload, Done};
use net_traits::{LoadData, LoadContext};
use self::hyper::header::ContentType;
use self::hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<ContentType>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use net::data_loader::load;
    use net::mime_classifier::MIMEClassifier;
    use net::resource_thread::CancellationListener;
    use std::sync::Arc;
    use std::sync::mpsc::channel;
    use url::Url;

    let (start_chan, start_port) = ipc::channel().unwrap();
    let classifier = Arc::new(MIMEClassifier::new());
    load(LoadData::new(LoadContext::Browsing, Url::parse(url).unwrap(), None),
         Channel(start_chan),
         classifier, CancellationListener::new(None));

    let response = start_port.recv().unwrap();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv().unwrap();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_owned())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv().unwrap(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse(
        "data:,hello%20world",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("us-ascii".to_owned())))))),
        Some("US-ASCII".to_owned()), Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse(
        "data:text/plain,hello",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec!()))),
        None,
        Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("latin1".to_owned())))))),
        Some("latin1".to_owned()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_only_charset() {
    assert_parse(
        "data:;charset=utf-8,hello",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Utf8))))),
        Some("utf-8".to_owned()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse(
        "data:;base64,C62+7w==",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("us-ascii".to_owned())))))),
        Some("US-ASCII".to_owned()), Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(ContentType(Mime(TopLevel::Application, SubLevel::Ext("octet-stream".to_owned()), vec!()))),
        None,
        Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("koi8-r".to_owned())))))),
        Some("koi8-r".to_owned()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<commit_msg>Auto merge of #9426 - timvandermeij:unused-import, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate hyper;

use ipc_channel::ipc;
use net_traits::LoadConsumer::Channel;
use net_traits::ProgressMsg::{Payload, Done};
use net_traits::{LoadData, LoadContext};
use self::hyper::header::ContentType;
use self::hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<ContentType>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use net::data_loader::load;
    use net::mime_classifier::MIMEClassifier;
    use net::resource_thread::CancellationListener;
    use std::sync::Arc;
    use url::Url;

    let (start_chan, start_port) = ipc::channel().unwrap();
    let classifier = Arc::new(MIMEClassifier::new());
    load(LoadData::new(LoadContext::Browsing, Url::parse(url).unwrap(), None),
         Channel(start_chan),
         classifier, CancellationListener::new(None));

    let response = start_port.recv().unwrap();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv().unwrap();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_owned())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv().unwrap(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse(
        "data:,hello%20world",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("us-ascii".to_owned())))))),
        Some("US-ASCII".to_owned()), Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse(
        "data:text/plain,hello",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec!()))),
        None,
        Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("latin1".to_owned())))))),
        Some("latin1".to_owned()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_only_charset() {
    assert_parse(
        "data:;charset=utf-8,hello",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Utf8))))),
        Some("utf-8".to_owned()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse(
        "data:;base64,C62+7w==",
        Some(ContentType(Mime(TopLevel::Text,
                              SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("us-ascii".to_owned())))))),
        Some("US-ASCII".to_owned()), Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(ContentType(Mime(TopLevel::Application, SubLevel::Ext("octet-stream".to_owned()), vec!()))),
        None,
        Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
                              vec!((Attr::Charset, Value::Ext("koi8-r".to_owned())))))),
        Some("koi8-r".to_owned()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<|endoftext|>


<commit_before>impl Solution {
    pub fn running_sum(nums: Vec<i32>) -> Vec<i32> {
        nums.iter().fold((0, vec![]), |(sum, mut vec), i| (sum + i, { vec.push(sum + i); vec }) ).1
    }
}
<commit_msg>[katas] additional option for running_sum<commit_after>impl Solution {
    pub fn running_sum(nums: Vec<i32>) -> Vec<i32> {
        nums.iter().fold((0, vec![]), |(sum, mut vec), i| (sum + i, { vec.push(sum + i); vec }) ).1
    }
}

impl Solution {
    pub fn running_sum(nums: Vec<i32>) -> Vec<i32> {
        nums.into_iter().fold(Vec::new(), |mut running_sum, elem| {
            match running_sum.last() {
                Some(last) => { running_sum.push(last + elem); running_sum },
                None => { running_sum.push(elem); running_sum }
            }
        })
    }
}
<|endoftext|>