<commit_before>use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
use rustc_span::Span;

declare_lint! {
    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
    ///
    /// ### Example
    ///
    /// ```rust
    /// # #![allow(unused)]
    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
    /// ```
    ///
    /// {{produces}}
    ///
    /// ### Explanation
    ///
    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
    /// behave as `(&array).into_iter()`, returning an iterator over
    /// references, just like in Rust 1.52 and earlier.
    /// This only applies to the method call syntax `array.into_iter()`, not to
    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
    pub ARRAY_INTO_ITER,
    Warn,
    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
    @future_incompatible = FutureIncompatibleInfo {
        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
    };
}

#[derive(Copy, Clone, Default)]
pub struct ArrayIntoIter {
    for_expr_span: Span,
}

impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);

impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
        // Save the span of expressions in `for _ in expr` syntax,
        // so we can give a better suggestion for those later.
        if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
            if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
                if let hir::ExprKind::Path(hir::QPath::LangItem(
                    hir::LangItem::IntoIterIntoIter,
                    _,
                )) = &path.kind
                {
                    self.for_expr_span = arg.span;
                }
            }
        }

        // We only care about method call expressions.
        if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
            if call.ident.name != sym::into_iter {
                return;
            }

            // Check if the method call actually calls the libcore
            // `IntoIterator::into_iter`.
            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
            match cx.tcx.trait_of_item(def_id) {
                Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
                _ => return,
            };

            // As this is a method call expression, we have at least one
            // argument.
            let receiver_arg = &args[0];

            // Peel all `Box<_>` layers. We have to special case `Box` here as
            // `Box` is the only thing that values can be moved out of via
            // method call. `Box::new([1]).into_iter()` should trigger this
            // lint.
            let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
            let mut num_box_derefs = 0;
            while recv_ty.is_box() {
                num_box_derefs += 1;
                recv_ty = recv_ty.boxed_ty();
            }

            // Make sure we found an array after peeling the boxes.
            if !matches!(recv_ty.kind(), ty::Array(..)) {
                return;
            }

            // Make sure that there is an autoref coercion at the expected
            // position. The first `num_box_derefs` adjustments are the derefs
            // of the box.
            match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
                Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
                _ => return,
            }

            // Emit lint diagnostic.
            let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() {
                ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
                ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",

                // We know the original first argument type is an array type,
                // we know that the first adjustment was an autoref coercion
                // and we know that `IntoIterator` is the trait involved. The
                // array cannot be coerced to something other than a reference
                // to an array or to a slice.
                _ => bug!("array type coerced to something other than array or slice"),
            };
            cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
                let mut diag = lint.build(&format!(
                    "this method call resolves to `<&{} as IntoIterator>::into_iter` \
                    (due to backwards compatibility), \
                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
                    target, target,
                ));
                diag.span_suggestion(
                    call.ident.span,
                    "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
                    "iter".into(),
                    Applicability::MachineApplicable,
                );
                if self.for_expr_span == expr.span {
                    let expr_span = expr.span.ctxt().outer_expn_data().call_site;
                    diag.span_suggestion(
                        receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
                        "or remove `.into_iter()` to iterate by value",
                        String::new(),
                        Applicability::MaybeIncorrect,
                    );
                } else {
                    diag.multipart_suggestion(
                        "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
                        vec![
                            (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
                            (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
                        ],
                        Applicability::MaybeIncorrect,
                    );
                }
                diag.emit();
            })
        }
    }
}
<commit_msg>Upgrade array_into_iter lint to include Deref-to-array types.<commit_after>use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
use rustc_span::Span;

declare_lint! {
    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
    ///
    /// ### Example
    ///
    /// ```rust
    /// # #![allow(unused)]
    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
    /// ```
    ///
    /// {{produces}}
    ///
    /// ### Explanation
    ///
    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
    /// behave as `(&array).into_iter()`, returning an iterator over
    /// references, just like in Rust 1.52 and earlier.
    /// This only applies to the method call syntax `array.into_iter()`, not to
    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
    pub ARRAY_INTO_ITER,
    Warn,
    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
    @future_incompatible = FutureIncompatibleInfo {
        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
    };
}

#[derive(Copy, Clone, Default)]
pub struct ArrayIntoIter {
    for_expr_span: Span,
}

impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);

impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
        // Save the span of expressions in `for _ in expr` syntax,
        // so we can give a better suggestion for those later.
        if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
            if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
                if let hir::ExprKind::Path(hir::QPath::LangItem(
                    hir::LangItem::IntoIterIntoIter,
                    _,
                )) = &path.kind
                {
                    self.for_expr_span = arg.span;
                }
            }
        }

        // We only care about method call expressions.
        if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
            if call.ident.name != sym::into_iter {
                return;
            }

            // Check if the method call actually calls the libcore
            // `IntoIterator::into_iter`.
            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
            match cx.tcx.trait_of_item(def_id) {
                Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
                _ => return,
            };

            // As this is a method call expression, we have at least one argument.
            let receiver_arg = &args[0];
            let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
            let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);

            let target = match adjustments.last() {
                Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
                _ => return,
            };

            let types =
                std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));

            let mut found_array = false;

            for ty in types {
                match ty.kind() {
                    // If we run into a &[T; N] or &[T] first, there's nothing to warn about.
                    // It'll resolve to the reference version.
                    ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
                    ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
                    // Found an actual array type without matching a &[T; N] first.
                    // This is the problematic case.
                    ty::Array(..) => {
                        found_array = true;
                        break;
                    }
                    _ => {}
                }
            }

            if !found_array {
                return;
            }

            // Emit lint diagnostic.
            let target = match *target.kind() {
                ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
                ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
                // We know the original first argument type is an array type,
                // we know that the first adjustment was an autoref coercion
                // and we know that `IntoIterator` is the trait involved. The
                // array cannot be coerced to something other than a reference
                // to an array or to a slice.
                _ => bug!("array type coerced to something other than array or slice"),
            };
            cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
                let mut diag = lint.build(&format!(
                    "this method call resolves to `<&{} as IntoIterator>::into_iter` \
                    (due to backwards compatibility), \
                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
                    target, target,
                ));
                diag.span_suggestion(
                    call.ident.span,
                    "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
                    "iter".into(),
                    Applicability::MachineApplicable,
                );
                if self.for_expr_span == expr.span {
                    let expr_span = expr.span.ctxt().outer_expn_data().call_site;
                    diag.span_suggestion(
                        receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
                        "or remove `.into_iter()` to iterate by value",
                        String::new(),
                        Applicability::MaybeIncorrect,
                    );
                } else {
                    diag.multipart_suggestion(
                        "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
                        vec![
                            (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
                            (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
                        ],
                        Applicability::MaybeIncorrect,
                    );
                }
                diag.emit();
            })
        }
    }
}
<|endoftext|>


<commit_before>//! Linux-specific extensions to primitives in the `std::process` module.

#![unstable(feature = "linux_pidfd", issue = "82971")]

use crate::io::Result;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::process;
use crate::sys::fd::FileDesc;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

/// This type represents a file descriptor that refers to a process.
///
/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
///
/// Example:
/// ```no_run
/// #![feature(linux_pidfd)]
/// use std::os::linux::process::{CommandExt, ChildExt};
/// use std::process::Command;
///
/// let mut child = Command::new("echo")
///     .create_pidfd(true)
///     .spawn()
///     .expect("Failed to spawn child");
///
/// let pidfd = child
///     .take_pidfd()
///     .expect("Failed to retrieve pidfd");
///
/// // The file descriptor will be closed when `pidfd` is dropped.
/// ```
/// Refer to the man page of [`pidfd_open(2)`] for further details.
///
/// [`Command`]: process::Command
/// [`create_pidfd`]: CommandExt::create_pidfd
/// [`Child`]: process::Child
/// [`pidfd`]: fn@ChildExt::pidfd
/// [`take_pidfd`]: ChildExt::take_pidfd
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
#[derive(Debug)]
pub struct PidFd {
    inner: FileDesc,
}

impl AsInner<FileDesc> for PidFd {
    fn as_inner(&self) -> &FileDesc {
        &self.inner
    }
}

impl FromInner<FileDesc> for PidFd {
    fn from_inner(inner: FileDesc) -> PidFd {
        PidFd { inner }
    }
}

impl IntoInner<FileDesc> for PidFd {
    fn into_inner(self) -> FileDesc {
        self.inner
    }
}

impl AsRawFd for PidFd {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().raw()
    }
}

impl FromRawFd for PidFd {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Self::from_inner(FileDesc::new(fd))
    }
}

impl IntoRawFd for PidFd {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_raw()
    }
}

mod private_child_ext {
    pub trait Sealed {}
    impl Sealed for crate::process::Child {}
}

/// Os-specific extensions for [`Child`]
///
/// [`Child`]: process::Child
pub trait ChildExt: private_child_ext::Sealed {
    /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
    ///
    /// A pidfd will only be available if its creation was requested with
    /// [`create_pidfd`] when the corresponding [`Command`] was created.
    ///
    /// Even if requested, a pidfd may not be available due to an older
    /// version of Linux being in use, or if some other error occurred.
    ///
    /// [`Command`]: process::Command
    /// [`create_pidfd`]: CommandExt::create_pidfd
    /// [`Child`]: process::Child
    fn pidfd(&self) -> Result<&PidFd>;

    /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
    ///
    /// A pidfd will only be available if its creation was requested with
    /// [`create_pidfd`] when the corresponding [`Command`] was created.
    ///
    /// Even if requested, a pidfd may not be available due to an older
    /// version of Linux being in use, or if some other error occurred.
    ///
    /// [`Command`]: process::Command
    /// [`create_pidfd`]: CommandExt::create_pidfd
    /// [`Child`]: process::Child
    fn take_pidfd(&mut self) -> Result<PidFd>;
}

mod private_command_ext {
    pub trait Sealed {}
    impl Sealed for crate::process::Command {}
}

/// Os-specific extensions for [`Command`]
///
/// [`Command`]: process::Command
pub trait CommandExt: private_command_ext::Sealed {
    /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
    /// spawned by this [`Command`].
    /// By default, no pidfd will be created.
    ///
    /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
    ///
    /// A pidfd will only be created if it is possible to do so
    /// in a guaranteed race-free manner (e.g. if the `clone3` system call
    /// is supported). Otherwise, [`pidfd`] will return an error.
    ///
    /// [`Command`]: process::Command
    /// [`Child`]: process::Child
    /// [`pidfd`]: fn@ChildExt::pidfd
    /// [`take_pidfd`]: ChildExt::take_pidfd
    fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
}

impl CommandExt for process::Command {
    fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
        self.as_inner_mut().create_pidfd(val);
        self
    }
}
<commit_msg>Add dummy FileDesc struct for doc target<commit_after>//! Linux-specific extensions to primitives in the `std::process` module.

#![unstable(feature = "linux_pidfd", issue = "82971")]

use crate::io::Result;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::process;
#[cfg(not(doc))]
use crate::sys::fd::FileDesc;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

#[cfg(doc)]
struct FileDesc;

/// This type represents a file descriptor that refers to a process.
///
/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
///
/// Example:
/// ```no_run
/// #![feature(linux_pidfd)]
/// use std::os::linux::process::{CommandExt, ChildExt};
/// use std::process::Command;
///
/// let mut child = Command::new("echo")
///     .create_pidfd(true)
///     .spawn()
///     .expect("Failed to spawn child");
///
/// let pidfd = child
///     .take_pidfd()
///     .expect("Failed to retrieve pidfd");
///
/// // The file descriptor will be closed when `pidfd` is dropped.
/// ```
/// Refer to the man page of [`pidfd_open(2)`] for further details.
///
/// [`Command`]: process::Command
/// [`create_pidfd`]: CommandExt::create_pidfd
/// [`Child`]: process::Child
/// [`pidfd`]: fn@ChildExt::pidfd
/// [`take_pidfd`]: ChildExt::take_pidfd
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
#[derive(Debug)]
pub struct PidFd {
    inner: FileDesc,
}

impl AsInner<FileDesc> for PidFd {
    fn as_inner(&self) -> &FileDesc {
        &self.inner
    }
}

impl FromInner<FileDesc> for PidFd {
    fn from_inner(inner: FileDesc) -> PidFd {
        PidFd { inner }
    }
}

impl IntoInner<FileDesc> for PidFd {
    fn into_inner(self) -> FileDesc {
        self.inner
    }
}

impl AsRawFd for PidFd {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().raw()
    }
}

impl FromRawFd for PidFd {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Self::from_inner(FileDesc::new(fd))
    }
}

impl IntoRawFd for PidFd {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_raw()
    }
}

mod private_child_ext {
    pub trait Sealed {}
    impl Sealed for crate::process::Child {}
}

/// Os-specific extensions for [`Child`]
///
/// [`Child`]: process::Child
pub trait ChildExt: private_child_ext::Sealed {
    /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
    ///
    /// A pidfd will only be available if its creation was requested with
    /// [`create_pidfd`] when the corresponding [`Command`] was created.
    ///
    /// Even if requested, a pidfd may not be available due to an older
    /// version of Linux being in use, or if some other error occurred.
    ///
    /// [`Command`]: process::Command
    /// [`create_pidfd`]: CommandExt::create_pidfd
    /// [`Child`]: process::Child
    fn pidfd(&self) -> Result<&PidFd>;

    /// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
    ///
    /// A pidfd will only be available if its creation was requested with
    /// [`create_pidfd`] when the corresponding [`Command`] was created.
    ///
    /// Even if requested, a pidfd may not be available due to an older
    /// version of Linux being in use, or if some other error occurred.
    ///
    /// [`Command`]: process::Command
    /// [`create_pidfd`]: CommandExt::create_pidfd
    /// [`Child`]: process::Child
    fn take_pidfd(&mut self) -> Result<PidFd>;
}

mod private_command_ext {
    pub trait Sealed {}
    impl Sealed for crate::process::Command {}
}

/// Os-specific extensions for [`Command`]
///
/// [`Command`]: process::Command
pub trait CommandExt: private_command_ext::Sealed {
    /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
    /// spawned by this [`Command`].
    /// By default, no pidfd will be created.
    ///
    /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
    ///
    /// A pidfd will only be created if it is possible to do so
    /// in a guaranteed race-free manner (e.g. if the `clone3` system call
    /// is supported). Otherwise, [`pidfd`] will return an error.
    ///
    /// [`Command`]: process::Command
    /// [`Child`]: process::Child
    /// [`pidfd`]: fn@ChildExt::pidfd
    /// [`take_pidfd`]: ChildExt::take_pidfd
    fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
}

impl CommandExt for process::Command {
    fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
        self.as_inner_mut().create_pidfd(val);
        self
    }
}
<|endoftext|>


<commit_before>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;

pub enum BlockValidatorError {
    SszInvalid,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;
const MIN_SSZ_BLOCK_LENGTH: usize = {
    32 +    // parent_hash
    8 +     // slot_number
    32 +    // randao_reveal
    LENGTH_BYTES +     // attestations (assuming zero)
    32 +    // pow_chain_ref
    32 +    // active_state_root
    32      // crystallized_state_root
};
const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + 2^24;

pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
}

impl<'a> SszBlock<'a> {
    pub fn from_vec(vec: &'a Vec<u8>)
        -> Result<Self, BlockValidatorError>
    {
        let ssz = &vec[..];
        if vec.len() < MIN_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::SszInvalid);
        }
        if vec.len() > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::SszInvalid);
        }
        let attestation_len = decode_length(ssz, 72, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::SszInvalid)?;
        // Is the length adequate now we know now many attestation
        // records exist?
        if vec.len() < (76 + attestation_len + 96) {
            return Err(BlockValidatorError::SszInvalid);
        }
        Ok(Self{
            ssz,
            attestation_len
        })
    }

    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[0..32]
    }

    pub fn slot_number(&self) -> u64 {
        u64::ssz_decode(&self.ssz, 32).unwrap().0
    }

    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[40..72]
    }

    pub fn attestations(&self) -> &[u8] {
        let start = 72 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    pub fn pow_chain_ref(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 96)..(len - 64)]
    }

    pub fn act_state_root(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 64)..(len - 32)]
    }

    pub fn cry_state_root(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 32)..(len)]
    }
}
<commit_msg>Add SszBlock comment<commit_after>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;

pub enum BlockValidatorError {
    SszInvalid,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;
const MIN_SSZ_BLOCK_LENGTH: usize = {
    32 +    // parent_hash
    8 +     // slot_number
    32 +    // randao_reveal
    LENGTH_BYTES +     // attestations (assuming zero)
    32 +    // pow_chain_ref
    32 +    // active_state_root
    32      // crystallized_state_root
};
const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + 2^24;

/// Allows for reading of block values directly from serialized
/// ssz bytes.
pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
}

impl<'a> SszBlock<'a> {
    pub fn from_vec(vec: &'a Vec<u8>)
        -> Result<Self, BlockValidatorError>
    {
        let ssz = &vec[..];
        if vec.len() < MIN_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::SszInvalid);
        }
        if vec.len() > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::SszInvalid);
        }
        let attestation_len = decode_length(ssz, 72, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::SszInvalid)?;
        // Is the length adequate now we know now many attestation
        // records exist?
        if vec.len() < (76 + attestation_len + 96) {
            return Err(BlockValidatorError::SszInvalid);
        }
        Ok(Self{
            ssz,
            attestation_len
        })
    }

    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[0..32]
    }

    pub fn slot_number(&self) -> u64 {
        u64::ssz_decode(&self.ssz, 32).unwrap().0
    }

    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[40..72]
    }

    pub fn attestations(&self) -> &[u8] {
        let start = 72 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    pub fn pow_chain_ref(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 96)..(len - 64)]
    }

    pub fn act_state_root(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 64)..(len - 32)]
    }

    pub fn cry_state_root(&self) -> &[u8] {
        let len = self.ssz.len();
        &self.ssz[(len - 32)..(len)]
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
  pure fn traverse(f: fn((&K), (@Option<V>)));
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

/**
 * A purely functional Red-Black tree.
 *
 * A port of Matt Might's Scala port of Okasaki's RB Trees: http://matt.might.net/articles/implementation-of-immutable-purely-functional-okasaki-red-black-tree-maps-in-scala/RBMap.scala
 * which was itself a port of http://www.ccs.neu.edu/course/cs3500wc/jfp99redblack.pdf
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  /// Visit all pairs in the map in order.
  pure fn traverse(f: fn((&K), (@Option<V>))) {
    match *self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.traverse(f);
        f(&key, maybe_value);
        right.traverse(f);
      }
    }
  }

  pure fn put(k : K, v : V) -> @RBMap<K, V> {
    self.modifiedWith(k, @Some(v))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modifiedWith(k, @None)
  }

  priv pure fn blacken(n : @RBMap<K, V>) -> @RBMap<K, V> {
    match n {
      @Leaf => n,
      @Tree(_,l,k,v,r) => @Tree(Black,l,k,v,r)
    }
  }

  priv pure fn modifiedWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    self.blacken(self.modWith(k, new_value))
  }

  priv pure fn balance (c : RBColor, l : @RBMap<K,V>, k : K, v : @Option<V>, r : @RBMap<K,V>) -> @RBMap<K,V> {
    match (c,l,k,v,r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),

      (Black,@Tree(Red,a,xK,xV,@Tree(Red,b,yK,yV,c)),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),

      (Black,a,xK,xV,@Tree(Red,@Tree(Red,b,yK,yV,c),zK,zV,d)) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),

      (Black,a,xK,xV,@Tree(Red,b,yK,yV,@Tree(Red,c,zK,zV,d))) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),

      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  priv pure fn modWith (k : K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balance(color, left.modWith(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balance(color, left, key, original_value, right.modWith(k, new_value))
        }
      }
    }
  }
}

#[test]
fn test_rb_tree_create() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(187));

  let v4 = v2.put("jeremy", 16);
  assert(v4.get("jeremy") == @Some(16));
  assert(v4.get("stevej") == @Some(150));
  assert(v4.get("thatstacy") == @Some(187));
}

#[test]
fn test_traverse() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, k: int, _v: Option<int>) {
    assert (*n == k); *n += 1;
  }

  v5.traverse(|x,y| t(n, *x, *y));
}
<commit_msg>simplify our Red-Black tree into a Left-Leaning Red-Black tree<commit_after>use core::cmp::{Eq, Ord};

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> @Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
  pure fn traverse(f: fn((&K), (@Option<V>)));
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, @Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, @Some(value), @Leaf)
}

/**
 * A purely functional Left-Leaning Red-Black Tree.
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> @Option<V> {
    match self {
      @Leaf => @None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          maybe_value
        }
      }
    }
  }

  /// Visit all pairs in the map in order.
  pure fn traverse(f: fn((&K), (@Option<V>))) {
    match *self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => {
        left.traverse(f);
        f(&key, maybe_value);
        right.traverse(f);
      }
    }
  }

  pure fn put(k: K, new_value: V) -> @RBMap<K, V> {
    self.modify(k, @Some(new_value))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modify(k, @None)
  }

  priv pure fn modify(k: K, new_value: @Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balanceLeft(color, left.modify(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, new_value, right)
        } else {
          self.balanceRight(color, left, key, original_value, right.modify(k, new_value))
        }
      }
    }
  }

  priv pure fn balanceLeft(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  priv pure fn balanceRight(c: RBColor, l: @RBMap<K,V>, k: K, v: @Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black, @Tree(Red, t1, k1, v1, t2), k0, v0, @Tree(Red, t3, k2, v2, t4)) =>
        @Tree(Red, @Tree(Black, t1, k1, v1, t2), k0, v0, @Tree(Black, t3, k2, v2, t4)),
      (c, l, k, v, @Tree(Red, t1, k1, v1, t2)) =>
        @Tree(c, @Tree(Red, l, k, v, t1), k1, v1, t2),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

}

#[test]
fn test_rb_tree() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == @Some(150));
  assert(v2.get("thatstacy") == @Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == @None);
  assert(v3.get("thatstacy") == @Some(187));

  let v4 = v2.put("jeremy", 16);

  let v5 = v4.put("ev", 20);
  let v6 = v5.put("zhana", 51573);

  assert(v6.get("jeremy") == @Some(16));
  assert(v6.get("stevej") == @Some(150));
  assert(v6.get("thatstacy") == @Some(187));
  assert(v6.get("ev") == @Some(20));
  assert(v6.get("zhana") == @Some(51573));
}

#[test]
fn test_traverse() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, k: int, _v: Option<int>) {
    assert (*n == k); *n += 1;
  }

  v5.traverse(|x,y| t(n, *x, *y));
}
<|endoftext|>


<commit_before>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! ## How to use this crate
//!
//! This crate is to be used in a build script. It provides you two
//! functions, `generate_c_code` and `generate_c_interfaces`. They'll
//! allow you to generate the code to use with the `wayland_client` or
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
//! need to do it for the core protocol, which is already included in both crates).
//!
//! First, have the XML files you want to use in your project, somewhere the build script
//! will be able to read them.
//!
//! Then, you'll need to invoke both `generate_c_interfaces` *and* `generate_c_code` for
//! each of these files.
//!
//! A sample build script:
//!
//! ```no_run
//! extern crate wayland_scanner;
//!
//! use std::env::var;
//! use std::path::Path;
//!
//! use wayland_scanner::{Side, generate_c_code, generate_c_interfaces};
//!
//! fn main() {
//!     // Location of the xml file, relative to the `Cargo.toml`
//!     let protocol_file = "./my_protocol.xml";
//!
//!     // Target directory for the generate files
//!     let out_dir_str = var("OUT_DIR").unwrap();
//!     let out_dir = Path::new(&out_dir_str);
//!
//!     generate_c_code(
//!         protocol_file,
//!         out_dir.join("my_protocol_api.rs"),
//!         Side::Client, // Replace by `Side::Server` for server-side code
//!     );
//!
//!     // interfaces are the same for client and server
//!     generate_c_interfaces(
//!         protocol_file,
//!         out_dir.join("my_protocol_interfaces.rs")
//!     );
//! }
//! ```
//!
//! The above example will output two `.rs` files in the `OUT_DIR` defined by
//! cargo. Then, you'll need to include these two generated files (using the
//! macro of the same name) to make this code available in your crate.
//!
//! ```ignore
//! // The generated code will import stuff from wayland_sys
//! extern crate wayland_sys;
//! extern crate wayland_client;
//!
//! // Re-export only the actual code, and then only use this re-export
//! // The `generated` module below is just some boilerplate to properly isolate stuff
//! // and avoid exposing internal details.
//! //
//! // You can use all the types from my_procol as if they went from `wayland_client::protocol`.
//! pub use generated::client as my_protocol;
//!
//! mod generated {
//!     // The generated code tends to trigger a lot of warnings
//!     // so we isole it into a very permissive module
//!     #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
//!     #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
//!
//!     pub mod interfaces {
//!         // include the interfaces, they just need to be accessible to the generated code
//!         // so this module is `pub` so that it can be imported by the other one.
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_interfaces.rs"));
//!     }
//!
//!     pub mod client {
//!         // If you protocol interacts with objects from other protocols, you'll need to import
//!         // their modules, like so:
//!         pub(crate) use wayland_client::protocol::{wl_surface, wl_region};
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
//!     }
//! }
//! ```

#![warn(missing_docs)]

extern crate xml;

use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;

mod c_code_gen;
mod c_interface_gen;
mod common_gen;
mod parse;
mod protocol;
mod side;
mod util;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = match File::open(prot.as_ref()) {
        Ok(f) => f,
        Err(_) => panic!("Unable to open protocol file `{}`.", prot.as_ref().display()),
    };
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_c_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(target)
        .unwrap();
    c_interface_gen::generate_interfaces(protocol, &mut out).unwrap()
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_c_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(target)
        .unwrap();
    match side {
        Side::Client => c_code_gen::write_protocol_client(protocol, &mut out).unwrap(),
        Side::Server => c_code_gen::write_protocol_server(protocol, &mut out).unwrap(),
    }
}

/// Generate the interfaces for a protocol from/to IO streams
///
/// Like `generate_c_interfaces`, but takes IO Streams directly rather than filenames
///
/// Args:
///
/// - `protocol`: an object `Read`-able containing the XML protocol file
/// - `target`: a `Write`-able object to which the generated code will be outputed to
pub fn generate_c_interfaces_streams<P1: Read, P2: Write>(protocol: P1, target: &mut P2) {
    let protocol = parse::parse_stream(protocol);
    c_interface_gen::generate_interfaces(protocol, target).unwrap();
}

/// Generate the code for a protocol from/to IO streams
///
/// Like `generate_code`, but takes IO Streams directly rather than filenames
///
/// Args:
///
/// - `protocol`: an object `Read`-able containing the XML protocol file
/// - `target`: a `Write`-able object to which the generated code will be outputed to
/// - `side`: the side (client or server) to generate code for.
pub fn generate_c_code_streams<P1: Read, P2: Write>(protocol: P1, target: &mut P2, side: Side) {
    let protocol = parse::parse_stream(protocol);
    match side {
        Side::Client => c_code_gen::write_protocol_client(protocol, target).unwrap(),
        Side::Server => c_code_gen::write_protocol_server(protocol, target).unwrap(),
    }
}
<commit_msg>More idiomatic error handling<commit_after>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! ## How to use this crate
//!
//! This crate is to be used in a build script. It provides you two
//! functions, `generate_c_code` and `generate_c_interfaces`. They'll
//! allow you to generate the code to use with the `wayland_client` or
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
//! need to do it for the core protocol, which is already included in both crates).
//!
//! First, have the XML files you want to use in your project, somewhere the build script
//! will be able to read them.
//!
//! Then, you'll need to invoke both `generate_c_interfaces` *and* `generate_c_code` for
//! each of these files.
//!
//! A sample build script:
//!
//! ```no_run
//! extern crate wayland_scanner;
//!
//! use std::env::var;
//! use std::path::Path;
//!
//! use wayland_scanner::{Side, generate_c_code, generate_c_interfaces};
//!
//! fn main() {
//!     // Location of the xml file, relative to the `Cargo.toml`
//!     let protocol_file = "./my_protocol.xml";
//!
//!     // Target directory for the generate files
//!     let out_dir_str = var("OUT_DIR").unwrap();
//!     let out_dir = Path::new(&out_dir_str);
//!
//!     generate_c_code(
//!         protocol_file,
//!         out_dir.join("my_protocol_api.rs"),
//!         Side::Client, // Replace by `Side::Server` for server-side code
//!     );
//!
//!     // interfaces are the same for client and server
//!     generate_c_interfaces(
//!         protocol_file,
//!         out_dir.join("my_protocol_interfaces.rs")
//!     );
//! }
//! ```
//!
//! The above example will output two `.rs` files in the `OUT_DIR` defined by
//! cargo. Then, you'll need to include these two generated files (using the
//! macro of the same name) to make this code available in your crate.
//!
//! ```ignore
//! // The generated code will import stuff from wayland_sys
//! extern crate wayland_sys;
//! extern crate wayland_client;
//!
//! // Re-export only the actual code, and then only use this re-export
//! // The `generated` module below is just some boilerplate to properly isolate stuff
//! // and avoid exposing internal details.
//! //
//! // You can use all the types from my_procol as if they went from `wayland_client::protocol`.
//! pub use generated::client as my_protocol;
//!
//! mod generated {
//!     // The generated code tends to trigger a lot of warnings
//!     // so we isole it into a very permissive module
//!     #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
//!     #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
//!
//!     pub mod interfaces {
//!         // include the interfaces, they just need to be accessible to the generated code
//!         // so this module is `pub` so that it can be imported by the other one.
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_interfaces.rs"));
//!     }
//!
//!     pub mod client {
//!         // If you protocol interacts with objects from other protocols, you'll need to import
//!         // their modules, like so:
//!         pub(crate) use wayland_client::protocol::{wl_surface, wl_region};
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
//!     }
//! }
//! ```

#![warn(missing_docs)]

extern crate xml;

use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;

mod c_code_gen;
mod c_interface_gen;
mod common_gen;
mod parse;
mod protocol;
mod side;
mod util;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = File::open(prot.as_ref()).expect(&format!(
        "Unable to open protocol file `{}`.",
        prot.as_ref().display()
    ));
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_c_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(target)
        .unwrap();
    c_interface_gen::generate_interfaces(protocol, &mut out).unwrap()
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_c_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(target)
        .unwrap();
    match side {
        Side::Client => c_code_gen::write_protocol_client(protocol, &mut out).unwrap(),
        Side::Server => c_code_gen::write_protocol_server(protocol, &mut out).unwrap(),
    }
}

/// Generate the interfaces for a protocol from/to IO streams
///
/// Like `generate_c_interfaces`, but takes IO Streams directly rather than filenames
///
/// Args:
///
/// - `protocol`: an object `Read`-able containing the XML protocol file
/// - `target`: a `Write`-able object to which the generated code will be outputed to
pub fn generate_c_interfaces_streams<P1: Read, P2: Write>(protocol: P1, target: &mut P2) {
    let protocol = parse::parse_stream(protocol);
    c_interface_gen::generate_interfaces(protocol, target).unwrap();
}

/// Generate the code for a protocol from/to IO streams
///
/// Like `generate_code`, but takes IO Streams directly rather than filenames
///
/// Args:
///
/// - `protocol`: an object `Read`-able containing the XML protocol file
/// - `target`: a `Write`-able object to which the generated code will be outputed to
/// - `side`: the side (client or server) to generate code for.
pub fn generate_c_code_streams<P1: Read, P2: Write>(protocol: P1, target: &mut P2, side: Side) {
    let protocol = parse::parse_stream(protocol);
    match side {
        Side::Client => c_code_gen::write_protocol_client(protocol, target).unwrap(),
        Side::Server => c_code_gen::write_protocol_server(protocol, target).unwrap(),
    }
}
<|endoftext|>


<commit_before>use opencl::hl;
use opencl::hl::{Device, Context, CommandQueue};

pub struct CL {
  pub device: Device,
  pub context: Context,
  pub queue: CommandQueue,
}

impl CL {
  pub unsafe fn new() -> CL {
    for platform in hl::get_platforms().iter() {
      debug!("Found OpenCL platform: {}", platform.name());
      debug!("Available devices:");
      let devices = platform.get_devices();
      for device in devices.into_iter() {
        debug!("  {}", device.name());
        let context = device.create_context();
        let queue = context.create_command_queue(&device);

        return CL {
          device: device,
          context: context,
          queue: queue,
        };
      }
    }

    panic!("Couldn't find an OpenCL device.");
  }
}
<commit_msg>remove obsolete opencl code<commit_after><|endoftext|>


<commit_before>//! Implements a command for uploading proguard mapping files.
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use prelude::*;
use utils::{ArgExt, TempFile, copy_with_progress, make_byte_progress_bar,
            get_sha1_checksum};
use config::Config;
use api::{Api, AssociateDsyms};

use clap::{App, Arg, ArgMatches};
use uuid::Uuid;
use zip;
use proguard::MappingView;
use console::style;

#[derive(Debug)]
struct MappingRef {
    pub path: PathBuf,
    pub size: u64,
    pub uuid: Uuid,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("uploads proguard mapping files to a project")
        .org_project_args()
        .arg(Arg::with_name("paths")
            .value_name("PATH")
            .help("The path to the mapping files")
            .multiple(true)
            .number_of_values(1)
            .index(1))
        .arg(Arg::with_name("version")
             .long("version")
             .value_name("VERSION")
             .requires("app_id")
             .help("Optionally associate the mapping files with a humand \
                    readable version.  This helps you understand which \
                    proguard files go with which version of your app."))
        .arg(Arg::with_name("version_code")
             .long("version-code")
             .value_name("VERSION_CODE")
             .requires("app_id")
             .requires("version")
             .help("Optionally associate the mapping files with a version \
                    code.  This helps you understand which proguard files \
                    go with which version of your app."))
        .arg(Arg::with_name("app_id")
             .long("app-id")
             .value_name("APP_ID")
             .requires("version")
             .help("Optionally associate the mapping files with an application \
                    ID.  If you have multiple apps in one sentry project you can \
                    then easlier tell them apart."))
        .arg(Arg::with_name("no_reprocessing")
             .long("no-reprocessing")
             .help("Does not trigger reprocessing after upload"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let (org, project) = config.get_org_and_project(matches)?;
    let api = Api::new(config);

    let paths: Vec<_> = match matches.values_of("paths") {
        Some(paths) => paths.collect(),
        None => { return Ok(()); }
    };
    let mut mappings = vec![];
    let mut all_checksums = vec![];

    // since the mappings are quite small we don't bother doing a second http
    // request to figure out if any of the checksums are missing.  We just ship
    // them all up.
    for path in &paths {
        let md = fs::metadata(path)?;
        let mapping = MappingView::from_path(path)?;
        if !mapping.has_line_info() {
            println_stderr!("warning: proguard mapping '{}' was ignored because it \
                             does not contain any line information.", path);
        } else {
            let mut f = fs::File::open(path)?;
            all_checksums.push(get_sha1_checksum(&mut f)?);
            mappings.push(MappingRef {
                path: PathBuf::from(path),
                size: md.len(),
                uuid: mapping.uuid(),
            });
        }
    }

    if mappings.is_empty() {
        fail!("found no mapping files to upload");
    }

    println!("{} compressing mappings", style("[1/2]").dim());
    let tf = TempFile::new()?;

    // add a scope here so we will flush before uploading
    {
        let mut zip = zip::ZipWriter::new(tf.open());
        for mapping in &mappings {
            let pb = make_byte_progress_bar(mapping.size);
            zip.start_file(format!("proguard/{}.txt", mapping.uuid),
                           zip::write::FileOptions::default())?;
            copy_with_progress(&pb, &mut fs::File::open(&mapping.path)?, &mut zip)?;
            pb.finish_and_clear();
        }
    }

    println!("{} uploading mappings", style("[2/2]").dim());
    api.upload_dsyms(&org, &project, tf.path())?;

    println!("Uploaded a total of {} mapping files",
             style(mappings.len()).yellow());

    // if values are given associate
    if let Some(app_id) = matches.value_of("app_id") {
        api.associate_dsyms(&org, &project, &AssociateDsyms {
            // android?
            platform: "android".to_string(),
            checksums: all_checksums,
            name: app_id.to_string(),
            app_id: app_id.to_string(),
            version: matches.value_of("version").unwrap().to_string(),
            build: matches.value_of("version_code").map(|x| x.to_string()),
        })?;
    }

    // If wanted trigger reprocessing
    if !matches.is_present("no_reprocessing") {
        if !api.trigger_reprocessing(&org, &project)? {
            println!("Server does not support reprocessing. Not triggering.");
        }
    } else {
        println!("Skipped reprocessing.");
    }

    Ok(())
}
<commit_msg>Print a report of uploaded proguard files<commit_after>//! Implements a command for uploading proguard mapping files.
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use prelude::*;
use utils::{ArgExt, TempFile, copy_with_progress, make_byte_progress_bar,
            get_sha1_checksum};
use config::Config;
use api::{Api, AssociateDsyms};

use clap::{App, Arg, ArgMatches};
use uuid::Uuid;
use zip;
use proguard::MappingView;
use console::style;

#[derive(Debug)]
struct MappingRef {
    pub path: PathBuf,
    pub size: u64,
    pub uuid: Uuid,
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("uploads proguard mapping files to a project")
        .org_project_args()
        .arg(Arg::with_name("paths")
            .value_name("PATH")
            .help("The path to the mapping files")
            .multiple(true)
            .number_of_values(1)
            .index(1))
        .arg(Arg::with_name("version")
             .long("version")
             .value_name("VERSION")
             .requires("app_id")
             .help("Optionally associate the mapping files with a humand \
                    readable version.  This helps you understand which \
                    proguard files go with which version of your app."))
        .arg(Arg::with_name("version_code")
             .long("version-code")
             .value_name("VERSION_CODE")
             .requires("app_id")
             .requires("version")
             .help("Optionally associate the mapping files with a version \
                    code.  This helps you understand which proguard files \
                    go with which version of your app."))
        .arg(Arg::with_name("app_id")
             .long("app-id")
             .value_name("APP_ID")
             .requires("version")
             .help("Optionally associate the mapping files with an application \
                    ID.  If you have multiple apps in one sentry project you can \
                    then easlier tell them apart."))
        .arg(Arg::with_name("no_reprocessing")
             .long("no-reprocessing")
             .help("Does not trigger reprocessing after upload"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let (org, project) = config.get_org_and_project(matches)?;
    let api = Api::new(config);

    let paths: Vec<_> = match matches.values_of("paths") {
        Some(paths) => paths.collect(),
        None => { return Ok(()); }
    };
    let mut mappings = vec![];
    let mut all_checksums = vec![];

    // since the mappings are quite small we don't bother doing a second http
    // request to figure out if any of the checksums are missing.  We just ship
    // them all up.
    for path in &paths {
        let md = fs::metadata(path)?;
        let mapping = MappingView::from_path(path)?;
        if !mapping.has_line_info() {
            println_stderr!("warning: proguard mapping '{}' was ignored because it \
                             does not contain any line information.", path);
        } else {
            let mut f = fs::File::open(path)?;
            all_checksums.push(get_sha1_checksum(&mut f)?);
            mappings.push(MappingRef {
                path: PathBuf::from(path),
                size: md.len(),
                uuid: mapping.uuid(),
            });
        }
    }

    if mappings.is_empty() {
        fail!("found no mapping files to upload");
    }

    println!("{} compressing mappings", style("[1/2]").dim());
    let tf = TempFile::new()?;

    // add a scope here so we will flush before uploading
    {
        let mut zip = zip::ZipWriter::new(tf.open());
        for mapping in &mappings {
            let pb = make_byte_progress_bar(mapping.size);
            zip.start_file(format!("proguard/{}.txt", mapping.uuid),
                           zip::write::FileOptions::default())?;
            copy_with_progress(&pb, &mut fs::File::open(&mapping.path)?, &mut zip)?;
            pb.finish_and_clear();
        }
    }

    println!("{} uploading mappings", style("[2/2]").dim());
    let rv = api.upload_dsyms(&org, &project, tf.path())?;

    println!("Uploaded a total of {} new mapping files",
             style(rv.len()).yellow());

    if rv.len() > 0 {
        println!("Newly uploaded debug symbols:");
        for df in rv {
            println!("  {}", style(&df.uuid).dim());
        }
    }

    // if values are given associate
    if let Some(app_id) = matches.value_of("app_id") {
        api.associate_dsyms(&org, &project, &AssociateDsyms {
            // android?
            platform: "android".to_string(),
            checksums: all_checksums,
            name: app_id.to_string(),
            app_id: app_id.to_string(),
            version: matches.value_of("version").unwrap().to_string(),
            build: matches.value_of("version_code").map(|x| x.to_string()),
        })?;
    }

    // If wanted trigger reprocessing
    if !matches.is_present("no_reprocessing") {
        if !api.trigger_reprocessing(&org, &project)? {
            println!("Server does not support reprocessing. Not triggering.");
        }
    } else {
        println!("Skipped reprocessing.");
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::stderr;
use std::path::Path;
use std::process;

const PREVIEW_LEN: usize = 50;

#[derive(Debug, PartialEq)]
struct Match {
    offset: usize,
    key: u8,
    preview: String,
}

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() < 2 {
        writeln!(stderr(), "usage: roxor <file> <crib>").unwrap();
        process::exit(1);
    }

    let path = Path::new(&args[0]);
    let crib = args[1].as_bytes();

    if crib.len() < 2 {
        writeln!(stderr(), "error: crib too short").unwrap();
        process::exit(1);
    }

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(file) => file,
    };

    let mut ciphertext: Vec<u8> = Vec::new();
    file.read_to_end(&mut ciphertext).unwrap();

    if ciphertext.len() < crib.len() {
        writeln!(stderr(), "error: ciphertext too short").unwrap();
        process::exit(1);
    }

    for m in attack_cipher(&ciphertext[..], crib) {
        println!("Found text at 0x{:x} (XOR key 0x{:02x})", m.offset, m.key);
        println!("  preview: {}", m.preview);
    }
}

fn attack_cipher(ciphertext: &[u8], crib: &[u8]) -> Vec<Match> {
    let mut matches: Vec<Match> = Vec::new();
    for (i, x) in ciphertext.iter().enumerate() {
        let mut old_key = x ^ crib[0];
        let mut j = 1;
        while j < crib.len() && (i+j) < ciphertext.len() {
            let key = ciphertext[i+j] ^ crib[j];
            if key != old_key { break; }
            old_key = key;
            j += 1;
            if j == crib.len() {
                let preview: String = ciphertext[i..]
                    .iter()
                    .take(PREVIEW_LEN)
                    .map(|x| x ^ key)
                    .map(|x| if x >= 32 && x <= 126 {x as char} else {'.'})
                    .collect();
                matches.push(Match { offset: i, key: key, preview: preview });
            }
        }
    }
    return matches;
}

#[cfg(test)]
mod tests {
    use super::{Match, attack_cipher};

    struct Test {
        ciphertext: Vec<u8>,
        crib: Vec<u8>,
        matches: Vec<Match>,
    }

    #[test]
    fn test_attack_cipher() {
        let tests = vec![
            Test {
                ciphertext: vec![],
                crib: vec![],
                matches: vec![],
            },
            Test {
                ciphertext: "haystack".bytes().collect(),
                crib: "needle".bytes().collect(),
                matches: vec![],
            },
            Test {
                ciphertext: "needle in haystack".bytes().collect(),
                crib: "needle".bytes().collect(),
                matches: vec![
                    Match { offset: 0, key: 0, preview: "needle in haystack".to_string() },
                ],
            },
            Test {
                ciphertext: "a needle, another needle".bytes().collect(),
                crib: "needle".bytes().collect(),
                matches: vec![
                    Match { offset: 2, key: 0, preview: "needle, another needle".to_string() },
                    Match { offset: 18, key: 0, preview: "needle".to_string() },
                ],
            },
            Test {
                ciphertext: vec![
                    0x23, 0x62, 0x2c, 0x27, 0x27, 0x26, 0x2e, 0x27,
                    0x6e, 0x62, 0x23, 0x2c, 0x2d, 0x36, 0x2a, 0x27,
                    0x30, 0x62, 0x2c, 0x27, 0x27, 0x26, 0x2e, 0x27,
                ],
                crib: "needle".bytes().collect(),
                matches: vec![
                    Match { offset: 2, key: 0x42, preview: "needle, another needle".to_string() },
                    Match { offset: 18, key: 0x42, preview: "needle".to_string() },
                ],
            },
        ];

        for t in tests.iter() {
            assert_eq!(t.matches, attack_cipher(&t.ciphertext[..], &t.crib[..]));
        }
    }
}
<commit_msg>Use static u8 slices<commit_after>use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::stderr;
use std::path::Path;
use std::process;

const PREVIEW_LEN: usize = 50;

#[derive(Debug, PartialEq)]
struct Match {
    offset: usize,
    key: u8,
    preview: String,
}

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() < 2 {
        writeln!(stderr(), "usage: roxor <file> <crib>").unwrap();
        process::exit(1);
    }

    let path = Path::new(&args[0]);
    let crib = args[1].as_bytes();

    if crib.len() < 2 {
        writeln!(stderr(), "error: crib too short").unwrap();
        process::exit(1);
    }

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), why),
        Ok(file) => file,
    };

    let mut ciphertext: Vec<u8> = Vec::new();
    file.read_to_end(&mut ciphertext).unwrap();

    if ciphertext.len() < crib.len() {
        writeln!(stderr(), "error: ciphertext too short").unwrap();
        process::exit(1);
    }

    for m in attack_cipher(&ciphertext[..], crib) {
        println!("Found text at 0x{:x} (XOR key 0x{:02x})", m.offset, m.key);
        println!("  preview: {}", m.preview);
    }
}

fn attack_cipher(ciphertext: &[u8], crib: &[u8]) -> Vec<Match> {
    let mut matches: Vec<Match> = Vec::new();
    for (i, x) in ciphertext.iter().enumerate() {
        let mut old_key = x ^ crib[0];
        let mut j = 1;
        while j < crib.len() && (i+j) < ciphertext.len() {
            let key = ciphertext[i+j] ^ crib[j];
            if key != old_key { break; }
            old_key = key;
            j += 1;
            if j == crib.len() {
                let preview: String = ciphertext[i..]
                    .iter()
                    .take(PREVIEW_LEN)
                    .map(|x| x ^ key)
                    .map(|x| if x >= 32 && x <= 126 {x as char} else {'.'})
                    .collect();
                matches.push(Match { offset: i, key: key, preview: preview });
            }
        }
    }
    return matches;
}

#[cfg(test)]
mod tests {
    use super::{Match, attack_cipher};

    struct Test {
        ciphertext: &'static [u8],
        crib: &'static [u8],
        matches: Vec<Match>,
    }

    #[test]
    fn test_attack_cipher() {
        let tests = vec![
            Test {
                ciphertext: &[],
                crib: &[],
                matches: vec![],
            },
            Test {
                ciphertext: b"haystack",
                crib: b"needle",
                matches: vec![],
            },
            Test {
                ciphertext: b"needle in haystack",
                crib: b"needle",
                matches: vec![
                    Match { offset: 0, key: 0, preview: "needle in haystack".to_string() },
                ],
            },
            Test {
                ciphertext: b"a needle, another needle",
                crib: b"needle",
                matches: vec![
                    Match { offset: 2, key: 0, preview: "needle, another needle".to_string() },
                    Match { offset: 18, key: 0, preview: "needle".to_string() },
                ],
            },
            Test {
                ciphertext: b"\x23\x62\x2c\x27\x27\x26\x2e\x27\x6e\x62\x23\x2c\x2d\x36\x2a\x27\x30\x62\x2c\x27\x27\x26\x2e\x27",
                crib: b"needle",
                matches: vec![
                    Match { offset: 2, key: 0x42, preview: "needle, another needle".to_string() },
                    Match { offset: 18, key: 0x42, preview: "needle".to_string() },
                ],
            },
        ];

        for t in tests.iter() {
            assert_eq!(t.matches, attack_cipher(t.ciphertext, t.crib));
        }
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg};

/// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
///
/// Subcommand `rustup toolchain install` would be converted to
/// `("install", "rustup toolchain install")`.
pub fn all_subcommands(app: &App) -> Vec<(String, String)> {
    let mut subcmds: Vec<_> = subcommands(app);

    for sc_v in app.get_subcommands().map(|s| all_subcommands(s)) {
        subcmds.extend(sc_v);
    }

    subcmds
}

/// Finds the subcommand [`clap::App`] from the given [`clap::App`] with the given path.
///
/// **NOTE:** `path` should not contain the root `bin_name`.
pub fn find_subcommand_with_path<'help, 'app>(
    p: &'app App<'help>,
    path: Vec<&str>,
) -> &'app App<'help> {
    let mut app = p;

    for sc in path {
        app = app.find_subcommand(sc).unwrap();
    }

    app
}

/// Gets subcommands of [`clap::App`] in the form of `("name", "bin_name")`.
///
/// Subcommand `rustup toolchain install` would be converted to
/// `("install", "rustup toolchain install")`.
pub fn subcommands(p: &App) -> Vec<(String, String)> {
    debug!("subcommands: name={}", p.get_name());
    debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());

    let mut subcmds = vec![];

    if !p.has_subcommands() {
        return subcmds;
    }

    for sc in p.get_subcommands() {
        let sc_bin_name = sc.get_bin_name().unwrap();

        debug!(
            "subcommands:iter: name={}, bin_name={}",
            sc.get_name(),
            sc_bin_name
        );

        subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
    }

    subcmds
}

/// Gets all the short options, their visible aliases and flags of a [`clap::App`].
/// Includes `h` and `V` depending on the [`clap::AppSettings`].
pub fn shorts_and_visible_aliases(p: &App) -> Vec<char> {
    debug!("shorts: name={}", p.get_name());

    p.get_arguments()
        .filter_map(|a| {
            if a.get_index().is_none() {
                if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
                    let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
                    shorts_and_visible_aliases.push(a.get_short().unwrap());
                    Some(shorts_and_visible_aliases)
                } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
                    Some(vec![a.get_short().unwrap()])
                } else {
                    None
                }
            } else {
                None
            }
        })
        .flatten()
        .collect()
}

/// Gets all the long options, their visible aliases and flags of a [`clap::App`].
/// Includes `help` and `version` depending on the [`clap::AppSettings`].
pub fn longs_and_visible_aliases(p: &App) -> Vec<String> {
    debug!("longs: name={}", p.get_name());

    p.get_arguments()
        .filter_map(|a| {
            if a.get_index().is_none() {
                if a.get_visible_aliases().is_some() && a.get_long().is_some() {
                    let mut visible_aliases: Vec<_> = a
                        .get_visible_aliases()
                        .unwrap()
                        .into_iter()
                        .map(|s| s.to_string())
                        .collect();
                    visible_aliases.push(a.get_long().unwrap().to_string());
                    Some(visible_aliases)
                } else if a.get_visible_aliases().is_none() && a.get_long().is_some() {
                    Some(vec![a.get_long().unwrap().to_string()])
                } else {
                    None
                }
            } else {
                None
            }
        })
        .flatten()
        .collect()
}

/// Gets all the flags of a [`clap::App`](App).
/// Includes `help` and `version` depending on the [`clap::AppSettings`].
pub fn flags<'help>(p: &App<'help>) -> Vec<Arg<'help>> {
    debug!("flags: name={}", p.get_name());
    p.get_flags().cloned().collect()
}

#[cfg(test)]
mod tests {
    use super::*;
    use clap::Arg;
    use pretty_assertions::assert_eq;

    fn common_app() -> App<'static> {
        App::new("myapp")
            .subcommand(
                App::new("test").subcommand(App::new("config")).arg(
                    Arg::new("file")
                        .short('f')
                        .short_alias('c')
                        .visible_short_alias('p')
                        .long("file")
                        .visible_alias("path"),
                ),
            )
            .subcommand(App::new("hello"))
            .bin_name("my-app")
    }

    fn built() -> App<'static> {
        let mut app = common_app();

        app._build_all();
        app
    }

    fn built_with_version() -> App<'static> {
        let mut app = common_app().version("3.0");

        app._build_all();
        app
    }

    #[test]
    fn test_subcommands() {
        let app = built_with_version();

        assert_eq!(
            subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
            ]
        );
    }

    #[test]
    fn test_all_subcommands() {
        let app = built_with_version();

        assert_eq!(
            all_subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
                ("config".to_string(), "my-app test config".to_string()),
                ("help".to_string(), "my-app test help".to_string()),
            ]
        );
    }

    #[test]
    fn test_find_subcommand_with_path() {
        let app = built_with_version();
        let sc_app = find_subcommand_with_path(&app, "test config".split(' ').collect());

        assert_eq!(sc_app.get_name(), "config");
    }

    #[test]
    fn test_flags() {
        let app = built_with_version();
        let actual_flags = flags(&app);

        assert_eq!(actual_flags.len(), 2);
        assert_eq!(actual_flags[0].get_long(), Some("help"));
        assert_eq!(actual_flags[1].get_long(), Some("version"));

        let sc_flags = flags(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 2);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
    }

    #[test]
    fn test_flag_subcommand() {
        let app = built();
        let actual_flags = flags(&app);

        assert_eq!(actual_flags.len(), 1);
        assert_eq!(actual_flags[0].get_long(), Some("help"));

        let sc_flags = flags(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 2);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
    }

    #[test]
    fn test_shorts() {
        let app = built_with_version();
        let shorts = shorts_and_visible_aliases(&app);

        assert_eq!(shorts.len(), 2);
        assert_eq!(shorts[0], 'h');
        assert_eq!(shorts[1], 'V');

        let sc_shorts = shorts_and_visible_aliases(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_shorts.len(), 3);
        assert_eq!(sc_shorts[0], 'p');
        assert_eq!(sc_shorts[1], 'f');
        assert_eq!(sc_shorts[2], 'h');
    }

    #[test]
    fn test_longs() {
        let app = built_with_version();
        let longs = longs_and_visible_aliases(&app);

        assert_eq!(longs.len(), 2);
        assert_eq!(longs[0], "help");
        assert_eq!(longs[1], "version");

        let sc_longs = longs_and_visible_aliases(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_longs.len(), 3);
        assert_eq!(sc_longs[0], "path");
        assert_eq!(sc_longs[1], "file");
        assert_eq!(sc_longs[2], "help");
    }
}
<commit_msg>fix(gen): address clippy suggestion<commit_after>use clap::{App, Arg};

/// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
///
/// Subcommand `rustup toolchain install` would be converted to
/// `("install", "rustup toolchain install")`.
pub fn all_subcommands(app: &App) -> Vec<(String, String)> {
    let mut subcmds: Vec<_> = subcommands(app);

    for sc_v in app.get_subcommands().map(all_subcommands) {
        subcmds.extend(sc_v);
    }

    subcmds
}

/// Finds the subcommand [`clap::App`] from the given [`clap::App`] with the given path.
///
/// **NOTE:** `path` should not contain the root `bin_name`.
pub fn find_subcommand_with_path<'help, 'app>(
    p: &'app App<'help>,
    path: Vec<&str>,
) -> &'app App<'help> {
    let mut app = p;

    for sc in path {
        app = app.find_subcommand(sc).unwrap();
    }

    app
}

/// Gets subcommands of [`clap::App`] in the form of `("name", "bin_name")`.
///
/// Subcommand `rustup toolchain install` would be converted to
/// `("install", "rustup toolchain install")`.
pub fn subcommands(p: &App) -> Vec<(String, String)> {
    debug!("subcommands: name={}", p.get_name());
    debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());

    let mut subcmds = vec![];

    if !p.has_subcommands() {
        return subcmds;
    }

    for sc in p.get_subcommands() {
        let sc_bin_name = sc.get_bin_name().unwrap();

        debug!(
            "subcommands:iter: name={}, bin_name={}",
            sc.get_name(),
            sc_bin_name
        );

        subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
    }

    subcmds
}

/// Gets all the short options, their visible aliases and flags of a [`clap::App`].
/// Includes `h` and `V` depending on the [`clap::AppSettings`].
pub fn shorts_and_visible_aliases(p: &App) -> Vec<char> {
    debug!("shorts: name={}", p.get_name());

    p.get_arguments()
        .filter_map(|a| {
            if a.get_index().is_none() {
                if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
                    let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
                    shorts_and_visible_aliases.push(a.get_short().unwrap());
                    Some(shorts_and_visible_aliases)
                } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
                    Some(vec![a.get_short().unwrap()])
                } else {
                    None
                }
            } else {
                None
            }
        })
        .flatten()
        .collect()
}

/// Gets all the long options, their visible aliases and flags of a [`clap::App`].
/// Includes `help` and `version` depending on the [`clap::AppSettings`].
pub fn longs_and_visible_aliases(p: &App) -> Vec<String> {
    debug!("longs: name={}", p.get_name());

    p.get_arguments()
        .filter_map(|a| {
            if a.get_index().is_none() {
                if a.get_visible_aliases().is_some() && a.get_long().is_some() {
                    let mut visible_aliases: Vec<_> = a
                        .get_visible_aliases()
                        .unwrap()
                        .into_iter()
                        .map(|s| s.to_string())
                        .collect();
                    visible_aliases.push(a.get_long().unwrap().to_string());
                    Some(visible_aliases)
                } else if a.get_visible_aliases().is_none() && a.get_long().is_some() {
                    Some(vec![a.get_long().unwrap().to_string()])
                } else {
                    None
                }
            } else {
                None
            }
        })
        .flatten()
        .collect()
}

/// Gets all the flags of a [`clap::App`](App).
/// Includes `help` and `version` depending on the [`clap::AppSettings`].
pub fn flags<'help>(p: &App<'help>) -> Vec<Arg<'help>> {
    debug!("flags: name={}", p.get_name());
    p.get_flags().cloned().collect()
}

#[cfg(test)]
mod tests {
    use super::*;
    use clap::Arg;
    use pretty_assertions::assert_eq;

    fn common_app() -> App<'static> {
        App::new("myapp")
            .subcommand(
                App::new("test").subcommand(App::new("config")).arg(
                    Arg::new("file")
                        .short('f')
                        .short_alias('c')
                        .visible_short_alias('p')
                        .long("file")
                        .visible_alias("path"),
                ),
            )
            .subcommand(App::new("hello"))
            .bin_name("my-app")
    }

    fn built() -> App<'static> {
        let mut app = common_app();

        app._build_all();
        app
    }

    fn built_with_version() -> App<'static> {
        let mut app = common_app().version("3.0");

        app._build_all();
        app
    }

    #[test]
    fn test_subcommands() {
        let app = built_with_version();

        assert_eq!(
            subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
            ]
        );
    }

    #[test]
    fn test_all_subcommands() {
        let app = built_with_version();

        assert_eq!(
            all_subcommands(&app),
            vec![
                ("test".to_string(), "my-app test".to_string()),
                ("hello".to_string(), "my-app hello".to_string()),
                ("help".to_string(), "my-app help".to_string()),
                ("config".to_string(), "my-app test config".to_string()),
                ("help".to_string(), "my-app test help".to_string()),
            ]
        );
    }

    #[test]
    fn test_find_subcommand_with_path() {
        let app = built_with_version();
        let sc_app = find_subcommand_with_path(&app, "test config".split(' ').collect());

        assert_eq!(sc_app.get_name(), "config");
    }

    #[test]
    fn test_flags() {
        let app = built_with_version();
        let actual_flags = flags(&app);

        assert_eq!(actual_flags.len(), 2);
        assert_eq!(actual_flags[0].get_long(), Some("help"));
        assert_eq!(actual_flags[1].get_long(), Some("version"));

        let sc_flags = flags(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 2);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
    }

    #[test]
    fn test_flag_subcommand() {
        let app = built();
        let actual_flags = flags(&app);

        assert_eq!(actual_flags.len(), 1);
        assert_eq!(actual_flags[0].get_long(), Some("help"));

        let sc_flags = flags(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_flags.len(), 2);
        assert_eq!(sc_flags[0].get_long(), Some("file"));
        assert_eq!(sc_flags[1].get_long(), Some("help"));
    }

    #[test]
    fn test_shorts() {
        let app = built_with_version();
        let shorts = shorts_and_visible_aliases(&app);

        assert_eq!(shorts.len(), 2);
        assert_eq!(shorts[0], 'h');
        assert_eq!(shorts[1], 'V');

        let sc_shorts = shorts_and_visible_aliases(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_shorts.len(), 3);
        assert_eq!(sc_shorts[0], 'p');
        assert_eq!(sc_shorts[1], 'f');
        assert_eq!(sc_shorts[2], 'h');
    }

    #[test]
    fn test_longs() {
        let app = built_with_version();
        let longs = longs_and_visible_aliases(&app);

        assert_eq!(longs.len(), 2);
        assert_eq!(longs[0], "help");
        assert_eq!(longs[1], "version");

        let sc_longs = longs_and_visible_aliases(find_subcommand_with_path(&app, vec!["test"]));

        assert_eq!(sc_longs.len(), 3);
        assert_eq!(sc_longs[0], "path");
        assert_eq!(sc_longs[1], "file");
        assert_eq!(sc_longs[2], "help");
    }
}
<|endoftext|>