<commit_before>use std::fmt;
use std::error::Error;
use super::{
    Dimension,
};

/// An error related to array shape or layout.
#[derive(Clone, Debug)]
pub struct ShapeError {
    // we want to be able to change this representation later
    repr: ErrorKind,
}

impl ShapeError {
    /// Return the `ErrorKind` of this error.
    #[inline]
    pub fn kind(&self) -> ErrorKind {
        self.repr
    }
}

/// Error code for an error related to array shape or layout.
///
/// This enumeration is not exhaustive. The representation of the enum
/// is not guaranteed.
#[derive(Copy, Clone, Debug)]
#[repr(u64)]
pub enum ErrorKind {
    /// incompatible shape
    IncompatibleShape,
    /// incompatible memory layout
    IncompatibleLayout,
    /// the shape does not fit inside type limits
    RangeLimited,
    /// stride leads to out of bounds indexing
    OutOfBounds,
    /// stride leads to aliasing array elements
    Unsupported,
    #[doc(hidden)]
    __Incomplete,
}

#[inline(always)]
pub fn from_kind(k: ErrorKind) -> ShapeError {
    ShapeError {
        repr: k
    }
}

impl PartialEq for ErrorKind {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        *self as u64 == *rhs as u64
    }
}

impl PartialEq for ShapeError {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        self.repr == rhs.repr
    }
}

impl Error for ShapeError {
    fn description(&self) -> &str {
        match self.kind() {
            ErrorKind::IncompatibleShape => "incompatible shapes",
            ErrorKind::IncompatibleLayout => "incompatible layout (not contiguous)",
            ErrorKind::RangeLimited => "the shape does not fit in type limits",
            ErrorKind::OutOfBounds => "stride leads to out of bounds indexing",
            ErrorKind::Unsupported => "stride leads to aliasing array elements",
            ErrorKind::__Incomplete => "this error variant is not in use",
        }
    }
}

impl fmt::Display for ShapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

pub fn incompatible_shapes<D, E>(_a: &D, _b: &E) -> ShapeError
    where D: Dimension,
          E: Dimension
{
    from_kind(ErrorKind::IncompatibleShape)
}
<commit_msg>Implement better Debug for ShapeError<commit_after>use std::fmt;
use std::error::Error;
use super::{
    Dimension,
};

/// An error related to array shape or layout.
#[derive(Clone)]
pub struct ShapeError {
    // we want to be able to change this representation later
    repr: ErrorKind,
}

impl ShapeError {
    /// Return the `ErrorKind` of this error.
    #[inline]
    pub fn kind(&self) -> ErrorKind {
        self.repr
    }
}

/// Error code for an error related to array shape or layout.
///
/// This enumeration is not exhaustive. The representation of the enum
/// is not guaranteed.
#[derive(Copy, Clone, Debug)]
#[repr(u64)]
pub enum ErrorKind {
    /// incompatible shape
    IncompatibleShape,
    /// incompatible memory layout
    IncompatibleLayout,
    /// the shape does not fit inside type limits
    RangeLimited,
    /// stride leads to out of bounds indexing
    OutOfBounds,
    /// stride leads to aliasing array elements
    Unsupported,
    #[doc(hidden)]
    __Incomplete,
}

#[inline(always)]
pub fn from_kind(k: ErrorKind) -> ShapeError {
    ShapeError {
        repr: k
    }
}

impl PartialEq for ErrorKind {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        *self as u64 == *rhs as u64
    }
}

impl PartialEq for ShapeError {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        self.repr == rhs.repr
    }
}

impl Error for ShapeError {
    fn description(&self) -> &str {
        match self.kind() {
            ErrorKind::IncompatibleShape => "incompatible shapes",
            ErrorKind::IncompatibleLayout => "incompatible memory layout",
            ErrorKind::RangeLimited => "the shape does not fit in type limits",
            ErrorKind::OutOfBounds => "stride leads to out of bounds indexing",
            ErrorKind::Unsupported => "stride leads to aliasing array elements",
            ErrorKind::__Incomplete => "this error variant is not in use",
        }
    }
}

impl fmt::Display for ShapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl fmt::Debug for ShapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ShapeError {:?}: {}", self.kind(), self.description())
    }
}

pub fn incompatible_shapes<D, E>(_a: &D, _b: &E) -> ShapeError
    where D: Dimension,
          E: Dimension
{
    from_kind(ErrorKind::IncompatibleShape)
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use quote::quote;
use syn::{spanned::Spanned as _, Error, Result};

use crate::utils::{
    self, AttrParams, DeriveType, FullMetaInfo, HashSet, MetaInfo, MultiFieldData,
    State,
};

pub fn expand(
    input: &syn::DeriveInput,
    trait_name: &'static str,
) -> Result<TokenStream> {
    let syn::DeriveInput {
        ident, generics, ..
    } = input;

    let state = State::with_attr_params(
        input,
        trait_name,
        quote!(::std::error),
        trait_name.to_lowercase(),
        allowed_attr_params(),
    )?;

    let type_params: HashSet<_> = generics
        .params
        .iter()
        .filter_map(|generic| match generic {
            syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
            _ => None,
        })
        .collect();

    let (bounds, source, backtrace) = match state.derive_type {
        DeriveType::Named | DeriveType::Unnamed => render_struct(&type_params, &state)?,
        DeriveType::Enum => render_enum(&type_params, &state)?,
    };

    let source = source.map(|source| {
        quote! {
            fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
                #source
            }
        }
    });

    let backtrace = backtrace.map(|backtrace| {
        quote! {
            fn backtrace(&self) -> Option<&::std::backtrace::Backtrace> {
                #backtrace
            }
        }
    });

    let mut generics = generics.clone();

    if !type_params.is_empty() {
        let generic_parameters = generics.params.iter();
        generics = utils::add_extra_where_clauses(
            &generics,
            quote! {
                where
                    #ident<#(#generic_parameters),*>: ::std::fmt::Debug + ::std::fmt::Display
            },
        );
    }

    if !bounds.is_empty() {
        let bounds = bounds.iter();
        generics = utils::add_extra_where_clauses(
            &generics,
            quote! {
                where
                    #(#bounds: ::std::fmt::Debug + ::std::fmt::Display + ::std::error::Error + 'static),*
            },
        );
    }

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let render = quote! {
        impl#impl_generics ::std::error::Error for #ident#ty_generics #where_clause {
            #source
            #backtrace
        }
    };

    Ok(render)
}

fn render_struct(
    type_params: &HashSet<syn::Ident>,
    state: &State,
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
    let parsed_fields = parse_fields(&type_params, &state)?;

    let source = parsed_fields.render_source_as_struct();
    let backtrace = parsed_fields.render_backtrace_as_struct();

    Ok((parsed_fields.bounds, source, backtrace))
}

fn render_enum(
    type_params: &HashSet<syn::Ident>,
    state: &State,
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
    let mut bounds = HashSet::default();
    let mut source_match_arms = Vec::new();
    let mut backtrace_match_arms = Vec::new();

    for variant in state.enabled_variant_data().variants {
        let mut default_info = FullMetaInfo::default();
        default_info.enabled = true;

        let state = State::from_variant(
            state.input,
            state.trait_name,
            state.trait_module.clone(),
            state.trait_attr.clone(),
            allowed_attr_params(),
            variant,
            default_info,
        )?;

        let parsed_fields = parse_fields(&type_params, &state)?;

        if let Some(expr) = parsed_fields.render_source_as_enum_variant_match_arm() {
            source_match_arms.push(expr);
        }

        if let Some(expr) = parsed_fields.render_backtrace_as_enum_variant_match_arm() {
            backtrace_match_arms.push(expr);
        }

        bounds.extend(parsed_fields.bounds.into_iter());
    }

    let render = |match_arms: &mut Vec<TokenStream>| {
        if !match_arms.is_empty() && match_arms.len() < state.variants.len() {
            match_arms.push(quote!(_ => None));
        }

        if !match_arms.is_empty() {
            let expr = quote! {
                match self {
                    #(#match_arms),*
                }
            };

            Some(expr)
        } else {
            None
        }
    };

    let source = render(&mut source_match_arms);
    let backtrace = render(&mut backtrace_match_arms);

    Ok((bounds, source, backtrace))
}

fn allowed_attr_params() -> AttrParams {
    AttrParams {
        enum_: vec!["ignore"],
        struct_: vec!["ignore"],
        variant: vec!["ignore"],
        field: vec!["ignore", "source", "backtrace"],
    }
}

struct ParsedFields<'input, 'state> {
    data: MultiFieldData<'input, 'state>,
    source: Option<usize>,
    backtrace: Option<usize>,
    bounds: HashSet<syn::Type>,
}

impl<'input, 'state> ParsedFields<'input, 'state> {
    fn new(data: MultiFieldData<'input, 'state>) -> Self {
        Self {
            data,
            source: None,
            backtrace: None,
            bounds: HashSet::default(),
        }
    }
}

impl<'input, 'state> ParsedFields<'input, 'state> {
    fn render_source_as_struct(&self) -> Option<TokenStream> {
        let source = self.source?;
        let ident = &self.data.members[source];
        Some(render_some(quote!(&#ident)))
    }

    fn render_source_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
        let source = self.source?;
        let pattern = self.data.matcher(&[source], &[quote!(source)]);
        let expr = render_some(quote!(source));
        Some(quote!(#pattern => #expr))
    }

    fn render_backtrace_as_struct(&self) -> Option<TokenStream> {
        let backtrace = self.backtrace?;
        let backtrace_expr = &self.data.members[backtrace];
        Some(quote!(Some(&#backtrace_expr)))
    }

    fn render_backtrace_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
        let backtrace = self.backtrace?;
        let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]);
        Some(quote!(#pattern => Some(backtrace)))
    }
}

fn render_some<T>(expr: T) -> TokenStream
where
    T: quote::ToTokens,
{
    quote!(Some(#expr as &(dyn ::std::error::Error + 'static)))
}

fn parse_fields<'input, 'state>(
    type_params: &HashSet<syn::Ident>,
    state: &'state State<'input>,
) -> Result<ParsedFields<'input, 'state>> {
    let mut parsed_fields = match state.derive_type {
        DeriveType::Named => {
            parse_fields_impl(state, |attr, field, _| {
                // Unwrapping is safe, cause fields in named struct
                // always have an ident
                let ident = field.ident.as_ref().unwrap();

                match attr {
                    "source" => ident == "source",
                    "backtrace" => {
                        ident == "backtrace"
                            || is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    _ => unreachable!(),
                }
            })
        }

        DeriveType::Unnamed => {
            let mut parsed_fields =
                parse_fields_impl(state, |attr, field, len| match attr {
                    "source" => {
                        len == 1
                            && !is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    "backtrace" => {
                        is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    _ => unreachable!(),
                })?;

            parsed_fields.source = parsed_fields
                .source
                .or_else(|| infer_source_field(&state.fields, &parsed_fields));

            Ok(parsed_fields)
        }

        _ => unreachable!(),
    }?;

    if let Some(source) = parsed_fields.source {
        add_bound_if_type_parameter_used_in_type(
            &mut parsed_fields.bounds,
            type_params,
            &state.fields[source].ty,
        );
    }

    Ok(parsed_fields)
}

/// Checks if `ty` is [`syn::Type::Path`] and ends with segment matching `tail`
/// and doesn't contain any generic parameters.
fn is_type_path_ends_with_segment(ty: &syn::Type, tail: &str) -> bool {
    let ty = match ty {
        syn::Type::Path(ty) => ty,
        _ => return false,
    };

    // Unwrapping is safe, cause 'syn::TypePath.path.segments'
    // have to have at least one segment
    let segment = ty.path.segments.last().unwrap();

    match segment.arguments {
        syn::PathArguments::None => (),
        _ => return false,
    };

    segment.ident == tail
}

fn infer_source_field(
    fields: &[&syn::Field],
    parsed_fields: &ParsedFields,
) -> Option<usize> {
    // if we have exactly two fields
    if fields.len() != 2 {
        return None;
    }

    // no source field was specified/inferred
    if parsed_fields.source.is_some() {
        return None;
    }

    // but one of the fields was specified/inferred as backtrace field
    if let Some(backtrace) = parsed_fields.backtrace {
        // then infer *other field* as source field
        let source = (backtrace + 1) % 2;
        // unless it was explicitly marked as non-source
        if parsed_fields.data.infos[source].info.source != Some(false) {
            return Some(source);
        }
    }

    None
}

fn parse_fields_impl<'input, 'state, P>(
    state: &'state State<'input>,
    is_valid_default_field_for_attr: P,
) -> Result<ParsedFields<'input, 'state>>
where
    P: Fn(&str, &syn::Field, usize) -> bool,
{
    let MultiFieldData { fields, infos, .. } = state.enabled_fields_data();

    let iter = fields
        .iter()
        .zip(infos.iter().map(|info| &info.info))
        .enumerate()
        .map(|(index, (field, info))| (index, *field, info));

    let source = parse_field_impl(
        &is_valid_default_field_for_attr,
        state.fields.len(),
        iter.clone(),
        "source",
        |info| info.source,
    )?;

    let backtrace = parse_field_impl(
        &is_valid_default_field_for_attr,
        state.fields.len(),
        iter.clone(),
        "backtrace",
        |info| info.backtrace,
    )?;

    let mut parsed_fields = ParsedFields::new(state.enabled_fields_data());

    if let Some((index, _, _)) = source {
        parsed_fields.source = Some(index);
    }

    if let Some((index, _, _)) = backtrace {
        parsed_fields.backtrace = Some(index);
    }

    Ok(parsed_fields)
}

fn parse_field_impl<'a, P, V>(
    is_valid_default_field_for_attr: &P,
    len: usize,
    iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)> + Clone,
    attr: &str,
    value: V,
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>>
where
    P: Fn(&str, &syn::Field, usize) -> bool,
    V: Fn(&MetaInfo) -> Option<bool>,
{
    let explicit_fields = iter.clone().filter(|(_, _, info)| match value(info) {
        Some(true) => true,
        _ => false,
    });

    let inferred_fields = iter.filter(|(_, field, info)| match value(info) {
        None => is_valid_default_field_for_attr(attr, field, len),
        _ => false,
    });

    let field = assert_iter_contains_zero_or_one_item(
        explicit_fields,
        &format!(
            "Multiple `{}` attributes specified. \
             Single attribute per struct/enum variant allowed.",
            attr
        ),
    )?;

    let field = match field {
        field @ Some(_) => field,
        None => assert_iter_contains_zero_or_one_item(
            inferred_fields,
            "Conflicting fields found. Consider specifying some \
             `#[error(...)]` attributes to resolve conflict.",
        )?,
    };

    Ok(field)
}

fn assert_iter_contains_zero_or_one_item<'a>(
    mut iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)>,
    error_msg: &str,
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>> {
    let item = match iter.next() {
        Some(item) => item,
        None => return Ok(None),
    };

    if let Some((_, field, _)) = iter.next() {
        return Err(Error::new(field.span(), error_msg));
    }

    Ok(Some(item))
}

fn add_bound_if_type_parameter_used_in_type(
    bounds: &mut HashSet<syn::Type>,
    type_params: &HashSet<syn::Ident>,
    ty: &syn::Type,
) {
    if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) {
        bounds.insert(ty);
    }
}
<commit_msg>Make Clippy happy again!<commit_after>use proc_macro2::TokenStream;
use quote::quote;
use syn::{spanned::Spanned as _, Error, Result};

use crate::utils::{
    self, AttrParams, DeriveType, FullMetaInfo, HashSet, MetaInfo, MultiFieldData,
    State,
};

pub fn expand(
    input: &syn::DeriveInput,
    trait_name: &'static str,
) -> Result<TokenStream> {
    let syn::DeriveInput {
        ident, generics, ..
    } = input;

    let state = State::with_attr_params(
        input,
        trait_name,
        quote!(::std::error),
        trait_name.to_lowercase(),
        allowed_attr_params(),
    )?;

    let type_params: HashSet<_> = generics
        .params
        .iter()
        .filter_map(|generic| match generic {
            syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
            _ => None,
        })
        .collect();

    let (bounds, source, backtrace) = match state.derive_type {
        DeriveType::Named | DeriveType::Unnamed => render_struct(&type_params, &state)?,
        DeriveType::Enum => render_enum(&type_params, &state)?,
    };

    let source = source.map(|source| {
        quote! {
            fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
                #source
            }
        }
    });

    let backtrace = backtrace.map(|backtrace| {
        quote! {
            fn backtrace(&self) -> Option<&::std::backtrace::Backtrace> {
                #backtrace
            }
        }
    });

    let mut generics = generics.clone();

    if !type_params.is_empty() {
        let generic_parameters = generics.params.iter();
        generics = utils::add_extra_where_clauses(
            &generics,
            quote! {
                where
                    #ident<#(#generic_parameters),*>: ::std::fmt::Debug + ::std::fmt::Display
            },
        );
    }

    if !bounds.is_empty() {
        let bounds = bounds.iter();
        generics = utils::add_extra_where_clauses(
            &generics,
            quote! {
                where
                    #(#bounds: ::std::fmt::Debug + ::std::fmt::Display + ::std::error::Error + 'static),*
            },
        );
    }

    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let render = quote! {
        impl#impl_generics ::std::error::Error for #ident#ty_generics #where_clause {
            #source
            #backtrace
        }
    };

    Ok(render)
}

fn render_struct(
    type_params: &HashSet<syn::Ident>,
    state: &State,
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
    let parsed_fields = parse_fields(&type_params, &state)?;

    let source = parsed_fields.render_source_as_struct();
    let backtrace = parsed_fields.render_backtrace_as_struct();

    Ok((parsed_fields.bounds, source, backtrace))
}

fn render_enum(
    type_params: &HashSet<syn::Ident>,
    state: &State,
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
    let mut bounds = HashSet::default();
    let mut source_match_arms = Vec::new();
    let mut backtrace_match_arms = Vec::new();

    for variant in state.enabled_variant_data().variants {
        let default_info = FullMetaInfo {
            enabled: true,
            ..FullMetaInfo::default()
        };

        let state = State::from_variant(
            state.input,
            state.trait_name,
            state.trait_module.clone(),
            state.trait_attr.clone(),
            allowed_attr_params(),
            variant,
            default_info,
        )?;

        let parsed_fields = parse_fields(&type_params, &state)?;

        if let Some(expr) = parsed_fields.render_source_as_enum_variant_match_arm() {
            source_match_arms.push(expr);
        }

        if let Some(expr) = parsed_fields.render_backtrace_as_enum_variant_match_arm() {
            backtrace_match_arms.push(expr);
        }

        bounds.extend(parsed_fields.bounds.into_iter());
    }

    let render = |match_arms: &mut Vec<TokenStream>| {
        if !match_arms.is_empty() && match_arms.len() < state.variants.len() {
            match_arms.push(quote!(_ => None));
        }

        if !match_arms.is_empty() {
            let expr = quote! {
                match self {
                    #(#match_arms),*
                }
            };

            Some(expr)
        } else {
            None
        }
    };

    let source = render(&mut source_match_arms);
    let backtrace = render(&mut backtrace_match_arms);

    Ok((bounds, source, backtrace))
}

fn allowed_attr_params() -> AttrParams {
    AttrParams {
        enum_: vec!["ignore"],
        struct_: vec!["ignore"],
        variant: vec!["ignore"],
        field: vec!["ignore", "source", "backtrace"],
    }
}

struct ParsedFields<'input, 'state> {
    data: MultiFieldData<'input, 'state>,
    source: Option<usize>,
    backtrace: Option<usize>,
    bounds: HashSet<syn::Type>,
}

impl<'input, 'state> ParsedFields<'input, 'state> {
    fn new(data: MultiFieldData<'input, 'state>) -> Self {
        Self {
            data,
            source: None,
            backtrace: None,
            bounds: HashSet::default(),
        }
    }
}

impl<'input, 'state> ParsedFields<'input, 'state> {
    fn render_source_as_struct(&self) -> Option<TokenStream> {
        let source = self.source?;
        let ident = &self.data.members[source];
        Some(render_some(quote!(&#ident)))
    }

    fn render_source_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
        let source = self.source?;
        let pattern = self.data.matcher(&[source], &[quote!(source)]);
        let expr = render_some(quote!(source));
        Some(quote!(#pattern => #expr))
    }

    fn render_backtrace_as_struct(&self) -> Option<TokenStream> {
        let backtrace = self.backtrace?;
        let backtrace_expr = &self.data.members[backtrace];
        Some(quote!(Some(&#backtrace_expr)))
    }

    fn render_backtrace_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
        let backtrace = self.backtrace?;
        let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]);
        Some(quote!(#pattern => Some(backtrace)))
    }
}

fn render_some<T>(expr: T) -> TokenStream
where
    T: quote::ToTokens,
{
    quote!(Some(#expr as &(dyn ::std::error::Error + 'static)))
}

fn parse_fields<'input, 'state>(
    type_params: &HashSet<syn::Ident>,
    state: &'state State<'input>,
) -> Result<ParsedFields<'input, 'state>> {
    let mut parsed_fields = match state.derive_type {
        DeriveType::Named => {
            parse_fields_impl(state, |attr, field, _| {
                // Unwrapping is safe, cause fields in named struct
                // always have an ident
                let ident = field.ident.as_ref().unwrap();

                match attr {
                    "source" => ident == "source",
                    "backtrace" => {
                        ident == "backtrace"
                            || is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    _ => unreachable!(),
                }
            })
        }

        DeriveType::Unnamed => {
            let mut parsed_fields =
                parse_fields_impl(state, |attr, field, len| match attr {
                    "source" => {
                        len == 1
                            && !is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    "backtrace" => {
                        is_type_path_ends_with_segment(&field.ty, "Backtrace")
                    }
                    _ => unreachable!(),
                })?;

            parsed_fields.source = parsed_fields
                .source
                .or_else(|| infer_source_field(&state.fields, &parsed_fields));

            Ok(parsed_fields)
        }

        _ => unreachable!(),
    }?;

    if let Some(source) = parsed_fields.source {
        add_bound_if_type_parameter_used_in_type(
            &mut parsed_fields.bounds,
            type_params,
            &state.fields[source].ty,
        );
    }

    Ok(parsed_fields)
}

/// Checks if `ty` is [`syn::Type::Path`] and ends with segment matching `tail`
/// and doesn't contain any generic parameters.
fn is_type_path_ends_with_segment(ty: &syn::Type, tail: &str) -> bool {
    let ty = match ty {
        syn::Type::Path(ty) => ty,
        _ => return false,
    };

    // Unwrapping is safe, cause 'syn::TypePath.path.segments'
    // have to have at least one segment
    let segment = ty.path.segments.last().unwrap();

    match segment.arguments {
        syn::PathArguments::None => (),
        _ => return false,
    };

    segment.ident == tail
}

fn infer_source_field(
    fields: &[&syn::Field],
    parsed_fields: &ParsedFields,
) -> Option<usize> {
    // if we have exactly two fields
    if fields.len() != 2 {
        return None;
    }

    // no source field was specified/inferred
    if parsed_fields.source.is_some() {
        return None;
    }

    // but one of the fields was specified/inferred as backtrace field
    if let Some(backtrace) = parsed_fields.backtrace {
        // then infer *other field* as source field
        let source = (backtrace + 1) % 2;
        // unless it was explicitly marked as non-source
        if parsed_fields.data.infos[source].info.source != Some(false) {
            return Some(source);
        }
    }

    None
}

fn parse_fields_impl<'input, 'state, P>(
    state: &'state State<'input>,
    is_valid_default_field_for_attr: P,
) -> Result<ParsedFields<'input, 'state>>
where
    P: Fn(&str, &syn::Field, usize) -> bool,
{
    let MultiFieldData { fields, infos, .. } = state.enabled_fields_data();

    let iter = fields
        .iter()
        .zip(infos.iter().map(|info| &info.info))
        .enumerate()
        .map(|(index, (field, info))| (index, *field, info));

    let source = parse_field_impl(
        &is_valid_default_field_for_attr,
        state.fields.len(),
        iter.clone(),
        "source",
        |info| info.source,
    )?;

    let backtrace = parse_field_impl(
        &is_valid_default_field_for_attr,
        state.fields.len(),
        iter.clone(),
        "backtrace",
        |info| info.backtrace,
    )?;

    let mut parsed_fields = ParsedFields::new(state.enabled_fields_data());

    if let Some((index, _, _)) = source {
        parsed_fields.source = Some(index);
    }

    if let Some((index, _, _)) = backtrace {
        parsed_fields.backtrace = Some(index);
    }

    Ok(parsed_fields)
}

fn parse_field_impl<'a, P, V>(
    is_valid_default_field_for_attr: &P,
    len: usize,
    iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)> + Clone,
    attr: &str,
    value: V,
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>>
where
    P: Fn(&str, &syn::Field, usize) -> bool,
    V: Fn(&MetaInfo) -> Option<bool>,
{
    let explicit_fields = iter.clone().filter(|(_, _, info)| match value(info) {
        Some(true) => true,
        _ => false,
    });

    let inferred_fields = iter.filter(|(_, field, info)| match value(info) {
        None => is_valid_default_field_for_attr(attr, field, len),
        _ => false,
    });

    let field = assert_iter_contains_zero_or_one_item(
        explicit_fields,
        &format!(
            "Multiple `{}` attributes specified. \
             Single attribute per struct/enum variant allowed.",
            attr
        ),
    )?;

    let field = match field {
        field @ Some(_) => field,
        None => assert_iter_contains_zero_or_one_item(
            inferred_fields,
            "Conflicting fields found. Consider specifying some \
             `#[error(...)]` attributes to resolve conflict.",
        )?,
    };

    Ok(field)
}

fn assert_iter_contains_zero_or_one_item<'a>(
    mut iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)>,
    error_msg: &str,
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>> {
    let item = match iter.next() {
        Some(item) => item,
        None => return Ok(None),
    };

    if let Some((_, field, _)) = iter.next() {
        return Err(Error::new(field.span(), error_msg));
    }

    Ok(Some(item))
}

fn add_bound_if_type_parameter_used_in_type(
    bounds: &mut HashSet<syn::Type>,
    type_params: &HashSet<syn::Ident>,
    ty: &syn::Type,
) {
    if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) {
        bounds.insert(ty);
    }
}
<|endoftext|>


<commit_before>#[cfg(not(target_os = "wasi"))]
use nix;
use std::convert;
use std::fmt;
use std::io;

#[derive(Debug)]
pub enum Error {
    /// Simple IO error
    Io(io::Error),
    /// Read unusual data from sysfs file.
    Unexpected(String),
    /// Invalid Path
    InvalidPath(String),
    /// Operation not supported on target os
    Unsupported(String),
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref e) => e.description(),
            Error::Unexpected(_) => "An Unexpected Error Occurred",
            Error::InvalidPath(_) => "A Provided Path was invalid",
            Error::Unsupported(_) => "Operation is not supported on target os",
        }
    }

    fn cause(&self) -> Option<&dyn std::error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Unexpected(ref s) => write!(f, "Unexpected: {}", s),
            Error::InvalidPath(ref s) => write!(f, "Invalid Path: {}", s),
            Error::Unsupported(ref s) => write!(f, "Operation not supported on target os: {}", s),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}
#[cfg(not(target_os = "wasi"))]
impl convert::From<nix::Error> for Error {
    fn from(e: nix::Error) -> Error {
        match e {
            nix::Error::Sys(errno) => Error::Io(errno.into()),
            other => Error::Unexpected(format!("{:?}", other)), // should just be dealing with errno case
        }
    }
}
<commit_msg>Align error implementation with current best practices<commit_after>#[cfg(not(target_os = "wasi"))]
use nix;
use std::convert;
use std::fmt;
use std::io;

#[derive(Debug)]
pub enum Error {
    /// Simple IO error
    Io(io::Error),
    /// Read unusual data from sysfs file.
    Unexpected(String),
    /// Invalid Path
    InvalidPath(String),
    /// Operation not supported on target os
    Unsupported(String),
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&dyn std::error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Unexpected(ref s) => write!(f, "Unexpected: {}", s),
            Error::InvalidPath(ref s) => write!(f, "Invalid Path: {}", s),
            Error::Unsupported(ref s) => write!(f, "Operation not supported on target os: {}", s),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::Io(e)
    }
}
#[cfg(not(target_os = "wasi"))]
impl convert::From<nix::Error> for Error {
    fn from(e: nix::Error) -> Error {
        match e {
            nix::Error::Sys(errno) => Error::Io(errno.into()),
            other => Error::Unexpected(format!("{:?}", other)), // should just be dealing with errno case
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{c_char, c_int};
use crate::defines::AfError;
use crate::util::{free_host, DimT, MutDimT};
use std::error::Error;
use std::ffi::CStr;
use std::ops::{Deref, DerefMut};
use std::sync::RwLock;

#[allow(dead_code)]
extern "C" {
    fn af_get_last_error(str: *mut *mut c_char, len: *mut DimT) -> c_int;
}

/// Signature of error handling callback function
pub type ErrorCallback = fn(AfError);

/// Structure holding handle to callback function
pub struct Callback {
    cb: ErrorCallback,
}

impl Callback {
    /// Associated function to create a new Callback object
    pub fn new(callback: ErrorCallback) -> Self {
        Self { cb: callback }
    }

    /// call invokes the error callback with `error_code`.
    pub fn call(&self, error_code: AfError) {
        (self.cb)(error_code)
    }
}

/// Default error handling callback provided by ArrayFire crate
pub fn handle_error_general(error_code: AfError) {
    match error_code {
        AfError::SUCCESS => {} /* No-op */
        _ => panic!(
            "Error message: {}\nLast error: {}",
            error_code.description(),
            get_last_error()
        ),
    }
}

lazy_static! {
    static ref ERROR_HANDLER_LOCK: RwLock<Callback> =
        RwLock::new(Callback::new(handle_error_general));
}

/// Register user provided error handler
///
/// # Examples
/// ```
/// #[macro_use]
/// extern crate arrayfire;
///
/// use arrayfire::{AfError, Callback, info, register_error_handler};
/// use std::error::Error;
///
/// fn handleError(error_code: AfError) {
///     match error_code {
///         AfError::SUCCESS => {}, /* No-op */
///         _ => panic!("Error message: {}", error_code.description()),
///     }
/// }
///
/// fn main() {
///     //Registering the error handler should be the first call
///     //before any other functions are called if your version
///     //of error is to be used for subsequent function calls
///     register_error_handler(Callback::new(handleError));
///
///     info();
/// }
/// ```
#[allow(unused_must_use)]
#[allow(clippy::match_wild_err_arm)]
pub fn register_error_handler(cb_value: Callback) {
    let mut gaurd = match ERROR_HANDLER_LOCK.write() {
        Ok(g) => g,
        Err(_) => panic!("Failed to acquire lock to register error handler"),
    };

    *gaurd.deref_mut() = cb_value;
}

#[allow(non_snake_case)]
#[allow(clippy::match_wild_err_arm)]
pub fn HANDLE_ERROR(error_code: AfError) {
    let gaurd = match ERROR_HANDLER_LOCK.read() {
        Ok(g) => g,
        Err(_) => panic!("Failed to acquire lock while handling FFI return value"),
    };

    (*gaurd.deref()).call(error_code);
}

pub fn get_last_error() -> String {
    let result: String;
    unsafe {
        let mut tmp: *mut c_char = ::std::ptr::null_mut();
        let mut len: DimT = 0;
        let err_val = af_get_last_error(&mut tmp, &mut len as MutDimT);
        HANDLE_ERROR(AfError::from(err_val));
        result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
        free_host(tmp);
    }
    result
}
<commit_msg>Fix unchecked string creation from ffi return value<commit_after>extern crate libc;

use self::libc::c_char;
use crate::defines::AfError;
use crate::util::{free_host, DimT, MutDimT};
use std::error::Error;
use std::ffi::CStr;
use std::ops::{Deref, DerefMut};
use std::sync::RwLock;

#[allow(dead_code)]
extern "C" {
    fn af_get_last_error(str: *mut *mut c_char, len: *mut DimT);
}

/// Signature of error handling callback function
pub type ErrorCallback = fn(AfError);

/// Structure holding handle to callback function
pub struct Callback {
    cb: ErrorCallback,
}

impl Callback {
    /// Associated function to create a new Callback object
    pub fn new(callback: ErrorCallback) -> Self {
        Self { cb: callback }
    }

    /// call invokes the error callback with `error_code`.
    pub fn call(&self, error_code: AfError) {
        (self.cb)(error_code)
    }
}

/// Default error handling callback provided by ArrayFire crate
pub fn handle_error_general(error_code: AfError) {
    match error_code {
        AfError::SUCCESS => {} /* No-op */
        _ => panic!(
            "Error message: {}\nLast error: {}",
            error_code.description(),
            get_last_error()
        ),
    }
}

lazy_static! {
    static ref ERROR_HANDLER_LOCK: RwLock<Callback> =
        RwLock::new(Callback::new(handle_error_general));
}

/// Register user provided error handler
///
/// # Examples
/// ```
/// #[macro_use]
/// extern crate arrayfire;
///
/// use arrayfire::{AfError, Callback, info, register_error_handler};
/// use std::error::Error;
///
/// fn handleError(error_code: AfError) {
///     match error_code {
///         AfError::SUCCESS => {}, /* No-op */
///         _ => panic!("Error message: {}", error_code.description()),
///     }
/// }
///
/// fn main() {
///     //Registering the error handler should be the first call
///     //before any other functions are called if your version
///     //of error is to be used for subsequent function calls
///     register_error_handler(Callback::new(handleError));
///
///     info();
/// }
/// ```
#[allow(unused_must_use)]
#[allow(clippy::match_wild_err_arm)]
pub fn register_error_handler(cb_value: Callback) {
    let mut gaurd = match ERROR_HANDLER_LOCK.write() {
        Ok(g) => g,
        Err(_) => panic!("Failed to acquire lock to register error handler"),
    };

    *gaurd.deref_mut() = cb_value;
}

#[allow(non_snake_case)]
#[allow(clippy::match_wild_err_arm)]
pub fn HANDLE_ERROR(error_code: AfError) {
    let gaurd = match ERROR_HANDLER_LOCK.read() {
        Ok(g) => g,
        Err(_) => panic!("Failed to acquire lock while handling FFI return value"),
    };

    (*gaurd.deref()).call(error_code);
}

pub fn get_last_error() -> String {
    let mut result: String = String::from("No Last Error");
    let mut tmp: *mut c_char = ::std::ptr::null_mut();
    let mut len: DimT = 0;
    unsafe {
        af_get_last_error(&mut tmp, &mut len as MutDimT);
        if len > 0 {
            result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
            free_host(tmp);
        }
    }
    result
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::path::PathBuf;
use std::str;
use libc::c_int;
use {ffi, errmsg_to_string};

/// Old name for `Error`. `SqliteError` is deprecated.
pub type SqliteError = Error;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was configured to
    /// allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// An error case available for implementors of the `FromSql` trait.
    FromSqlConversionFailure(Box<error::Error + Send + Sync>),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g., for `query_row`)
    /// did not return any.
    QueryReturnedNoRows,

    /// Error when trying to access a `Row` after stepping past it. See the discussion on
    /// the `Rows` type for more details.
    GetFromStaleRow,

    /// Error when the value of a particular column is requested, but the index is out of range
    /// for the statement.
    InvalidColumnIndex(c_int),

    /// Error when the value of a named column is requested, but no column matches the name
    /// for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type of the result in
    /// that column cannot be converted to the requested Rust type.
    InvalidColumnType,

    /// Error returned by `functions::Context::get` when the function argument cannot be converted
    /// to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType,

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<error::Error + Send + Sync>),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => {
                write!(f,
                       "SQLite was compiled or configured for single-threaded use only")
            }
            Error::FromSqlConversionFailure(ref err) => err.fmt(f),
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::GetFromStaleRow => write!(f, "Attempted to get a value from a stale row"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType => write!(f, "Invalid column type"),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => write!(f, "Invalid function parameter type"),
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(ref err) => err.description(),
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::GetFromStaleRow => "attempted to get a value from a stale row",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType => "invalid column type",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => "invalid function parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
        }
    }

    #[allow(match_same_arms)]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::FromSqlConversionFailure(ref err) => Some(&**err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::SqliteSingleThreadedMode |
            Error::InvalidParameterName(_) |
            Error::ExecuteReturnedResults |
            Error::QueryReturnedNoRows |
            Error::GetFromStaleRow |
            Error::InvalidColumnIndex(_) |
            Error::InvalidColumnName(_) |
            Error::InvalidColumnType |
            Error::InvalidPath(_) => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::Struct_sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}
<commit_msg>Move clippy allowance behind a cfg_attr<commit_after>use std::error;
use std::fmt;
use std::path::PathBuf;
use std::str;
use libc::c_int;
use {ffi, errmsg_to_string};

/// Old name for `Error`. `SqliteError` is deprecated.
pub type SqliteError = Error;

/// Enum listing possible errors from rusqlite.
#[derive(Debug)]
pub enum Error {
    /// An error from an underlying SQLite call.
    SqliteFailure(ffi::Error, Option<String>),

    /// Error reported when attempting to open a connection when SQLite was configured to
    /// allow single-threaded use only.
    SqliteSingleThreadedMode,

    /// An error case available for implementors of the `FromSql` trait.
    FromSqlConversionFailure(Box<error::Error + Send + Sync>),

    /// Error converting a string to UTF-8.
    Utf8Error(str::Utf8Error),

    /// Error converting a string to a C-compatible string because it contained an embedded nul.
    NulError(::std::ffi::NulError),

    /// Error when using SQL named parameters and passing a parameter name not present in the SQL.
    InvalidParameterName(String),

    /// Error converting a file path to a string.
    InvalidPath(PathBuf),

    /// Error returned when an `execute` call returns rows.
    ExecuteReturnedResults,

    /// Error when a query that was expected to return at least one row (e.g., for `query_row`)
    /// did not return any.
    QueryReturnedNoRows,

    /// Error when trying to access a `Row` after stepping past it. See the discussion on
    /// the `Rows` type for more details.
    GetFromStaleRow,

    /// Error when the value of a particular column is requested, but the index is out of range
    /// for the statement.
    InvalidColumnIndex(c_int),

    /// Error when the value of a named column is requested, but no column matches the name
    /// for the statement.
    InvalidColumnName(String),

    /// Error when the value of a particular column is requested, but the type of the result in
    /// that column cannot be converted to the requested Rust type.
    InvalidColumnType,

    /// Error returned by `functions::Context::get` when the function argument cannot be converted
    /// to the requested type.
    #[cfg(feature = "functions")]
    InvalidFunctionParameterType,

    /// An error case available for implementors of custom user functions (e.g.,
    /// `create_scalar_function`).
    #[cfg(feature = "functions")]
    #[allow(dead_code)]
    UserFunctionError(Box<error::Error + Send + Sync>),
}

impl From<str::Utf8Error> for Error {
    fn from(err: str::Utf8Error) -> Error {
        Error::Utf8Error(err)
    }
}

impl From<::std::ffi::NulError> for Error {
    fn from(err: ::std::ffi::NulError) -> Error {
        Error::NulError(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::SqliteFailure(ref err, None) => err.fmt(f),
            Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
            Error::SqliteSingleThreadedMode => {
                write!(f,
                       "SQLite was compiled or configured for single-threaded use only")
            }
            Error::FromSqlConversionFailure(ref err) => err.fmt(f),
            Error::Utf8Error(ref err) => err.fmt(f),
            Error::NulError(ref err) => err.fmt(f),
            Error::InvalidParameterName(ref name) => write!(f, "Invalid parameter name: {}", name),
            Error::InvalidPath(ref p) => write!(f, "Invalid path: {}", p.to_string_lossy()),
            Error::ExecuteReturnedResults => {
                write!(f, "Execute returned results - did you mean to call query?")
            }
            Error::QueryReturnedNoRows => write!(f, "Query returned no rows"),
            Error::GetFromStaleRow => write!(f, "Attempted to get a value from a stale row"),
            Error::InvalidColumnIndex(i) => write!(f, "Invalid column index: {}", i),
            Error::InvalidColumnName(ref name) => write!(f, "Invalid column name: {}", name),
            Error::InvalidColumnType => write!(f, "Invalid column type"),

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => write!(f, "Invalid function parameter type"),
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::SqliteFailure(ref err, None) => err.description(),
            Error::SqliteFailure(_, Some(ref s)) => s,
            Error::SqliteSingleThreadedMode => {
                "SQLite was compiled or configured for single-threaded use only"
            }
            Error::FromSqlConversionFailure(ref err) => err.description(),
            Error::Utf8Error(ref err) => err.description(),
            Error::InvalidParameterName(_) => "invalid parameter name",
            Error::NulError(ref err) => err.description(),
            Error::InvalidPath(_) => "invalid path",
            Error::ExecuteReturnedResults => {
                "execute returned results - did you mean to call query?"
            }
            Error::QueryReturnedNoRows => "query returned no rows",
            Error::GetFromStaleRow => "attempted to get a value from a stale row",
            Error::InvalidColumnIndex(_) => "invalid column index",
            Error::InvalidColumnName(_) => "invalid column name",
            Error::InvalidColumnType => "invalid column type",

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => "invalid function parameter type",
            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => err.description(),
        }
    }

    #[cfg_attr(feature="clippy", allow(match_same_arms))]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::SqliteFailure(ref err, _) => Some(err),
            Error::FromSqlConversionFailure(ref err) => Some(&**err),
            Error::Utf8Error(ref err) => Some(err),
            Error::NulError(ref err) => Some(err),

            Error::SqliteSingleThreadedMode |
            Error::InvalidParameterName(_) |
            Error::ExecuteReturnedResults |
            Error::QueryReturnedNoRows |
            Error::GetFromStaleRow |
            Error::InvalidColumnIndex(_) |
            Error::InvalidColumnName(_) |
            Error::InvalidColumnType |
            Error::InvalidPath(_) => None,

            #[cfg(feature = "functions")]
            Error::InvalidFunctionParameterType => None,

            #[cfg(feature = "functions")]
            Error::UserFunctionError(ref err) => Some(&**err),
        }
    }
}

// These are public but not re-exported by lib.rs, so only visible within crate.

pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
    Error::SqliteFailure(ffi::Error::new(code), message)
}

pub fn error_from_handle(db: *mut ffi::Struct_sqlite3, code: c_int) -> Error {
    let message = if db.is_null() {
        None
    } else {
        Some(unsafe { errmsg_to_string(ffi::sqlite3_errmsg(db)) })
    };
    error_from_sqlite_code(code, message)
}
<|endoftext|>


<commit_before>use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use geometry::CGPoint;
use event_source::{CGEventSource,CGEventSourceRef};

use libc;
use std::mem;
use std::ptr;

pub type CGKeyCode = libc::uint16_t;

/// Flags for events
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
bitflags! {
    pub flags CGEventFlags: u64 {
        const Null = 0,

        // Device-independent modifier key bits.
        const AlphaShift = 0x00010000,
        const Shift = 0x00020000,
        const Control = 0x00040000,
        const Alternate = 0x00080000,
        const Command = 0x00100000,

        // Special key identifiers.
        const Help = 0x00400000,
        const SecondaryFn = 0x00800000,

        // Identifies key events from numeric keypad area on extended keyboards.
        const NumericPad = 0x00200000,

        // Indicates if mouse/pen movement events are not being coalesced
        const NonCoalesced = 0x00000100,
    }
}

/// Constants that specify the different types of input events.
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventType {
    Null = 0,

    // Mouse events.
    LeftMouseDown = 1,
    LeftMouseUp = 2,
    RightMouseDown = 3,
    RightMouseUp = 4,
    MouseMoved = 5,
    LeftMouseDragged = 6,
    RightMouseDragged = 7,

    // Keyboard events.
    KeyDown = 10,
    KeyUp = 11,
    FlagsChanged = 12,

    // Specialized control devices.
    ScrollWheel = 22,
    TabletPointer = 23,
    TabletProximity = 24,
    OtherMouseDown = 25,
    OtherMouseUp = 26,
    OtherMouseDragged = 27,

    // Out of band event types. These are delivered to the event tap callback
    // to notify it of unusual conditions that disable the event tap.
    TapDisabledByTimeout = 0xFFFFFFFE,
    TapDisabledByUserInput = 0xFFFFFFFF,
}

// Constants that specify buttons on a one, two, or three-button mouse.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGMouseButton {
    Left,
    Right,
    Center,
}

/// Possible tapping points for events.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapLocation {
    HID,
    Session,
    AnnotatedSession,
}

#[repr(C)]
pub struct __CGEvent;

pub type CGEventRef = *const __CGEvent;

pub struct CGEvent {
    obj: CGEventRef,
}

impl Clone for CGEvent {
    #[inline]
    fn clone(&self) -> CGEvent {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGEvent {
    fn drop(&mut self) {
        unsafe {
            let ptr = self.as_CFTypeRef();
            assert!(ptr != ptr::null());
            CFRelease(ptr);
        }
    }
}

impl TCFType<CGEventRef> for CGEvent {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGEventRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
        let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
        CGEvent {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGEventGetTypeID()
        }
    }
}

impl CGEvent {
    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreate(source.as_concrete_TypeRef());
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_keyboard_event(
        source: CGEventSource,
        keycode: CGKeyCode,
        keydown: bool
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_mouse_event(
        source: CGEventSource,
        mouse_type: CGEventType,
        mouse_cursor_position: CGPoint,
        mouse_button: CGMouseButton
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
                mouse_cursor_position, mouse_button);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn post(&self, tap_location: CGEventTapLocation) {
        unsafe {
            CGEventPost(tap_location, self.as_concrete_TypeRef());
        }
    }

    pub fn location(&self) -> CGPoint {
        unsafe {
            CGEventGetLocation(self.as_concrete_TypeRef())
        }
    }

    #[cfg(feature = "elcapitan")]
    pub fn post_to_pid(&self, pid: libc::pid_t) {
        unsafe {
            CGEventPostToPid(pid, self.as_concrete_TypeRef());
        }
    }

    pub fn set_flags(&self, flags: CGEventFlags) {
        unsafe {
            CGEventSetFlags(self.as_concrete_TypeRef(), flags);
        }
    }

    pub fn get_flags(&self) -> CGEventFlags {
        unsafe {
            CGEventGetFlags(self.as_concrete_TypeRef())
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    /// Return the type identifier for the opaque type `CGEventRef'.
    fn CGEventGetTypeID() -> CFTypeID;

    /// Return a new event using the event source `source'. If `source' is NULL,
    /// the default source is used.
    fn CGEventCreate(source: CGEventSourceRef) -> CGEventRef;

    /// Return a new keyboard event.
    ///
    /// The event source may be taken from another event, or may be NULL. Based
    /// on the virtual key code values entered, the appropriate key down, key up,
    /// or flags changed events are generated.
    ///
    /// All keystrokes needed to generate a character must be entered, including
    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
    /// and 'z' key must be released:
    fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
        keydown: bool) -> CGEventRef;

    /// Return a new mouse event.
    ///
    /// The event source may be taken from another event, or may be NULL.
    /// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
    /// should be the position of the mouse cursor in global coordinates.
    /// `mouseButton' should be the button that's changing state; `mouseButton'
    /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
    /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
    ///
    /// The current implemementation of the event system supports a maximum of
    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
    /// the center button, and the remaining buttons are in USB device order.
    fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
        mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;

    /// Post an event into the event stream at a specified location.
    ///
    /// This function posts the specified event immediately before any event taps
    /// instantiated for that location, and the event passes through any such
    /// taps.
    fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);

    #[cfg(feature = "elcapitan")]
    /// Post an event to a specified process ID
    fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);

    /// Set the event flags of an event.
    fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);

    /// Return the event flags of an event.
    fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;

    /// Return the location of an event in global display coordinates.
    /// CGPointZero is returned if event is not a valid CGEventRef.
    fn CGEventGetLocation(event: CGEventRef) -> CGPoint;
}
<commit_msg>Add prefix to bitflags<commit_after>use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use geometry::CGPoint;
use event_source::{CGEventSource,CGEventSourceRef};

use libc;
use std::mem;
use std::ptr;

pub type CGKeyCode = libc::uint16_t;

/// Flags for events
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
bitflags! {
    pub flags CGEventFlags: u64 {
        const CGEventFlagNull = 0,

        // Device-independent modifier key bits.
        const CGEventFlagAlphaShift = 0x00010000,
        const CGEventFlagShift = 0x00020000,
        const CGEventFlagControl = 0x00040000,
        const CGEventFlagAlternate = 0x00080000,
        const CGEventFlagCommand = 0x00100000,

        // Special key identifiers.
        const CGEventFlagHelp = 0x00400000,
        const CGEventFlagSecondaryFn = 0x00800000,

        // Identifies key events from numeric keypad area on extended keyboards.
        const CGEventFlagNumericPad = 0x00200000,

        // Indicates if mouse/pen movement events are not being coalesced
        const CGEventFlagNonCoalesced = 0x00000100,
    }
}

/// Constants that specify the different types of input events.
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventType {
    Null = 0,

    // Mouse events.
    LeftMouseDown = 1,
    LeftMouseUp = 2,
    RightMouseDown = 3,
    RightMouseUp = 4,
    MouseMoved = 5,
    LeftMouseDragged = 6,
    RightMouseDragged = 7,

    // Keyboard events.
    KeyDown = 10,
    KeyUp = 11,
    FlagsChanged = 12,

    // Specialized control devices.
    ScrollWheel = 22,
    TabletPointer = 23,
    TabletProximity = 24,
    OtherMouseDown = 25,
    OtherMouseUp = 26,
    OtherMouseDragged = 27,

    // Out of band event types. These are delivered to the event tap callback
    // to notify it of unusual conditions that disable the event tap.
    TapDisabledByTimeout = 0xFFFFFFFE,
    TapDisabledByUserInput = 0xFFFFFFFF,
}

// Constants that specify buttons on a one, two, or three-button mouse.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGMouseButton {
    Left,
    Right,
    Center,
}

/// Possible tapping points for events.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapLocation {
    HID,
    Session,
    AnnotatedSession,
}

#[repr(C)]
pub struct __CGEvent;

pub type CGEventRef = *const __CGEvent;

pub struct CGEvent {
    obj: CGEventRef,
}

impl Clone for CGEvent {
    #[inline]
    fn clone(&self) -> CGEvent {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGEvent {
    fn drop(&mut self) {
        unsafe {
            let ptr = self.as_CFTypeRef();
            assert!(ptr != ptr::null());
            CFRelease(ptr);
        }
    }
}

impl TCFType<CGEventRef> for CGEvent {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGEventRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
        let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
        CGEvent {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGEventGetTypeID()
        }
    }
}

impl CGEvent {
    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreate(source.as_concrete_TypeRef());
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_keyboard_event(
        source: CGEventSource,
        keycode: CGKeyCode,
        keydown: bool
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_mouse_event(
        source: CGEventSource,
        mouse_type: CGEventType,
        mouse_cursor_position: CGPoint,
        mouse_button: CGMouseButton
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
                mouse_cursor_position, mouse_button);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn post(&self, tap_location: CGEventTapLocation) {
        unsafe {
            CGEventPost(tap_location, self.as_concrete_TypeRef());
        }
    }

    pub fn location(&self) -> CGPoint {
        unsafe {
            CGEventGetLocation(self.as_concrete_TypeRef())
        }
    }

    #[cfg(feature = "elcapitan")]
    pub fn post_to_pid(&self, pid: libc::pid_t) {
        unsafe {
            CGEventPostToPid(pid, self.as_concrete_TypeRef());
        }
    }

    pub fn set_flags(&self, flags: CGEventFlags) {
        unsafe {
            CGEventSetFlags(self.as_concrete_TypeRef(), flags);
        }
    }

    pub fn get_flags(&self) -> CGEventFlags {
        unsafe {
            CGEventGetFlags(self.as_concrete_TypeRef())
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    /// Return the type identifier for the opaque type `CGEventRef'.
    fn CGEventGetTypeID() -> CFTypeID;

    /// Return a new event using the event source `source'. If `source' is NULL,
    /// the default source is used.
    fn CGEventCreate(source: CGEventSourceRef) -> CGEventRef;

    /// Return a new keyboard event.
    ///
    /// The event source may be taken from another event, or may be NULL. Based
    /// on the virtual key code values entered, the appropriate key down, key up,
    /// or flags changed events are generated.
    ///
    /// All keystrokes needed to generate a character must be entered, including
    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
    /// and 'z' key must be released:
    fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
        keydown: bool) -> CGEventRef;

    /// Return a new mouse event.
    ///
    /// The event source may be taken from another event, or may be NULL.
    /// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
    /// should be the position of the mouse cursor in global coordinates.
    /// `mouseButton' should be the button that's changing state; `mouseButton'
    /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
    /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
    ///
    /// The current implemementation of the event system supports a maximum of
    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
    /// the center button, and the remaining buttons are in USB device order.
    fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
        mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;

    /// Post an event into the event stream at a specified location.
    ///
    /// This function posts the specified event immediately before any event taps
    /// instantiated for that location, and the event passes through any such
    /// taps.
    fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);

    #[cfg(feature = "elcapitan")]
    /// Post an event to a specified process ID
    fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);

    /// Set the event flags of an event.
    fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);

    /// Return the event flags of an event.
    fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;

    /// Return the location of an event in global display coordinates.
    /// CGPointZero is returned if event is not a valid CGEventRef.
    fn CGEventGetLocation(event: CGEventRef) -> CGPoint;
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) RFILE refsize rfilename fsize tsize

extern crate clap;

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use std::fs::{metadata, File, OpenOptions};
use std::io::Result;
use std::path::Path;

#[derive(Eq, PartialEq)]
enum TruncateMode {
    Reference,
    Extend,
    Reduce,
    AtMost,
    AtLeast,
    RoundDown,
    RoundUp,
}

static ABOUT: &str = "Shrink or extend the size of each file to the specified size.";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_NO_CREATE: &str = "no-create";
static OPT_REFERENCE: &str = "reference";
static OPT_IO_BLOCKS: &str = "io-blocks";
static OPT_SIZE: &str = "size";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

fn get_long_usage() -> String {
    format!(
        "
    SIZE is an integer with an optional prefix and optional unit.
    The available units (K, M, G, T, P, E, Z, and Y) use the following format:
        'KB' =>           1000 (kilobytes)
        'K'  =>           1024 (kibibytes)
        'MB' =>      1000*1000 (megabytes)
        'M'  =>      1024*1024 (mebibytes)
        'GB' => 1000*1000*1000 (gigabytes)
        'G'  => 1024*1024*1024 (gibibytes)
    SIZE may also be prefixed by one of the following to adjust the size of each
    file based on its current size:
        '+'  => extend by
        '-'  => reduce by
        '<'  => at most
        '>'  => at least
        '/'  => round down to multiple of
        '%'  => round up to multiple of"
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    /*
    let args = args.collect_str();

    let mut opts = getopts::Options::new();*/
    let usage = get_usage();
    let long_usage = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .arg(
            Arg::with_name(OPT_NO_CREATE)
            .short("c")
            .long(OPT_NO_CREATE)
            .help("do not create files that do not exist")
        )
        .arg(
            Arg::with_name(OPT_IO_BLOCKS)
            .short("o")
            .long(OPT_IO_BLOCKS)
            .help("treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED)")
        )
        .arg(
            Arg::with_name(OPT_REFERENCE)
            .short("r")
            .long(OPT_REFERENCE)
            .help("base the size of each file on the size of RFILE")
            .value_name("RFILE")
        )
        .arg(
            Arg::with_name(OPT_SIZE)
            .short("s")
            .long("size")
            .help("set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified")
            .value_name("SIZE")
        )
        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true).min_values(1))
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    if files.is_empty() {
        show_error!("Missing an argument");
        return 1;
    } else {
        let no_create = matches.is_present(OPT_NO_CREATE);
        let io_blocks = matches.is_present(OPT_IO_BLOCKS);
        let reference = matches.value_of(OPT_REFERENCE).map(String::from);
        let size = matches.value_of(OPT_SIZE).map(String::from);
        if reference.is_none() && size.is_none() {
            crash!(1, "you must specify either --reference or --size");
        } else {
            match truncate(no_create, io_blocks, reference, size, files) {
                Ok(()) => ( /* pass */ ),
                Err(_) => return 1,
            }
        }
    }

    0
}

fn truncate(
    no_create: bool,
    _: bool,
    reference: Option<String>,
    size: Option<String>,
    filenames: Vec<String>,
) -> Result<()> {
    let (refsize, mode) = match reference {
        Some(rfilename) => {
            let _ = match File::open(Path::new(&rfilename)) {
                Ok(m) => m,
                Err(f) => crash!(1, "{}", f.to_string()),
            };
            match metadata(rfilename) {
                Ok(meta) => (meta.len(), TruncateMode::Reference),
                Err(f) => crash!(1, "{}", f.to_string()),
            }
        }
        None => parse_size(size.unwrap().as_ref()),
    };
    for filename in &filenames {
        let path = Path::new(filename);
        match OpenOptions::new()
            .read(true)
            .write(true)
            .create(!no_create)
            .open(path)
        {
            Ok(file) => {
                let fsize = match metadata(filename) {
                    Ok(meta) => meta.len(),
                    Err(f) => {
                        show_warning!("{}", f.to_string());
                        continue;
                    }
                };
                let tsize: u64 = match mode {
                    TruncateMode::Reference => refsize,
                    TruncateMode::Extend => fsize + refsize,
                    TruncateMode::Reduce => fsize - refsize,
                    TruncateMode::AtMost => {
                        if fsize > refsize {
                            refsize
                        } else {
                            fsize
                        }
                    }
                    TruncateMode::AtLeast => {
                        if fsize < refsize {
                            refsize
                        } else {
                            fsize
                        }
                    }
                    TruncateMode::RoundDown => fsize - fsize % refsize,
                    TruncateMode::RoundUp => fsize + fsize % refsize,
                };
                match file.set_len(tsize) {
                    Ok(_) => {}
                    Err(f) => crash!(1, "{}", f.to_string()),
                };
            }
            Err(f) => crash!(1, "{}", f.to_string()),
        }
    }
    Ok(())
}

fn parse_size(size: &str) -> (u64, TruncateMode) {
    let mode = match size.chars().next().unwrap() {
        '+' => TruncateMode::Extend,
        '-' => TruncateMode::Reduce,
        '<' => TruncateMode::AtMost,
        '>' => TruncateMode::AtLeast,
        '/' => TruncateMode::RoundDown,
        '*' => TruncateMode::RoundUp,
        _ => TruncateMode::Reference, /* assume that the size is just a number */
    };
    let bytes = {
        let mut slice = if mode == TruncateMode::Reference {
            size
        } else {
            &size[1..]
        };
        if slice.chars().last().unwrap().is_alphabetic() {
            slice = &slice[..slice.len() - 1];
            if !slice.is_empty() && slice.chars().last().unwrap().is_alphabetic() {
                slice = &slice[..slice.len() - 1];
            }
        }
        slice
    }
    .to_owned();
    let mut number: u64 = match bytes.parse() {
        Ok(num) => num,
        Err(e) => crash!(1, "'{}' is not a valid number: {}", size, e),
    };
    if size.chars().last().unwrap().is_alphabetic() {
        number *= match size.chars().last().unwrap().to_ascii_uppercase() {
            'B' => match size
                .chars()
                .nth(size.len() - 2)
                .unwrap()
                .to_ascii_uppercase()
            {
                'K' => 1000u64,
                'M' => 1000u64.pow(2),
                'G' => 1000u64.pow(3),
                'T' => 1000u64.pow(4),
                'P' => 1000u64.pow(5),
                'E' => 1000u64.pow(6),
                'Z' => 1000u64.pow(7),
                'Y' => 1000u64.pow(8),
                letter => crash!(1, "'{}B' is not a valid suffix.", letter),
            },
            'K' => 1024u64,
            'M' => 1024u64.pow(2),
            'G' => 1024u64.pow(3),
            'T' => 1024u64.pow(4),
            'P' => 1024u64.pow(5),
            'E' => 1024u64.pow(6),
            'Z' => 1024u64.pow(7),
            'Y' => 1024u64.pow(8),
            letter => crash!(1, "'{}' is not a valid suffix.", letter),
        };
    }
    (number, mode)
}
<commit_msg>reorder the args<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) RFILE refsize rfilename fsize tsize

extern crate clap;

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use std::fs::{metadata, File, OpenOptions};
use std::io::Result;
use std::path::Path;

#[derive(Eq, PartialEq)]
enum TruncateMode {
    Reference,
    Extend,
    Reduce,
    AtMost,
    AtLeast,
    RoundDown,
    RoundUp,
}

static ABOUT: &str = "Shrink or extend the size of each file to the specified size.";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_IO_BLOCKS: &str = "io-blocks";
static OPT_NO_CREATE: &str = "no-create";
static OPT_REFERENCE: &str = "reference";
static OPT_SIZE: &str = "size";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

fn get_long_usage() -> String {
    format!(
        "
    SIZE is an integer with an optional prefix and optional unit.
    The available units (K, M, G, T, P, E, Z, and Y) use the following format:
        'KB' =>           1000 (kilobytes)
        'K'  =>           1024 (kibibytes)
        'MB' =>      1000*1000 (megabytes)
        'M'  =>      1024*1024 (mebibytes)
        'GB' => 1000*1000*1000 (gigabytes)
        'G'  => 1024*1024*1024 (gibibytes)
    SIZE may also be prefixed by one of the following to adjust the size of each
    file based on its current size:
        '+'  => extend by
        '-'  => reduce by
        '<'  => at most
        '>'  => at least
        '/'  => round down to multiple of
        '%'  => round up to multiple of"
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    /*
    let args = args.collect_str();

    let mut opts = getopts::Options::new();*/
    let usage = get_usage();
    let long_usage = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .arg(
            Arg::with_name(OPT_IO_BLOCKS)
            .short("o")
            .long(OPT_IO_BLOCKS)
            .help("treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED)")
        )
        .arg(
            Arg::with_name(OPT_NO_CREATE)
            .short("c")
            .long(OPT_NO_CREATE)
            .help("do not create files that do not exist")
        )
        .arg(
            Arg::with_name(OPT_REFERENCE)
            .short("r")
            .long(OPT_REFERENCE)
            .help("base the size of each file on the size of RFILE")
            .value_name("RFILE")
        )
        .arg(
            Arg::with_name(OPT_SIZE)
            .short("s")
            .long("size")
            .help("set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified")
            .value_name("SIZE")
        )
        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true).min_values(1))
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    if files.is_empty() {
        show_error!("Missing an argument");
        return 1;
    } else {
        let io_blocks = matches.is_present(OPT_IO_BLOCKS);
        let no_create = matches.is_present(OPT_NO_CREATE);
        let reference = matches.value_of(OPT_REFERENCE).map(String::from);
        let size = matches.value_of(OPT_SIZE).map(String::from);
        if reference.is_none() && size.is_none() {
            crash!(1, "you must specify either --reference or --size");
        } else {
            match truncate(no_create, io_blocks, reference, size, files) {
                Ok(()) => ( /* pass */ ),
                Err(_) => return 1,
            }
        }
    }

    0
}

fn truncate(
    no_create: bool,
    _: bool,
    reference: Option<String>,
    size: Option<String>,
    filenames: Vec<String>,
) -> Result<()> {
    let (refsize, mode) = match reference {
        Some(rfilename) => {
            let _ = match File::open(Path::new(&rfilename)) {
                Ok(m) => m,
                Err(f) => crash!(1, "{}", f.to_string()),
            };
            match metadata(rfilename) {
                Ok(meta) => (meta.len(), TruncateMode::Reference),
                Err(f) => crash!(1, "{}", f.to_string()),
            }
        }
        None => parse_size(size.unwrap().as_ref()),
    };
    for filename in &filenames {
        let path = Path::new(filename);
        match OpenOptions::new()
            .read(true)
            .write(true)
            .create(!no_create)
            .open(path)
        {
            Ok(file) => {
                let fsize = match metadata(filename) {
                    Ok(meta) => meta.len(),
                    Err(f) => {
                        show_warning!("{}", f.to_string());
                        continue;
                    }
                };
                let tsize: u64 = match mode {
                    TruncateMode::Reference => refsize,
                    TruncateMode::Extend => fsize + refsize,
                    TruncateMode::Reduce => fsize - refsize,
                    TruncateMode::AtMost => {
                        if fsize > refsize {
                            refsize
                        } else {
                            fsize
                        }
                    }
                    TruncateMode::AtLeast => {
                        if fsize < refsize {
                            refsize
                        } else {
                            fsize
                        }
                    }
                    TruncateMode::RoundDown => fsize - fsize % refsize,
                    TruncateMode::RoundUp => fsize + fsize % refsize,
                };
                match file.set_len(tsize) {
                    Ok(_) => {}
                    Err(f) => crash!(1, "{}", f.to_string()),
                };
            }
            Err(f) => crash!(1, "{}", f.to_string()),
        }
    }
    Ok(())
}

fn parse_size(size: &str) -> (u64, TruncateMode) {
    let mode = match size.chars().next().unwrap() {
        '+' => TruncateMode::Extend,
        '-' => TruncateMode::Reduce,
        '<' => TruncateMode::AtMost,
        '>' => TruncateMode::AtLeast,
        '/' => TruncateMode::RoundDown,
        '*' => TruncateMode::RoundUp,
        _ => TruncateMode::Reference, /* assume that the size is just a number */
    };
    let bytes = {
        let mut slice = if mode == TruncateMode::Reference {
            size
        } else {
            &size[1..]
        };
        if slice.chars().last().unwrap().is_alphabetic() {
            slice = &slice[..slice.len() - 1];
            if !slice.is_empty() && slice.chars().last().unwrap().is_alphabetic() {
                slice = &slice[..slice.len() - 1];
            }
        }
        slice
    }
    .to_owned();
    let mut number: u64 = match bytes.parse() {
        Ok(num) => num,
        Err(e) => crash!(1, "'{}' is not a valid number: {}", size, e),
    };
    if size.chars().last().unwrap().is_alphabetic() {
        number *= match size.chars().last().unwrap().to_ascii_uppercase() {
            'B' => match size
                .chars()
                .nth(size.len() - 2)
                .unwrap()
                .to_ascii_uppercase()
            {
                'K' => 1000u64,
                'M' => 1000u64.pow(2),
                'G' => 1000u64.pow(3),
                'T' => 1000u64.pow(4),
                'P' => 1000u64.pow(5),
                'E' => 1000u64.pow(6),
                'Z' => 1000u64.pow(7),
                'Y' => 1000u64.pow(8),
                letter => crash!(1, "'{}B' is not a valid suffix.", letter),
            },
            'K' => 1024u64,
            'M' => 1024u64.pow(2),
            'G' => 1024u64.pow(3),
            'T' => 1024u64.pow(4),
            'P' => 1024u64.pow(5),
            'E' => 1024u64.pow(6),
            'Z' => 1024u64.pow(7),
            'Y' => 1024u64.pow(8),
            letter => crash!(1, "'{}' is not a valid suffix.", letter),
        };
    }
    (number, mode)
}
<|endoftext|>


<commit_before>use jack_sys as j;

/// port type for Jack's built in 32 bit floating audio.
pub const DEFAULT_AUDIO_TYPE: &'static str = "32 bit float mono audio";

/// port type for Jack's built in 8 bit raw midi
pub const DEFAULT_MIDI_TYPE: &'static str = "8 bit raw midi";

bitflags! {
    /// Option flags for opening a Jack client.
    ///
    /// * `NULL_OPTION` - Equivalent to `ClientOptions::empty()`
    ///
    /// * `NO_START_SERVER`: Do not automatically start the Jack server when it
    /// is not already running. This option is always selected if
    /// `$JACK_NO_START_SERVER` is defined in the calling process
    /// environment.
    ///
    /// * `USE_EXACT_NAME`: Use the exact client name requested. Otherwise,
    /// Jack automatically generates a unique one if needed.
    ///
    /// * `SERVER_NAME`: Open with optional `server_name` parameter. TODO:
    /// implement
    ///
    /// * `LOAD_NAME`: Load internal client from optional `load_name`,
    /// otherwise use the `client_name`. TODO implement
    ///
    /// * `LOAD_INIT`: Pass optional `load_init` to `jack_initialize()`
    /// entry point of an internal client. TODO: implement
    ///
    /// * `SESSION_ID`: Pass a SessionID token. This allows the session
    /// manager to identify the client again.
    pub flags ClientOptions: u32 {
        const NULL_OPTION     = j::JackNullOption,
        const NO_START_SERVER = j::JackNoStartServer,
        const USE_EXACT_NAME  = j::JackUseExactName,
        const SERVER_NAME     = j::JackServerName,
        const LOAD_NAME       = j::JackLoadName,
        const LOAD_INIT       = j::JackLoadInit,
        const SESSION_ID      = j::JackSessionID,
    }
}

bitflags! {
    /// Status flags for Jack clients.
    ///
    /// * `JackFailure` - Overall operation failed.
    ///
    /// * `JackInvalidOption` - The operation contained an invalid or unsupported
    /// option.
    ///
    /// * `JackNameNotUnique` - The desired client name was not unique. With the
    /// JackUseExactName option this situation is fatal. Otherwise, the name was
    /// modified by appending a dash and a two-digit number in the range "-01"
    /// to "-99". `Client::name()` will return the exact string that was
    /// used. If the specified client_name plus these extra characters would be
    /// too long, the open fails instead.
    ///
    /// * `JackServerStarted` - The JACK server was started as a result of this
    /// operation. Otherwise, it was running already. In either case the caller
    /// is now connected to jackd, so there is no race condition. When the
    /// server shuts down, the client will find out.
    ///
    /// * `JackServerFailed` - Unable to connect to the JACK server.
    ///
    /// * `JackServerError` - Communication error with the JACK server.
    ///
    /// * `JackNoSuchClient` - Requested client does not exist.
    ///
    /// * `JackLoadFailure` - Unable to load internal client
    ///
    /// * `JackInitFailure` - Unable to initialize client
    ///
    /// * `JackShmFailure` - Unable to access shared memory
    ///
    /// * `JackVersionError` - Client's protocol version does not match
    ///
    /// * `JackBackendError` - No documentation found. TODO: dig deeper
    ///
    /// * `JackClientZombie` - No documentation found. TODO: dig deeper
    pub flags ClientStatus: u32 {
        const FAILURE         = j::JackFailure,
        const INVALID_OPTION  = j::JackInvalidOption,
        const NAME_NOT_UNIQUE = j::JackNameNotUnique,
        const SERVER_STARTED  = j::JackServerStarted,
        const SERVER_FAILED   = j::JackServerFailed,
        const SERVER_ERROR    = j::JackServerError,
        const NO_SUCH_CLIENT  = j::JackNoSuchClient,
        const LOAD_FAILURE    = j::JackLoadFailure,
        const INIT_FAILURE    = j::JackInitFailure,
        const SHM_FAILURE     = j::JackShmFailure,
        const VERSION_ERROR   = j::JackVersionError,
        const BACKEND_ERROR   = j::JackBackendError,
        const CLIENT_ZOMBIE   = j::JackClientZombie,
        const UNKNOWN_ERROR   = 0x2000, // TODO: don't use this
    }
}

bitflags! {
    /// Flags for specifying port options.
    ///
    /// * `IS_INPUT` - The port can receive data.
    ///
    /// * `IS_OUTPUT` - Data can be read from the port.
    ///
    /// * `IS_PHYSICAL` - Port corresponds to some kind of physical I/O
    /// connector.
    ///
    /// * `CAN_MONITOR` - A call to `jack_port_request_monitor()` makes
    /// sense. TODO: implement. Precisely what this means it dependent on the
    /// client. A typical result of it being called with `true` as the second
    /// argument is that data that would be available from an output port (with
    /// `IS_PHYSICAL` set) is sent to a physical output connector as well, so
    /// that it can be heard/seen/whatever.
    ///
    /// * `IS_TERMINAL` - For an input port, the data received by the port will
    /// not be passed on or made available at any other port. For output, the
    /// data available at the port does not originate from any other port. Audio
    /// synthesizers, I/O hardware interface clients, HDR systems are examples
    /// of clients that would set this flag for their ports.
    pub flags PortFlags: u32 {
        const IS_INPUT    = j::JackPortIsInput,
        const IS_OUTPUT   = j::JackPortIsOutput,
        const IS_PHYSICAL = j::JackPortIsPhysical,
        const CAN_MONITOR = j::JackPortCanMonitor,
        const IS_TERMINAL = j::JackPortIsTerminal,
    }
}

/// Used by `JackHandler::latency()`.
pub enum LatencyType {
    Capture,
    Playback,
}
<commit_msg>fix doc on ClientStatus<commit_after>use jack_sys as j;

/// port type for Jack's built in 32 bit floating audio.
pub const DEFAULT_AUDIO_TYPE: &'static str = "32 bit float mono audio";

/// port type for Jack's built in 8 bit raw midi
pub const DEFAULT_MIDI_TYPE: &'static str = "8 bit raw midi";

bitflags! {
    /// Option flags for opening a Jack client.
    ///
    /// * `NULL_OPTION` - Equivalent to `ClientOptions::empty()`
    ///
    /// * `NO_START_SERVER`: Do not automatically start the Jack server when it
    /// is not already running. This option is always selected if
    /// `$JACK_NO_START_SERVER` is defined in the calling process
    /// environment.
    ///
    /// * `USE_EXACT_NAME`: Use the exact client name requested. Otherwise,
    /// Jack automatically generates a unique one if needed.
    ///
    /// * `SERVER_NAME`: Open with optional `server_name` parameter. TODO:
    /// implement
    ///
    /// * `LOAD_NAME`: Load internal client from optional `load_name`,
    /// otherwise use the `client_name`. TODO implement
    ///
    /// * `LOAD_INIT`: Pass optional `load_init` to `jack_initialize()`
    /// entry point of an internal client. TODO: implement
    ///
    /// * `SESSION_ID`: Pass a SessionID token. This allows the session
    /// manager to identify the client again.
    pub flags ClientOptions: u32 {
        const NULL_OPTION     = j::JackNullOption,
        const NO_START_SERVER = j::JackNoStartServer,
        const USE_EXACT_NAME  = j::JackUseExactName,
        const SERVER_NAME     = j::JackServerName,
        const LOAD_NAME       = j::JackLoadName,
        const LOAD_INIT       = j::JackLoadInit,
        const SESSION_ID      = j::JackSessionID,
    }
}

bitflags! {
    /// Status flags for Jack clients.
    ///
    /// * `FAILURE` - Overall operation failed.
    ///
    /// * `INVALID_OPTION` - The operation contained an invalid or unsupported
    /// option.
    ///
    /// * `NAME_NOT_UNIQUE` - The desired client name was not unique. With the
    /// `USE_EXACT_NAME` option this situation is fatal. Otherwise, the name was
    /// modified by appending a dash and a two-digit number in the range "-01"
    /// to "-99". `Client::name()` will return the exact string that was
    /// used. If the specified client_name plus these extra characters would be
    /// too long, the open fails instead.
    ///
    /// * `SERVER_STARTED` - The JACK server was started as a result of this
    /// operation. Otherwise, it was running already. In either case the caller
    /// is now connected to jackd, so there is no race condition. When the
    /// server shuts down, the client will find out.
    ///
    /// * `SERVER_FAILED` - Unable to connect to the JACK server.
    ///
    /// * `SERVER_ERROR` - Communication error with the JACK server.
    ///
    /// * `NO_SUCH_CLIENT` - Requested client does not exist.
    ///
    /// * `LOAD_FAILURE` - Unable to load internal client
    ///
    /// * `INIT_FAILURE` - Unable to initialize client
    ///
    /// * `SHM_FAILURE` - Unable to access shared memory
    ///
    /// * `VERSION_ERROR` - Client's protocol version does not match
    ///
    /// * `BACKEND_ERROR` - No documentation found. TODO: dig deeper
    ///
    /// * `CLIENT_ZOZMBIE` - No documentation found. TODO: dig deeper
    ///
    /// * `UNKNOWN_ERROR` - Not part of jack and shouldn't occur ever.
    /// File an issue if you can get it to appear.
    pub flags ClientStatus: u32 {
        const FAILURE         = j::JackFailure,
        const INVALID_OPTION  = j::JackInvalidOption,
        const NAME_NOT_UNIQUE = j::JackNameNotUnique,
        const SERVER_STARTED  = j::JackServerStarted,
        const SERVER_FAILED   = j::JackServerFailed,
        const SERVER_ERROR    = j::JackServerError,
        const NO_SUCH_CLIENT  = j::JackNoSuchClient,
        const LOAD_FAILURE    = j::JackLoadFailure,
        const INIT_FAILURE    = j::JackInitFailure,
        const SHM_FAILURE     = j::JackShmFailure,
        const VERSION_ERROR   = j::JackVersionError,
        const BACKEND_ERROR   = j::JackBackendError,
        const CLIENT_ZOMBIE   = j::JackClientZombie,
        const UNKNOWN_ERROR   = 0x2000, // TODO: don't use this
    }
}

bitflags! {
    /// Flags for specifying port options.
    ///
    /// * `IS_INPUT` - The port can receive data.
    ///
    /// * `IS_OUTPUT` - Data can be read from the port.
    ///
    /// * `IS_PHYSICAL` - Port corresponds to some kind of physical I/O
    /// connector.
    ///
    /// * `CAN_MONITOR` - A call to `jack_port_request_monitor()` makes
    /// sense. TODO: implement. Precisely what this means it dependent on the
    /// client. A typical result of it being called with `true` as the second
    /// argument is that data that would be available from an output port (with
    /// `IS_PHYSICAL` set) is sent to a physical output connector as well, so
    /// that it can be heard/seen/whatever.
    ///
    /// * `IS_TERMINAL` - For an input port, the data received by the port will
    /// not be passed on or made available at any other port. For output, the
    /// data available at the port does not originate from any other port. Audio
    /// synthesizers, I/O hardware interface clients, HDR systems are examples
    /// of clients that would set this flag for their ports.
    pub flags PortFlags: u32 {
        const IS_INPUT    = j::JackPortIsInput,
        const IS_OUTPUT   = j::JackPortIsOutput,
        const IS_PHYSICAL = j::JackPortIsPhysical,
        const CAN_MONITOR = j::JackPortCanMonitor,
        const IS_TERMINAL = j::JackPortIsTerminal,
    }
}

/// Used by `JackHandler::latency()`.
pub enum LatencyType {
    Capture,
    Playback,
}
<|endoftext|>