<commit_before>use crate::utils::span_lint_and_sugg;
use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

/// **What it does:** Checks for unnecessary repetition of structure name when a
/// replacement with `Self` is applicable.
///
/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
/// name
/// feels inconsistent.
///
/// **Known problems:**
/// - False positive when using associated types (#2843)
/// - False positives in some situations when using generics (#3410)
///
/// **Example:**
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Foo {
///         Foo {}
///     }
/// }
/// ```
/// could be
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Self {
///         Self {}
///     }
/// }
/// ```
declare_clippy_lint! {
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

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

impl LintPass for UseSelf {
    fn get_lints(&self) -> LintArray {
        lint_array!(USE_SELF)
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // path segments only include actual path, no methods or fields
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // `to()` doesn't shorten span, so we shorten it with `until(..)`
    // and then include it with `to(..)`
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

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

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration.  We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        GenericArg::Type(_) => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::All(&self.cx.tcx.hir())
    }
}
<commit_msg>Improving comments.<commit_after>use crate::utils::span_lint_and_sugg;
use if_chain::if_chain;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax_pos::symbol::keywords::SelfUpper;

/// **What it does:** Checks for unnecessary repetition of structure name when a
/// replacement with `Self` is applicable.
///
/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
/// name
/// feels inconsistent.
///
/// **Known problems:**
/// - False positive when using associated types (#2843)
/// - False positives in some situations when using generics (#3410)
///
/// **Example:**
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Foo {
///         Foo {}
///     }
/// }
/// ```
/// could be
/// ```rust
/// struct Foo {}
/// impl Foo {
///     fn new() -> Self {
///         Self {}
///     }
/// }
/// ```
declare_clippy_lint! {
    pub USE_SELF,
    pedantic,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

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

impl LintPass for UseSelf {
    fn get_lints(&self) -> LintArray {
        lint_array!(USE_SELF)
    }
}

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
    // path segments only include actual path, no methods or fields
    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
    // only take path up to the end of last_path_span
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx: 'a> {
    item_type: ty::Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, t: &'tcx Ty) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty {
                if let Some(impl_ty) = impl_ty {
                    if self.item_type == impl_ty {
                        let is_self_ty = if let def::Def::SelfTy(..) = path.def {
                            true
                        } else {
                            false
                        };

                        if !is_self_ty {
                            span_use_self_lint(self.cx, path);
                        }
                    }
                }
            }
        }

        walk_ty(self, t)
    }

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

fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: ty::Ty<'tcx>,
    impl_item: &ImplItem,
    impl_decl: &'tcx FnDecl,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find(|assoc_item| {
            assoc_item.kind == ty::AssociatedKind::Method
                && cx
                    .tcx
                    .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
        })
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration.  We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        GenericArg::Type(_) => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.node {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx: 'a> {
    item_path: &'a Path,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
            if self.item_path.def == path.def {
                span_use_self_lint(self.cx, path);
            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
                    span_use_self_lint(self.cx, path);
                }
            }
        }
        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item) {
        match item.node {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

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


<commit_before>macro_rules! struct_events {
  (
    keyboard: { $( $k_alias:ident : $k_sdl:ident ),* },
    else: { $( $e_alias:ident : $e_sdl:pat ),* }
    )
  => {
    use sdl2::EventPump;

    pub struct ImmediateEvents {
      resize: Option<(u32, u32)>,
      $( pub $k_alias : Option<bool> , )*
      pub mouse_click : Option<(i32, i32)>,
      $( pub $e_alias : bool ),*
    }

    impl ImmediateEvents {
      pub fn new() -> ImmediateEvents {
        ImmediateEvents {
          resize: None,
          $( $k_alias: None , )*
          mouse_click: None,
          $( $e_alias: false ),*
        }
      }
    }

    pub struct Events {
      pump: EventPump,
      pub now: ImmediateEvents,

      pub mouse_click: Option<(i32, i32)>,
      $( pub $k_alias: bool ),*
    }

    impl Events {
      pub fn new(pump: EventPump) -> Events {
        Events {
          pump: pump,
          now: ImmediateEvents::new(),

          mouse_click: None,
          $( $k_alias: false ),*
        }
      }

      pub fn pump(&mut self, renderer: &mut ::sdl2::render::Renderer) {
        self.now = ImmediateEvents::new();

        for event in self.pump.poll_iter() {
          use sdl2::event::Event::*;
          use sdl2::event::WindowEventId::Resized;
          use sdl2::keyboard::Keycode::*;

          match event {
            Window { win_event_id: Resized, .. } => {
              self.now.resize = Some(renderer.output_size().unwrap());
            },

            MouseButtonDown { x, y, .. } => {
              self.now.mouse_click = Some((x, y));
              self.mouse_click = Some((x, y));
            },

            MouseButtonUp {..} => {
              self.now.mouse_click = None;
              self.mouse_click = None;
            },

            KeyDown { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  if !self.$k_alias {
                    self.now.$k_alias = Some(true);
                  }

                  self.$k_alias = true;
                }
                ),*
              _ => {}
            },

            KeyUp { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  self.now.$k_alias = Some(false);
                  self.$k_alias = false;
                }
                ),*
              _ => {}
            },

            $(
              $e_sdl => {
                self.now.$e_alias = true;
              }
              )*,

            _ => {}
          }
        }
      }
    }
  }
}
<commit_msg>Convert events.rs to 0.27 compatible<commit_after>macro_rules! struct_events {
  (
    keyboard: { $( $k_alias:ident : $k_sdl:ident ),* },
    else: { $( $e_alias:ident : $e_sdl:pat ),* }
    )
  => {
    use sdl2::EventPump;

    pub struct ImmediateEvents {
      resize: Option<(u32, u32)>,
      $( pub $k_alias : Option<bool> , )*
      pub mouse_click : Option<(i32, i32)>,
      $( pub $e_alias : bool ),*
    }

    impl ImmediateEvents {
      pub fn new() -> ImmediateEvents {
        ImmediateEvents {
          resize: None,
          $( $k_alias: None , )*
          mouse_click: None,
          $( $e_alias: false ),*
        }
      }
    }

    pub struct Events {
      pump: EventPump,
      pub now: ImmediateEvents,

      pub mouse_click: Option<(i32, i32)>,
      $( pub $k_alias: bool ),*
    }

    impl Events {
      pub fn new(pump: EventPump) -> Events {
        Events {
          pump: pump,
          now: ImmediateEvents::new(),

          mouse_click: None,
          $( $k_alias: false ),*
        }
      }

      pub fn pump(&mut self, renderer: &mut ::sdl2::render::Renderer) {
        self.now = ImmediateEvents::new();

        for event in self.pump.poll_iter() {
          use sdl2::event::Event::*;
          use sdl2::event::WindowEvent;
          use sdl2::keyboard::Keycode::*;

          match event {
            Window { win_event: Resized, .. } => {
              self.now.resize = Some(renderer.output_size().unwrap());
            },

            MouseButtonDown { x, y, .. } => {
              self.now.mouse_click = Some((x, y));
              self.mouse_click = Some((x, y));
            },

            MouseButtonUp {..} => {
              self.now.mouse_click = None;
              self.mouse_click = None;
            },

            KeyDown { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  if !self.$k_alias {
                    self.now.$k_alias = Some(true);
                  }

                  self.$k_alias = true;
                }
                ),*
              _ => {}
            },

            KeyUp { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  self.now.$k_alias = Some(false);
                  self.$k_alias = false;
                }
                ),*
              _ => {}
            },

            $(
              $e_sdl => {
                self.now.$e_alias = true;
              }
              )*,

            _ => {}
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use coresimd::simd::*;
use coresimd::x86::*;
use mem;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sha1msg1"]
    fn sha1msg1(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1msg2"]
    fn sha1msg2(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1nexte"]
    fn sha1nexte(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1rnds4"]
    fn sha1rnds4(a: i32x4, b: i32x4, c: i8) -> i32x4;
    #[link_name = "llvm.x86.sha256msg1"]
    fn sha256msg1(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha256msg2"]
    fn sha256msg2(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha256rnds2"]
    fn sha256rnds2(a: i32x4, b: i32x4, k: i32x4) -> i32x4;
}

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Perform an intermediate calculation for the next four SHA1 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and returning the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1msg1))]
pub unsafe fn _mm_sha1msg1_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1msg1(a.as_i32x4(), b.as_i32x4()))
}

/// Perform the final calculation for the next four SHA1 message values
/// (unsigned 32-bit integers) using the intermediate result in `a` and the
/// previous message values in `b`, and returns the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1msg2))]
pub unsafe fn _mm_sha1msg2_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1msg2(a.as_i32x4(), b.as_i32x4()))
}

/// Calculate SHA1 state variable E after four rounds of operation from the
/// current SHA1 state variable `a`, add that value to the scheduled values
/// (unsigned 32-bit integers) in `b`, and returns the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1nexte))]
pub unsafe fn _mm_sha1nexte_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1nexte(a.as_i32x4(), b.as_i32x4()))
}

/// Perform four rounds of SHA1 operation using an initial SHA1 state (A,B,C,D)
/// from `a` and some pre-computed sum of the next 4 round message values
/// (unsigned 32-bit integers), and state variable E from `b`, and return the
/// updated SHA1 state (A,B,C,D). `func` contains the logic functions and round
/// constants.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1rnds4, func = 0))]
#[rustc_args_required_const(2)]
pub unsafe fn _mm_sha1rnds4_epu32(a: __m128i, b: __m128i, func: i32) -> __m128i {
    let a = a.as_i32x4();
    let b = b.as_i32x4();
    macro_rules! call {
        ($imm2:expr) => { sha1rnds4(a, b, $imm2) }
    }
    let ret = constify_imm2!(func, call);
    mem::transmute(ret)
}

/// Perform an intermediate calculation for the next four SHA256 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and return the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256msg1))]
pub unsafe fn _mm_sha256msg1_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha256msg1(a.as_i32x4(), b.as_i32x4()))
}

/// Perform the final calculation for the next four SHA256 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and return the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256msg2))]
pub unsafe fn _mm_sha256msg2_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha256msg2(a.as_i32x4(), b.as_i32x4()))
}

/// Perform 2 rounds of SHA256 operation using an initial SHA256 state (C,D,G,H)
/// from `a`, an initial SHA256 state (A,B,E,F) from `b`, and a pre-computed sum
/// of the next 2 round message values (unsigned 32-bit integers) and the
/// corresponding round constants from `k`, and store the updated SHA256 state
/// (A,B,E,F) in dst.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256rnds2))]
pub unsafe fn _mm_sha256rnds2_epu32 (a: __m128i, b: __m128i, k: __m128i) -> __m128i {
    mem::transmute(sha256rnds2(a.as_i32x4(), b.as_i32x4(), k.as_i32x4()))
}

#[cfg(test)]
mod tests {
    use std::mem::{self, transmute};
    use std::f64::{self, NAN};
    use std::f32;
    use std::i32;

    use stdsimd_test::simd_test;
    use test::black_box; // Used to inhibit constant-folding.
    use coresimd::x86::*;
    use coresimd::simd::*;

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1msg1_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x98829f34f74ad457, 0xda2b1a44d0b5ad3c);
        let r = _mm_sha1msg1_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1msg2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xf714b202d863d47d, 0x90c30d946b3d3b35);
        let r = _mm_sha1msg2_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1nexte_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x2589d5be923f82a4, 0x59f111f13956c25b);
        let r = _mm_sha1nexte_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1rnds4_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x32b13cd8322f5268, 0xc54420862bd9246f);
        let r = _mm_sha1rnds4_epu32(a, b, 0);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0x6d4c43e56a3c25d9, 0xa7e00fb775cbd3fe);
        let r = _mm_sha1rnds4_epu32(a, b, 1);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0xb304e383c01222f4, 0x66f6b3b1f89d8001);
        let r = _mm_sha1rnds4_epu32(a, b, 2);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0x8189b758bfabfa79, 0xdb08f6e78cae098b);
        let r = _mm_sha1rnds4_epu32(a, b, 3);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256msg1_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xeb84973fd5cda67d, 0x2857b88f406b09ee);
        let r = _mm_sha256msg1_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256msg2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xb58777ce887fd851, 0x15d1ec8b73ac8450);
        let r = _mm_sha256msg2_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256rnds2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let k = _mm_set_epi64x(0, 0x12835b01d807aa98);
        let expected = _mm_set_epi64x(0xd3063037effb15ea, 0x187ee3db0d6d1d19);
        let r = _mm_sha256rnds2_epu32(a, b, k);
        assert_eq_m128i(r, expected);
    }
}
<commit_msg>rustfmt<commit_after>use coresimd::simd::*;
use coresimd::x86::*;
use mem;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sha1msg1"]
    fn sha1msg1(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1msg2"]
    fn sha1msg2(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1nexte"]
    fn sha1nexte(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha1rnds4"]
    fn sha1rnds4(a: i32x4, b: i32x4, c: i8) -> i32x4;
    #[link_name = "llvm.x86.sha256msg1"]
    fn sha256msg1(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha256msg2"]
    fn sha256msg2(a: i32x4, b: i32x4) -> i32x4;
    #[link_name = "llvm.x86.sha256rnds2"]
    fn sha256rnds2(a: i32x4, b: i32x4, k: i32x4) -> i32x4;
}

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Perform an intermediate calculation for the next four SHA1 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and returning the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1msg1))]
pub unsafe fn _mm_sha1msg1_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1msg1(a.as_i32x4(), b.as_i32x4()))
}

/// Perform the final calculation for the next four SHA1 message values
/// (unsigned 32-bit integers) using the intermediate result in `a` and the
/// previous message values in `b`, and returns the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1msg2))]
pub unsafe fn _mm_sha1msg2_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1msg2(a.as_i32x4(), b.as_i32x4()))
}

/// Calculate SHA1 state variable E after four rounds of operation from the
/// current SHA1 state variable `a`, add that value to the scheduled values
/// (unsigned 32-bit integers) in `b`, and returns the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1nexte))]
pub unsafe fn _mm_sha1nexte_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha1nexte(a.as_i32x4(), b.as_i32x4()))
}

/// Perform four rounds of SHA1 operation using an initial SHA1 state (A,B,C,D)
/// from `a` and some pre-computed sum of the next 4 round message values
/// (unsigned 32-bit integers), and state variable E from `b`, and return the
/// updated SHA1 state (A,B,C,D). `func` contains the logic functions and round
/// constants.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha1rnds4, func = 0))]
#[rustc_args_required_const(2)]
pub unsafe fn _mm_sha1rnds4_epu32(
    a: __m128i, b: __m128i, func: i32
) -> __m128i {
    let a = a.as_i32x4();
    let b = b.as_i32x4();
    macro_rules! call {
        ($imm2: expr) => {
            sha1rnds4(a, b, $imm2)
        };
    }
    let ret = constify_imm2!(func, call);
    mem::transmute(ret)
}

/// Perform an intermediate calculation for the next four SHA256 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and return the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256msg1))]
pub unsafe fn _mm_sha256msg1_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha256msg1(a.as_i32x4(), b.as_i32x4()))
}

/// Perform the final calculation for the next four SHA256 message values
/// (unsigned 32-bit integers) using previous message values from `a` and `b`,
/// and return the result.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256msg2))]
pub unsafe fn _mm_sha256msg2_epu32(a: __m128i, b: __m128i) -> __m128i {
    mem::transmute(sha256msg2(a.as_i32x4(), b.as_i32x4()))
}

/// Perform 2 rounds of SHA256 operation using an initial SHA256 state
/// (C,D,G,H) from `a`, an initial SHA256 state (A,B,E,F) from `b`, and a
/// pre-computed sum of the next 2 round message values (unsigned 32-bit
/// integers) and the corresponding round constants from `k`, and store the
/// updated SHA256 state (A,B,E,F) in dst.
#[inline]
#[target_feature(enable = "sha")]
#[cfg_attr(test, assert_instr(sha256rnds2))]
pub unsafe fn _mm_sha256rnds2_epu32(
    a: __m128i, b: __m128i, k: __m128i
) -> __m128i {
    mem::transmute(sha256rnds2(
        a.as_i32x4(),
        b.as_i32x4(),
        k.as_i32x4(),
    ))
}

#[cfg(test)]
mod tests {
    use std::mem::{self, transmute};
    use std::f64::{self, NAN};
    use std::f32;
    use std::i32;

    use stdsimd_test::simd_test;
    use test::black_box; // Used to inhibit constant-folding.
    use coresimd::x86::*;
    use coresimd::simd::*;

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1msg1_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x98829f34f74ad457, 0xda2b1a44d0b5ad3c);
        let r = _mm_sha1msg1_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1msg2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xf714b202d863d47d, 0x90c30d946b3d3b35);
        let r = _mm_sha1msg2_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1nexte_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x2589d5be923f82a4, 0x59f111f13956c25b);
        let r = _mm_sha1nexte_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha1rnds4_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0x32b13cd8322f5268, 0xc54420862bd9246f);
        let r = _mm_sha1rnds4_epu32(a, b, 0);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0x6d4c43e56a3c25d9, 0xa7e00fb775cbd3fe);
        let r = _mm_sha1rnds4_epu32(a, b, 1);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0xb304e383c01222f4, 0x66f6b3b1f89d8001);
        let r = _mm_sha1rnds4_epu32(a, b, 2);
        assert_eq_m128i(r, expected);

        let expected = _mm_set_epi64x(0x8189b758bfabfa79, 0xdb08f6e78cae098b);
        let r = _mm_sha1rnds4_epu32(a, b, 3);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256msg1_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xeb84973fd5cda67d, 0x2857b88f406b09ee);
        let r = _mm_sha256msg1_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256msg2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let expected = _mm_set_epi64x(0xb58777ce887fd851, 0x15d1ec8b73ac8450);
        let r = _mm_sha256msg2_epu32(a, b);
        assert_eq_m128i(r, expected);
    }

    #[simd_test = "sha"]
    #[allow(overflowing_literals)]
    unsafe fn test_mm_sha256rnds2_epu32() {
        let a = _mm_set_epi64x(0xe9b5dba5b5c0fbcf, 0x71374491428a2f98);
        let b = _mm_set_epi64x(0xab1c5ed5923f82a4, 0x59f111f13956c25b);
        let k = _mm_set_epi64x(0, 0x12835b01d807aa98);
        let expected = _mm_set_epi64x(0xd3063037effb15ea, 0x187ee3db0d6d1d19);
        let r = _mm_sha256rnds2_epu32(a, b, k);
        assert_eq_m128i(r, expected);
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<commit_msg>Replace unwrap() with try!()<commit_after>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<|endoftext|>


<commit_before>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};

use error::{TagError, TagErrorKind};
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.unwrap_err()))));
        }
        let tags = tags.unwrap();

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagError::new(TagErrorKind::TagTypeError, None));
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagError::new(TagErrorKind::NotATag, None));
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagError::new(TagErrorKind::TagTypeError, None)),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagError::new(TagErrorKind::NotATag, None));
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(|e| TagError::new(TagErrorKind::HeaderWriteError, Some(Box::new(e))))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagError::new(TagErrorKind::NotATag, None));
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagError::new(TagErrorKind::NotATag, None));
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.unwrap_err()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<commit_msg>Use IntoError functionality to have less noise in the error construction code<commit_after>use std::ops::Deref;
use std::ops::DerefMut;

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader, FileLockEntry};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(kind.into_error_with_cause(Box::new(tags.unwrap_err())));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.unwrap_err());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

impl<'a> Tagable for FileLockEntry<'a> {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.deref().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.deref().has_tags(ts)
    }

}

<|endoftext|>


<commit_before>use super::*;
use super::super::chunk::{Chunk, Chunks};
use super::super::segs::{Segment};
use ram::entry::*;
use ram::cell::{Cell, CellHeader};
use ram::tombstone::Tombstone;
use dovahkiin::types::Id;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

pub struct CompactCleaner {
    chunks: Arc<Chunks>,
    closed: AtomicBool
}

impl CompactCleaner {
    pub fn clean_segment(chunk: &Chunk, seg: &Arc<Segment>) {
        // Clean only if segment have fragments
        if seg.total_dead_space() == 0 {return;}

        // Previous implementation is inplace compaction. Segments are mutable and subject to changes.
        // Log-structured cleaner suggests new segment allocation and copy living entries from the
        // old segment to new segment. The new segment should have smaller sizes than the old one.
        // In this way locks can be straight forward, copy those entries to the new segment, change
        // cell indices by lock cells first, remove the old segment.
        // Segment locks will no long be required for transfer process will ensure there will be no
        // on going read operations to the old segment when the segment to be deleted.

        // Some comments regards to RAMCloud seglets. To compress the actual memory spaces consumed by
        // segments, RAMCloud introduces seglets as the minimal unit of the memory. It records a mapping
        // from segment to seglets it consumed. In this case, compacted segments will take less seglets.
        // Freed seglets will be used by other new allocated segments, which can leads to incontinently.
        // Actually, malloc already handled this situation to overcome fragmentation, we can simply use
        // malloc to allocate new memory spaces for segments than maintaining seglets mappings in userspace.
        debug!("Cleaning segment {} from chunk {}", seg.id, chunk.id);

        // scan and mark live entries
        let entries = chunk.live_entries(seg);
        let live_size: usize = entries.iter().map(|e| e.meta.entry_size).sum();
        debug!("Segment {} from chunk {} have {} live objects. Total size {} bytes for new segment.",
               seg.id, chunk.id, entries.len(), live_size);
        let new_seg_id = chunk.seg_counter.fetch_add(1, Ordering::Relaxed);
        let new_seg = Arc::new(Segment::new(new_seg_id, live_size, &chunk.backup_storage));
        let mut cursor = new_seg.addr;
        let copied_entries =
            entries
                .iter()
                .map(|e: &Entry| {
                    let entry_size = e.meta.entry_size;
                    let result= (e, cursor);
                    unsafe {
                        libc::memcpy(
                            cursor as *mut libc::c_void,
                            e.meta.entry_pos as *mut libc::c_void,
                            entry_size);
                    }
                    cursor += entry_size;
                    return result;
                });

        new_seg.append_header.store(new_seg.addr + live_size, Ordering::Relaxed);
        // put segment directly into the segment map prior to resetting cell addresses as side logs
        chunk.put_segment(new_seg);

        // update cell address chunk index
        copied_entries
            .filter(|pair|
                pair.0.meta.entry_header.entry_type == EntryType::Cell)
            .for_each(|(entry, new_addr)| {
                if let EntryContent::Cell(header) = entry.content {
                    if let Some(mut cell_guard) = chunk.index.get_mut(&header.hash) {
                        let old_addr = entry.meta.entry_pos;
                        if *cell_guard == old_addr {
                            *cell_guard = new_addr;
                        } else {
                            warn!("cell address {} have been changed to {} on relocating on cleaning",
                                  old_addr, *cell_guard);
                        }
                    }
                } else {
                    panic!("not cell after filter")
                }
            });

        chunk.remove_segment(seg.id);
        debug!("Clean finished for segment {} from chunk {}", seg.id, chunk.id);
    }
}
<commit_msg>overwrite the old segment instead of create one with new id<commit_after>use super::*;
use super::super::chunk::{Chunk, Chunks};
use super::super::segs::{Segment};
use ram::entry::*;
use ram::cell::{Cell, CellHeader};
use ram::tombstone::Tombstone;
use dovahkiin::types::Id;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

pub struct CompactCleaner;

impl CompactCleaner {
    pub fn clean_segment(chunk: &Chunk, seg: &Arc<Segment>) {
        // Clean only if segment have fragments
        if seg.total_dead_space() == 0 {return;}

        // Previous implementation is inplace compaction. Segments are mutable and subject to changes.
        // Log-structured cleaner suggests new segment allocation and copy living entries from the
        // old segment to new segment. The new segment should have smaller sizes than the old one.
        // In this way locks can be straight forward, copy those entries to the new segment, change
        // cell indices by lock cells first, remove the old segment.
        // Segment locks will no long be required for transfer process will ensure there will be no
        // on going read operations to the old segment when the segment to be deleted.

        // Some comments regards to RAMCloud seglets. To compress the actual memory spaces consumed by
        // segments, RAMCloud introduces seglets as the minimal unit of the memory. It records a mapping
        // from segment to seglets it consumed. In this case, compacted segments will take less seglets.
        // Freed seglets will be used by other new allocated segments, which can leads to incontinently.
        // Actually, malloc already handled this situation to overcome fragmentation, we can simply use
        // malloc to allocate new memory spaces for segments than maintaining seglets mappings in userspace.
        debug!("Cleaning segment {} from chunk {}", seg.id, chunk.id);

        // scan and mark live entries
        let entries = chunk.live_entries(seg);
        let live_size: usize = entries.iter().map(|e| e.meta.entry_size).sum();
        debug!("Segment {} from chunk {} have {} live objects. Total size {} bytes for new segment.",
               seg.id, chunk.id, entries.len(), live_size);
        let new_seg = Arc::new(Segment::new(seg.id, live_size, &chunk.backup_storage));
        let mut cursor = new_seg.addr;
        let copied_entries =
            entries
                .iter()
                .map(|e: &Entry| {
                    let entry_size = e.meta.entry_size;
                    let result= (e, cursor);
                    unsafe {
                        libc::memcpy(
                            cursor as *mut libc::c_void,
                            e.meta.entry_pos as *mut libc::c_void,
                            entry_size);
                    }
                    cursor += entry_size;
                    return result;
                });

        new_seg.append_header.store(new_seg.addr + live_size, Ordering::Relaxed);

        // update cell address chunk index
        copied_entries
            .filter(|pair|
                pair.0.meta.entry_header.entry_type == EntryType::Cell)
            .for_each(|(entry, new_addr)| {
                if let EntryContent::Cell(header) = entry.content {
                    if let Some(mut cell_guard) = chunk.index.get_mut(&header.hash) {
                        let old_addr = entry.meta.entry_pos;
                        if *cell_guard == old_addr {
                            *cell_guard = new_addr;
                        } else {
                            warn!("cell address {} have been changed to {} on relocating on cleaning",
                                  old_addr, *cell_guard);
                        }
                    }
                } else {
                    panic!("not cell after filter")
                }
            });

        // put segment directly into the segment map after to resetting cell addresses as side logs to replace the old one
        chunk.put_segment(new_seg);

        debug!("Clean finished for segment {} from chunk {}", seg.id, chunk.id);
    }
}
<|endoftext|>


<commit_before>import rustc::syntax::ast;

export fn_attrs, arg_attrs;
export parse_fn;

type fn_attrs = {
    brief: option<str>,
    desc: option<str>,
    args: [arg_attrs],
    return: option<str>
};

type arg_attrs = {
    name: str,
    desc: str
};

fn parse_fn(
    attrs: [ast::attribute]
) -> fn_attrs {

    for attr in attrs {
        alt attr.node.value.node {
          ast::meta_name_value(
              "doc", {node: ast::lit_str(value), span: _}) {
            ret {
                brief: none,
                desc: some(value),
                args: [],
                return: none
            };
          }
          ast::meta_list("doc", docs) {
            ret parse_fn_(docs);
          }
        }
    }

    {
        brief: none,
        desc: none,
        args: [],
        return: none
    }
}

fn parse_fn_(
    items: [@ast::meta_item]
) -> fn_attrs {
    let brief = none;
    let desc = none;
    let return = none;
    let argdocs = [];
    let argdocsfound = none;
    for item: @ast::meta_item in items {
        alt item.node {
            ast::meta_name_value("brief", {node: ast::lit_str(value),
                                           span: _}) {
                brief = some(value);
            }
            ast::meta_name_value("desc", {node: ast::lit_str(value),
                                              span: _}) {
                desc = some(value);
            }
            ast::meta_name_value("return", {node: ast::lit_str(value),
                                            span: _}) {
                return = some(value);
            }
            ast::meta_list("args", args) {
                argdocsfound = some(args);
            }
            _ { }
        }
    }

    alt argdocsfound {
        none. { }
        some(ds) {
            for d: @ast::meta_item in ds {
                alt d.node {
                  ast::meta_name_value(key, {node: ast::lit_str(value),
                                             span: _}) {
                    argdocs += [{
                        name: key,
                        desc: value
                    }];
                  }
                }
            }
        }
    }

    {
        brief: brief,
        desc: desc,
        args: argdocs,
        return: return
    }
}

#[cfg(test)]
mod tests {

    fn parse_attributes(source: str) -> [ast::attribute] {
        import rustc::driver::diagnostic;
        import rustc::syntax::codemap;
        import rustc::syntax::parse::parser;

        let cm = codemap::new_codemap();
        let parse_sess = @{
            cm: cm,
            mutable next_id: 0,
            diagnostic: diagnostic::mk_handler(cm, none)
        };
        let parser = parser::new_parser_from_source_str(
            parse_sess, [], "-", source);

        parser::parse_outer_attributes(parser)
    }

    #[test]
    fn parse_fn_should_handle_undocumented_functions() {
        let source = "";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == none;
        assert attrs.desc == none;
        assert attrs.return == none;
        assert vec::len(attrs.args) == 0u;
    }

    #[tes]
    fn parse_fn_should_parse_simple_doc_attributes() {
        let source = "#[doc = \"basic\"]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == some("basic");
    }

    #[test]
    fn parse_fn_should_parse_the_brief_description() {
        let source = "#[doc(brief = \"short\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == some("short");
    }

    #[test]
    fn parse_fn_should_parse_the_long_description() {
        let source = "#[doc(desc = \"description\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.desc == some("description");
    }

    #[test]
    fn parse_fn_should_parse_the_return_value_description() {
        let source = "#[doc(return = \"return value\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.return == some("return value");
    }

    #[test]
    fn parse_fn_should_parse_the_argument_descriptions() {
        let source = "#[doc(args(a = \"arg a\", b = \"arg b\"))]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.args[0] == {name: "a", desc: "arg a"};
        assert attrs.args[1] == {name: "b", desc: "arg b"};
    }
}<commit_msg>rustdoc: Add a fallthrough path to meta_item search in parse_fn<commit_after>import rustc::syntax::ast;

export fn_attrs, arg_attrs;
export parse_fn;

type fn_attrs = {
    brief: option<str>,
    desc: option<str>,
    args: [arg_attrs],
    return: option<str>
};

type arg_attrs = {
    name: str,
    desc: str
};

fn parse_fn(
    attrs: [ast::attribute]
) -> fn_attrs {

    for attr in attrs {
        alt attr.node.value.node {
          ast::meta_name_value(
              "doc", {node: ast::lit_str(value), span: _}) {
            ret {
                brief: none,
                desc: some(value),
                args: [],
                return: none
            };
          }
          ast::meta_list("doc", docs) {
            ret parse_fn_(docs);
          }
          _ { }
        }
    }

    {
        brief: none,
        desc: none,
        args: [],
        return: none
    }
}

fn parse_fn_(
    items: [@ast::meta_item]
) -> fn_attrs {
    let brief = none;
    let desc = none;
    let return = none;
    let argdocs = [];
    let argdocsfound = none;
    for item: @ast::meta_item in items {
        alt item.node {
            ast::meta_name_value("brief", {node: ast::lit_str(value),
                                           span: _}) {
                brief = some(value);
            }
            ast::meta_name_value("desc", {node: ast::lit_str(value),
                                              span: _}) {
                desc = some(value);
            }
            ast::meta_name_value("return", {node: ast::lit_str(value),
                                            span: _}) {
                return = some(value);
            }
            ast::meta_list("args", args) {
                argdocsfound = some(args);
            }
            _ { }
        }
    }

    alt argdocsfound {
        none. { }
        some(ds) {
            for d: @ast::meta_item in ds {
                alt d.node {
                  ast::meta_name_value(key, {node: ast::lit_str(value),
                                             span: _}) {
                    argdocs += [{
                        name: key,
                        desc: value
                    }];
                  }
                }
            }
        }
    }

    {
        brief: brief,
        desc: desc,
        args: argdocs,
        return: return
    }
}

#[cfg(test)]
mod tests {

    fn parse_attributes(source: str) -> [ast::attribute] {
        import rustc::driver::diagnostic;
        import rustc::syntax::codemap;
        import rustc::syntax::parse::parser;

        let cm = codemap::new_codemap();
        let parse_sess = @{
            cm: cm,
            mutable next_id: 0,
            diagnostic: diagnostic::mk_handler(cm, none)
        };
        let parser = parser::new_parser_from_source_str(
            parse_sess, [], "-", source);

        parser::parse_outer_attributes(parser)
    }

    #[test]
    fn parse_fn_should_handle_undocumented_functions() {
        let source = "";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == none;
        assert attrs.desc == none;
        assert attrs.return == none;
        assert vec::len(attrs.args) == 0u;
    }

    #[tes]
    fn parse_fn_should_parse_simple_doc_attributes() {
        let source = "#[doc = \"basic\"]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == some("basic");
    }

    #[test]
    fn parse_fn_should_parse_the_brief_description() {
        let source = "#[doc(brief = \"short\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.brief == some("short");
    }

    #[test]
    fn parse_fn_should_parse_the_long_description() {
        let source = "#[doc(desc = \"description\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.desc == some("description");
    }

    #[test]
    fn parse_fn_should_parse_the_return_value_description() {
        let source = "#[doc(return = \"return value\")]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.return == some("return value");
    }

    #[test]
    fn parse_fn_should_parse_the_argument_descriptions() {
        let source = "#[doc(args(a = \"arg a\", b = \"arg b\"))]";
        let attrs = parse_attributes(source);
        let attrs = parse_fn(attrs);
        assert attrs.args[0] == {name: "a", desc: "arg a"};
        assert attrs.args[1] == {name: "b", desc: "arg b"};
    }
}<|endoftext|>


<commit_before>// This example uses `main()` at the top so it can be read top to
// bottom. `main()` is usually at the bottom.
fn main() {
    // Create variables which will be borrowed.
    let (four, nine) = (4, 9);

    // Borrows (`&`) of both variables are passed into the function.
    // If a borrow is truly a borrow, the variable must be returned,
    // otherwise a borrow would be transferring ownership. This means
    // no matter what, *any* input which is borrowed via function or
    // otherwise, *must* still exist after the borrower ceases. In
    // other words, *Rule 2* must be true.
    print_refs(&four, &nine);

    // Uses a lifetime without any input. The lifetime sizedness will
    // be chosen by the caller (which is here) from available lifetimes
    // (scopes). Any lifetime chosen will then be larger than that of
    // the function.
    failed_borrow();
}

// `print_refs` takes two references to `i32` which have different
// lifetimes `'a` and `'b`. These two lifetimes must both be at
// least as long as the function `print_refs`.
fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
    println!("x is {} and y is {}", x, y);
}

// There are no references to force `'a` to be larger than the
// function yet, `'a` remains larger than the function.
fn failed_borrow<'a>() {
    let _x = 12;

    // Attempting to use the lifetime `'a` as an explicit type
    // annotation inside the function will fail because the
    // lifetime of `&_x` is smaller than `y` has. A small lifetime
    // cannot be coerced into a larger one.
    //
    //let y: &'a i32 = &_x;
    // ERROR: `_x` does not live long enough
}
<commit_msg>Rephrase explicit lifetime comment<commit_after>// This example uses `main()` at the top so it can be read top to
// bottom. `main()` is usually at the bottom.
fn main() {
    // Create variables which will be borrowed.
    let (four, nine) = (4, 9);

    // Borrows (`&`) of both variables are passed into the function.
    // If a borrow is truly a borrow, the variable must be returned,
    // otherwise a borrow would be transferring ownership. This means
    // no matter what, *any* input which is borrowed via function or
    // otherwise, *must* still exist after the borrower ceases. In
    // other words, *Rule 2* must be true.
    print_refs(&four, &nine);

    // Note that there is no input even though the function specifies
    // a lifetime. The sizedness of that lifetime will be determined
    // by the caller (which is here) from available lifetimes (scopes).
    // Any lifetime chosen will then be larger than that of the function.
    failed_borrow();
}

// `print_refs` takes two references to `i32` which have different
// lifetimes `'a` and `'b`. These two lifetimes must both be at
// least as long as the function `print_refs`.
fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
    println!("x is {} and y is {}", x, y);
}

// There are no references to force `'a` to be larger than the
// function yet, `'a` remains larger than the function.
fn failed_borrow<'a>() {
    let _x = 12;

    // Attempting to use the lifetime `'a` as an explicit type
    // annotation inside the function will fail because the
    // lifetime of `&_x` is smaller than `y` has. A small lifetime
    // cannot be coerced into a larger one.
    //
    //let y: &'a i32 = &_x;
    // ERROR: `_x` does not live long enough
}
<|endoftext|>