<commit_before>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.to_pretty_str().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };

    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: uint, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.to_pretty_str().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day 15&16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>Small cleanups.<commit_after>#![feature(phase)]

extern crate fuse;
#[phase(plugin)]
extern crate json_macros;
extern crate time;
extern crate libc;
extern crate serialize;

use std::collections::TreeMap;
use std::io::{FileType, USER_FILE, USER_DIR};
use std::os;
use libc::{ENOENT};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
    attrs: TreeMap<u64, FileAttr>,
    inodes: TreeMap<String, u64>,
}

impl JsonFilesystem {
    fn new(tree: &json::Object) -> JsonFilesystem {
        let mut attrs = TreeMap::new();
        let mut inodes = TreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: USER_DIR,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0,
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_string(), 1);
        for (i, (key, value)) in tree.iter().enumerate() {
            let attr = FileAttr {
                ino: i as u64 + 2,
                size: value.to_pretty_str().len() as u64,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: USER_FILE,
                nlink: 0,
                uid: 0,
                gid: 0,
                rdev: 0,
                flags: 0,
            };
            attrs.insert(attr.ino, attr);
            inodes.insert(key.clone(), attr.ino);
        }
        JsonFilesystem { tree: tree.clone(), attrs: attrs, inodes: inodes }
    }
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT),
        };
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &PosixPath, reply: ReplyEntry) {
        println!("lookup(parent={}, name={})", parent, name.display());
        let inode = match self.inodes.get(name.as_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            },
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: uint, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);
        for (key, &inode) in self.inodes.iter() {
            if inode == ino {
                let value = self.tree.get(key).unwrap();
                reply.data(value.to_pretty_str().as_bytes());
                return;
            }
        }
        reply.error(ENOENT);
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (key, &inode) in self.inodes.iter() {
                    if inode == 1 { continue; }
                    let offset = inode; // hack
                    println!("\tkey={}, inode={}, offset={}", key, inode, offset);
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (days 15 & 16)");
    let data = json!({
        "foo": "bar",
        "answer": 42,
    });
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem::new(tree);
    let mountpoint = match os::args().as_slice() {
        [_, ref path] => Path::new(path),
        _ => {
            println!("Usage: {} <MOUNTPOINT>", os::args()[0]);
            return;
        }
    };
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

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

use crate::utils::{
    self, AttrParams, DeriveType, FullMetaInfo, 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::new();
    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::new(),
        }
    }
}

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

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

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

    fn render_backtrace_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
        self.backtrace.map(|backtrace| {
            let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]);
            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 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!(),
    };

    parsed_fields.map(|mut parsed_fields| {
        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,
            );
        }

        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>Replace some .map calls with ?<commit_after>use std::collections::HashSet;

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

use crate::utils::{
    self, AttrParams, DeriveType, FullMetaInfo, 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::new();
    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::new(),
        }
    }
}

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>/// Error types

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {

        // Errors for tokenizer

        QueryParsingError(query: String) {
            description("parsing the query failed")
            display("Parsing the query '{}' failed", query)
        }

        EmptyQueryError {
            description("the query is empty")
            display("The query on the TOML is empty")
        }

        EmptyIdentifier {
            description("Query an empty identifier: ''")
            display("The passed query has an empty identifier")
        }

        ArrayAccessWithoutIndex {
            description("trying to access array without index")
            display("The passed query tries to access an array but does not specify the index")
        }

        ArrayAccessWithInvalidIndex {
            description("trying to pass an invalid index")
            display("The passed query tries to access an array but does not specify a valid index")
        }

        // Errors for Resolver

        IdentifierNotFoundInDocument(ident: String) {
            description("Identifier missing in document")
            display("The identfier '{}' is not present in the document", ident)
        }

        NoIndexInTable(i: usize) {
            description("Cannot deref index from table")
            display("Got an index query '[{}]' but have table", i)
        }

        NoIdentifierInArray(s: String) {
            description("Cannot query identifier in array")
            display("Got an identifier query '{}' but have array", s)
        }

        QueryingValueAsTable(s: String) {
            description("Querying a table where a value is")
            display("Got an identifier query '{}' but have value", s)
        }

        QueryingValueAsArray(i: usize) {
            description("Querying a table where a value is")
            display("Got an index query '{}' but have value", i)
        }

        CannotDeleteNonEmptyTable(tabname: Option<String>) {
            description("Cannot delete Table that is not empty")
            display("Cannot delete table '{:?}' which is not empty", tabname)
        }

        CannotDeleteNonEmptyArray(arrname: Option<String>) {
            description("Cannot delete Array that is not empty")
            display("Cannot delete array '{:?}' which is not empty", arrname)
        }

        CannotAccessBecauseTypeMismatch(expected: &'static str, actual: &'static str) {
            description("Cannot access value because of type mismatch")
            display("Cannot access {} because expected {}", actual, expected)
        }

        ArrayIndexOutOfBounds(idx: usize, arrlen: usize) {
            description("Delete index out of bounds")
            display("Cannot delete in array at {}, array has length {}", idx, arrlen)
        }

    }
}
<commit_msg>Add error types for read<commit_after>/// Error types

error_chain! {
    types {
        Error, ErrorKind, ResultExt, Result;
    }

    errors {

        // Errors for tokenizer

        QueryParsingError(query: String) {
            description("parsing the query failed")
            display("Parsing the query '{}' failed", query)
        }

        EmptyQueryError {
            description("the query is empty")
            display("The query on the TOML is empty")
        }

        EmptyIdentifier {
            description("Query an empty identifier: ''")
            display("The passed query has an empty identifier")
        }

        ArrayAccessWithoutIndex {
            description("trying to access array without index")
            display("The passed query tries to access an array but does not specify the index")
        }

        ArrayAccessWithInvalidIndex {
            description("trying to pass an invalid index")
            display("The passed query tries to access an array but does not specify a valid index")
        }

        // Errors for Resolver

        IdentifierNotFoundInDocument(ident: String) {
            description("Identifier missing in document")
            display("The identfier '{}' is not present in the document", ident)
        }

        NoIndexInTable(i: usize) {
            description("Cannot deref index from table")
            display("Got an index query '[{}]' but have table", i)
        }

        NoIdentifierInArray(s: String) {
            description("Cannot query identifier in array")
            display("Got an identifier query '{}' but have array", s)
        }

        QueryingValueAsTable(s: String) {
            description("Querying a table where a value is")
            display("Got an identifier query '{}' but have value", s)
        }

        QueryingValueAsArray(i: usize) {
            description("Querying a table where a value is")
            display("Got an index query '{}' but have value", i)
        }

        CannotDeleteNonEmptyTable(tabname: Option<String>) {
            description("Cannot delete Table that is not empty")
            display("Cannot delete table '{:?}' which is not empty", tabname)
        }

        CannotDeleteNonEmptyArray(arrname: Option<String>) {
            description("Cannot delete Array that is not empty")
            display("Cannot delete array '{:?}' which is not empty", arrname)
        }

        CannotAccessBecauseTypeMismatch(expected: &'static str, actual: &'static str) {
            description("Cannot access value because of type mismatch")
            display("Cannot access {} because expected {}", actual, expected)
        }

        ArrayIndexOutOfBounds(idx: usize, arrlen: usize) {
            description("Delete index out of bounds")
            display("Cannot delete in array at {}, array has length {}", idx, arrlen)
        }

        TypeError(requested: &'static str, got: &'static str) {
            description("Type error")
            display("Type Error. Requested {}, but got {}", requested, got)
        }

        NotAvailable(query: String) {
            description("Value missing error")
            display("Value at '{}' not there", query)
        }

    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

#[derive(Debug, Clone)]
pub enum PngError {
    DeflatedDataTooLong(usize),
    Other(Box<str>),
}

impl Error for PngError {
    // deprecated
    fn description(&self) -> &str {
        ""
    }
}

impl fmt::Display for PngError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PngError::DeflatedDataTooLong(_) => f.write_str("deflated data too long"),
            PngError::Other(ref s) => f.write_str(s),
        }
    }
}

impl PngError {
    #[inline]
    pub fn new(description: &str) -> PngError {
        PngError::Other(description.into())
    }
}
<commit_msg>Make PngError non-exhaustive for forward compatibility<commit_after>use std::error::Error;
use std::fmt;

// TODO: Use `#[non_exhaustive]` once stabilized
// https://github.com/rust-lang/rust/issues/44109
#[derive(Debug, Clone)]
pub enum PngError {
    DeflatedDataTooLong(usize),
    Other(Box<str>),
    #[doc(hidden)]
    _Nonexhaustive,
}

impl Error for PngError {
    // deprecated
    fn description(&self) -> &str {
        ""
    }
}

impl fmt::Display for PngError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PngError::DeflatedDataTooLong(_) => f.write_str("deflated data too long"),
            PngError::Other(ref s) => f.write_str(s),
            PngError::_Nonexhaustive => unreachable!(),
        }
    }
}

impl PngError {
    #[inline]
    pub fn new(description: &str) -> PngError {
        PngError::Other(description.into())
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate serde_json;

use self::ErrorType::*;
use std::error::Error as StdError;
use std::fmt;
use std::io;

#[derive(Debug)]
pub enum ErrorType {
    Unauthorized,
    SerdeJson(serde_json::error::Error),
    Hyper(hyper::error::Error),
    Io(io::Error),
    StatusCode(hyper::status::StatusCode),
    Api(ApiError),
}

#[derive(Debug)]
pub struct Error {
    pub err: ErrorType,
    pub url: Option<hyper::Url>,
}

impl Error {
    pub fn new<T: Into<Error>>(err: T, url: Option<hyper::Url>) -> Error {
        Error {
            err: err.into().err,
            url: url,
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

impl From<ErrorType> for Error {
    fn from(err: ErrorType) -> Error {
        Error {
            err: err,
            url: None,
        }
    }
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error {
        Error {
            err: ErrorType::SerdeJson(err),
            url: None,
        }
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        Error {
            err: ErrorType::Hyper(err),
            url: None,
        }
    }
}

impl From<hyper::error::ParseError> for Error {
    fn from(err: hyper::error::ParseError) -> Error {
        Error {
            err: ErrorType::Hyper(hyper::Error::Uri(err)),
            url: None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error {
            err: ErrorType::Io(err),
            url: None,
        }
    }
}

impl From<hyper::status::StatusCode> for Error {
    fn from(code: hyper::status::StatusCode) -> Error {
        Error {
            err: {
                if code == hyper::status::StatusCode::Unauthorized {
                    ErrorType::Unauthorized
                } else {
                    ErrorType::StatusCode(code)
                }
            },
            url: None,
        }
    }
}

impl From<ApiError> for Error {
    fn from(err: ApiError) -> Error {
        Error {
            err: ErrorType::Api(err),
            url: None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            SerdeJson(ref err) => fmt::Display::fmt(err, f),
            Hyper(ref err) => fmt::Display::fmt(err, f),
            Io(ref err) => fmt::Display::fmt(err, f),
            StatusCode(ref status) => fmt::Display::fmt(status, f),
            Api(ref err) => fmt::Display::fmt(err, f),
            Unauthorized => {
                write!(f, "access not authorized: token expired, username/password incorrect or no login provided")
            }
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.err {
            SerdeJson(ref err) => err.description(),
            Hyper(ref err) => err.description(),
            Io(ref err) => err.description(),
            StatusCode(ref status) => {
                if let Some(reason) = status.canonical_reason() {
                    return reason;
                }
                if status.is_success() {
                    return "status code error: success";
                }
                if status.is_informational() {
                    return "status code error: informational";
                }
                if status.is_redirection() {
                    return "status code error: redirection";
                }
                if status.is_client_error() {
                    return "status code error: client error";
                }
                if status.is_server_error() {
                    return "status code error: server error";
                }
                if status.is_strange_status() {
                    return "status code error: strange status";
                }
                return "status code error";
            }
            Api(ref err) => err.description(),
            Unauthorized => "access not authorized: token expired, username/password incorrect or no login provided",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.err {
            SerdeJson(ref err) => Some(err),
            Hyper(ref err) => Some(err),
            Io(ref err) => Some(err),
            StatusCode(_) => None,
            Api(ref err) => Some(err),
            Unauthorized => None,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum ApiError {
    NotOk(i32),
    MissingField(&'static str),
}

impl fmt::Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ApiError::NotOk(code) => write!(f, "non-ok result from api call: {}", code),
            ApiError::MissingField(field) => write!(f, "missing field from api call: {}", field),
        }
    }
}

impl StdError for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::NotOk(_) => "non-ok result from api call",
            ApiError::MissingField(_) => "missing field from api call",
        }
    }

    fn cause(&self) -> Option<&StdError> { None }
}
<commit_msg>Match on status class rather than using different is_* methods.<commit_after>extern crate hyper;
extern crate serde_json;

use self::ErrorType::*;
use std::error::Error as StdError;
use std::fmt;
use std::io;

#[derive(Debug)]
pub enum ErrorType {
    Unauthorized,
    SerdeJson(serde_json::error::Error),
    Hyper(hyper::error::Error),
    Io(io::Error),
    StatusCode(hyper::status::StatusCode),
    Api(ApiError),
}

#[derive(Debug)]
pub struct Error {
    pub err: ErrorType,
    pub url: Option<hyper::Url>,
}

impl Error {
    pub fn new<T: Into<Error>>(err: T, url: Option<hyper::Url>) -> Error {
        Error {
            err: err.into().err,
            url: url,
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

impl From<ErrorType> for Error {
    fn from(err: ErrorType) -> Error {
        Error {
            err: err,
            url: None,
        }
    }
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error {
        Error {
            err: ErrorType::SerdeJson(err),
            url: None,
        }
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        Error {
            err: ErrorType::Hyper(err),
            url: None,
        }
    }
}

impl From<hyper::error::ParseError> for Error {
    fn from(err: hyper::error::ParseError) -> Error {
        Error {
            err: ErrorType::Hyper(hyper::Error::Uri(err)),
            url: None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error {
            err: ErrorType::Io(err),
            url: None,
        }
    }
}

impl From<hyper::status::StatusCode> for Error {
    fn from(code: hyper::status::StatusCode) -> Error {
        Error {
            err: {
                if code == hyper::status::StatusCode::Unauthorized {
                    ErrorType::Unauthorized
                } else {
                    ErrorType::StatusCode(code)
                }
            },
            url: None,
        }
    }
}

impl From<ApiError> for Error {
    fn from(err: ApiError) -> Error {
        Error {
            err: ErrorType::Api(err),
            url: None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            SerdeJson(ref err) => fmt::Display::fmt(err, f),
            Hyper(ref err) => fmt::Display::fmt(err, f),
            Io(ref err) => fmt::Display::fmt(err, f),
            StatusCode(ref status) => fmt::Display::fmt(status, f),
            Api(ref err) => fmt::Display::fmt(err, f),
            Unauthorized => {
                write!(f, "access not authorized: token expired, username/password incorrect or no login provided")
            }
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.err {
            SerdeJson(ref err) => err.description(),
            Hyper(ref err) => err.description(),
            Io(ref err) => err.description(),
            StatusCode(ref status) => {
                match status.canonical_reason() {
                    Some(reason) => reason,
                    None => {
                        use hyper::status::StatusClass::*;
                        match status.class() {
                            Informational => "status code error: informational",
                            Success => "status code error: success",
                            Redirection => "status code error: redirection",
                            ClientError => "status code error: client error",
                            ServerError => "status code error: server error",
                            NoClass => "status code error: strange status",
                        }
                    }
                }
            }
            Api(ref err) => err.description(),
            Unauthorized => "access not authorized: token expired, username/password incorrect or no login provided",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.err {
            SerdeJson(ref err) => Some(err),
            Hyper(ref err) => Some(err),
            Io(ref err) => Some(err),
            StatusCode(_) => None,
            Api(ref err) => Some(err),
            Unauthorized => None,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum ApiError {
    NotOk(i32),
    MissingField(&'static str),
}

impl fmt::Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ApiError::NotOk(code) => write!(f, "non-ok result from api call: {}", code),
            ApiError::MissingField(field) => write!(f, "missing field from api call: {}", field),
        }
    }
}

impl StdError for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::NotOk(_) => "non-ok result from api call",
            ApiError::MissingField(_) => "missing field from api call",
        }
    }

    fn cause(&self) -> Option<&StdError> { None }
}
<|endoftext|>


<commit_before>use std::io;
use std::string;

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    pos: u64,
    kind: ErrorKind,
}

impl Error {
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

#[derive(Debug)]
pub enum ErrorKind {
    FromUtf8Error(string::FromUtf8Error),
    InvalidMagic,
    Io(io::Error),
    UnexpectedEof,
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        ErrorKind::Io(err)
    }
}
<commit_msg>Implement conversion from `byteorder::Error` to `ErrorKind`<commit_after>extern crate byteorder;

use std::io;
use std::string;

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
    pos: u64,
    kind: ErrorKind,
}

impl Error {
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

#[derive(Debug)]
pub enum ErrorKind {
    FromUtf8Error(string::FromUtf8Error),
    InvalidMagic,
    Io(io::Error),
    UnexpectedEof,
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<|endoftext|>


<commit_before>use std::env::JoinPathsError;
use std::ffi::{CStr, NulError};
use std::error;
use std::fmt;
use std::str;
use libc::c_int;

use {raw, ErrorClass, ErrorCode};

/// A structure to represent errors coming out of libgit2.
#[derive(Debug)]
pub struct Error {
    code: c_int,
    klass: c_int,
    message: String,
}

impl Error {
    /// Returns the last error, or `None` if one is not available.
    pub fn last_error(code: c_int) -> Option<Error> {
        ::init();
        unsafe {
            let ptr = raw::giterr_last();
            if ptr.is_null() {
                None
            } else {
                Some(Error::from_raw(code, ptr))
            }
        }
    }

    unsafe fn from_raw(code: c_int, ptr: *const raw::git_error) -> Error {
        let msg = CStr::from_ptr((*ptr).message as *const _).to_bytes();
        let msg = str::from_utf8(msg).unwrap();
        Error { code: code, klass: (*ptr).klass, message: msg.to_string() }
    }

    /// Creates a new error from the given string as the error.
    pub fn from_str(s: &str) -> Error {
        Error {
            code: raw::GIT_ERROR as c_int,
            klass: raw::GITERR_NONE as c_int,
            message: s.to_string(),
        }
    }

    /// Return the error code associated with this error.
    pub fn code(&self) -> ErrorCode {
        match self.raw_code() {
            raw::GIT_OK => super::ErrorCode::GenericError,
            raw::GIT_ERROR => super::ErrorCode::GenericError,
            raw::GIT_ENOTFOUND => super::ErrorCode::NotFound,
            raw::GIT_EEXISTS => super::ErrorCode::Exists,
            raw::GIT_EAMBIGUOUS => super::ErrorCode::Ambiguous,
            raw::GIT_EBUFS => super::ErrorCode::BufSize,
            raw::GIT_EUSER => super::ErrorCode::User,
            raw::GIT_EBAREREPO => super::ErrorCode::BareRepo,
            raw::GIT_EUNBORNBRANCH => super::ErrorCode::UnbornBranch,
            raw::GIT_EUNMERGED => super::ErrorCode::Unmerged,
            raw::GIT_ENONFASTFORWARD => super::ErrorCode::NotFastForward,
            raw::GIT_EINVALIDSPEC => super::ErrorCode::InvalidSpec,
            raw::GIT_ECONFLICT => super::ErrorCode::Conflict,
            raw::GIT_ELOCKED => super::ErrorCode::Locked,
            raw::GIT_EMODIFIED => super::ErrorCode::Modified,
            raw::GIT_PASSTHROUGH => super::ErrorCode::GenericError,
            raw::GIT_ITEROVER => super::ErrorCode::GenericError,
            raw::GIT_EAUTH => super::ErrorCode::Auth,
            raw::GIT_ECERTIFICATE => super::ErrorCode::Certificate,
            raw::GIT_EAPPLIED => super::ErrorCode::Applied,
            raw::GIT_EPEEL => super::ErrorCode::Peel,
            raw::GIT_EEOF => super::ErrorCode::Eof,
            raw::GIT_EINVALID => super::ErrorCode::Invalid,
            raw::GIT_EUNCOMMITTED => super::ErrorCode::Uncommitted,
            raw::GIT_EDIRECTORY => super::ErrorCode::Directory,
            _ => super::ErrorCode::GenericError,
        }
    }

    /// Return the error class associated with this error.
    pub fn class(&self) -> ErrorClass {
        match self.raw_class() {
            raw::GITERR_NONE => super::ErrorClass::None,
            raw::GITERR_NOMEMORY => super::ErrorClass::NoMemory,
            raw::GITERR_OS => super::ErrorClass::Os,
            raw::GITERR_INVALID => super::ErrorClass::Invalid,
            raw::GITERR_REFERENCE => super::ErrorClass::Reference,
            raw::GITERR_ZLIB => super::ErrorClass::Zlib,
            raw::GITERR_REPOSITORY => super::ErrorClass::Repository,
            raw::GITERR_CONFIG => super::ErrorClass::Config,
            raw::GITERR_REGEX => super::ErrorClass::Regex,
            raw::GITERR_ODB => super::ErrorClass::Odb,
            raw::GITERR_INDEX => super::ErrorClass::Index,
            raw::GITERR_OBJECT => super::ErrorClass::Object,
            raw::GITERR_NET => super::ErrorClass::Net,
            raw::GITERR_TAG => super::ErrorClass::Tag,
            raw::GITERR_TREE => super::ErrorClass::Tree,
            raw::GITERR_INDEXER => super::ErrorClass::Indexer,
            raw::GITERR_SSL => super::ErrorClass::Ssl,
            raw::GITERR_SUBMODULE => super::ErrorClass::Submodule,
            raw::GITERR_THREAD => super::ErrorClass::Thread,
            raw::GITERR_STASH => super::ErrorClass::Stash,
            raw::GITERR_CHECKOUT => super::ErrorClass::Checkout,
            raw::GITERR_FETCHHEAD => super::ErrorClass::FetchHead,
            raw::GITERR_MERGE => super::ErrorClass::Merge,
            raw::GITERR_SSH => super::ErrorClass::Ssh,
            raw::GITERR_FILTER => super::ErrorClass::Filter,
            raw::GITERR_REVERT => super::ErrorClass::Revert,
            raw::GITERR_CALLBACK => super::ErrorClass::Callback,
            raw::GITERR_CHERRYPICK => super::ErrorClass::CherryPick,
            raw::GITERR_DESCRIBE => super::ErrorClass::Describe,
            raw::GITERR_REBASE => super::ErrorClass::Rebase,
            raw::GITERR_FILESYSTEM => super::ErrorClass::Filesystem,
            _ => super::ErrorClass::None,
        }
    }

    /// Return the raw error code associated with this error.
    pub fn raw_code(&self) -> raw::git_error_code {
        macro_rules! check( ($($e:ident,)*) => (
            $(if self.code == raw::$e as c_int { raw::$e }) else *
            else {
                raw::GIT_ERROR
            }
        ) );
        check!(
            GIT_OK,
            GIT_ERROR,
            GIT_ENOTFOUND,
            GIT_EEXISTS,
            GIT_EAMBIGUOUS,
            GIT_EBUFS,
            GIT_EUSER,
            GIT_EBAREREPO,
            GIT_EUNBORNBRANCH,
            GIT_EUNMERGED,
            GIT_ENONFASTFORWARD,
            GIT_EINVALIDSPEC,
            GIT_ECONFLICT,
            GIT_ELOCKED,
            GIT_EMODIFIED,
            GIT_EAUTH,
            GIT_ECERTIFICATE,
            GIT_EAPPLIED,
            GIT_EPEEL,
            GIT_EEOF,
            GIT_EINVALID,
            GIT_EUNCOMMITTED,
            GIT_PASSTHROUGH,
            GIT_ITEROVER,
        )
    }

    /// Return the raw error class associated with this error.
    pub fn raw_class(&self) -> raw::git_error_t {
        macro_rules! check( ($($e:ident,)*) => (
            $(if self.klass == raw::$e as c_int { raw::$e }) else *
            else {
                raw::GITERR_NONE
            }
        ) );
        check!(
            GITERR_NONE,
            GITERR_NOMEMORY,
            GITERR_OS,
            GITERR_INVALID,
            GITERR_REFERENCE,
            GITERR_ZLIB,
            GITERR_REPOSITORY,
            GITERR_CONFIG,
            GITERR_REGEX,
            GITERR_ODB,
            GITERR_INDEX,
            GITERR_OBJECT,
            GITERR_NET,
            GITERR_TAG,
            GITERR_TREE,
            GITERR_INDEXER,
            GITERR_SSL,
            GITERR_SUBMODULE,
            GITERR_THREAD,
            GITERR_STASH,
            GITERR_CHECKOUT,
            GITERR_FETCHHEAD,
            GITERR_MERGE,
            GITERR_SSH,
            GITERR_FILTER,
            GITERR_REVERT,
            GITERR_CALLBACK,
            GITERR_CHERRYPICK,
            GITERR_DESCRIBE,
            GITERR_REBASE,
            GITERR_FILESYSTEM,
        )
    }

    /// Return the message associated with this error
    pub fn message(&self) -> &str { &self.message }
}

impl error::Error for Error {
    fn description(&self) -> &str { &self.message }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[{}/{}] ", self.klass, self.code));
        f.write_str(&self.message)
    }
}

impl From<NulError> for Error {
    fn from(_: NulError) -> Error {
        Error::from_str("data contained a nul byte that could not be \
                         represented as a string")
    }
}

impl From<JoinPathsError> for Error {
    fn from(e: JoinPathsError) -> Error {
        Error::from_str(error::Error::description(&e))
    }
}

#[cfg(test)]
mod tests {
    use {ErrorClass, ErrorCode};

    #[test]
    fn smoke() {
        let (_td, repo) = ::test::repo_init();

        let err = repo.find_submodule("does_not_exist").err().unwrap();
        assert_eq!(err.code(), ErrorCode::NotFound);
        assert_eq!(err.class(), ErrorClass::Submodule);
    }
}
<commit_msg>Implement PartialEq for git2::Error (and thus Result<T, git2::Error>)<commit_after>use std::env::JoinPathsError;
use std::ffi::{CStr, NulError};
use std::error;
use std::fmt;
use std::str;
use libc::c_int;

use {raw, ErrorClass, ErrorCode};

/// A structure to represent errors coming out of libgit2.
#[derive(Debug,PartialEq)]
pub struct Error {
    code: c_int,
    klass: c_int,
    message: String,
}

impl Error {
    /// Returns the last error, or `None` if one is not available.
    pub fn last_error(code: c_int) -> Option<Error> {
        ::init();
        unsafe {
            let ptr = raw::giterr_last();
            if ptr.is_null() {
                None
            } else {
                Some(Error::from_raw(code, ptr))
            }
        }
    }

    unsafe fn from_raw(code: c_int, ptr: *const raw::git_error) -> Error {
        let msg = CStr::from_ptr((*ptr).message as *const _).to_bytes();
        let msg = str::from_utf8(msg).unwrap();
        Error { code: code, klass: (*ptr).klass, message: msg.to_string() }
    }

    /// Creates a new error from the given string as the error.
    pub fn from_str(s: &str) -> Error {
        Error {
            code: raw::GIT_ERROR as c_int,
            klass: raw::GITERR_NONE as c_int,
            message: s.to_string(),
        }
    }

    /// Return the error code associated with this error.
    pub fn code(&self) -> ErrorCode {
        match self.raw_code() {
            raw::GIT_OK => super::ErrorCode::GenericError,
            raw::GIT_ERROR => super::ErrorCode::GenericError,
            raw::GIT_ENOTFOUND => super::ErrorCode::NotFound,
            raw::GIT_EEXISTS => super::ErrorCode::Exists,
            raw::GIT_EAMBIGUOUS => super::ErrorCode::Ambiguous,
            raw::GIT_EBUFS => super::ErrorCode::BufSize,
            raw::GIT_EUSER => super::ErrorCode::User,
            raw::GIT_EBAREREPO => super::ErrorCode::BareRepo,
            raw::GIT_EUNBORNBRANCH => super::ErrorCode::UnbornBranch,
            raw::GIT_EUNMERGED => super::ErrorCode::Unmerged,
            raw::GIT_ENONFASTFORWARD => super::ErrorCode::NotFastForward,
            raw::GIT_EINVALIDSPEC => super::ErrorCode::InvalidSpec,
            raw::GIT_ECONFLICT => super::ErrorCode::Conflict,
            raw::GIT_ELOCKED => super::ErrorCode::Locked,
            raw::GIT_EMODIFIED => super::ErrorCode::Modified,
            raw::GIT_PASSTHROUGH => super::ErrorCode::GenericError,
            raw::GIT_ITEROVER => super::ErrorCode::GenericError,
            raw::GIT_EAUTH => super::ErrorCode::Auth,
            raw::GIT_ECERTIFICATE => super::ErrorCode::Certificate,
            raw::GIT_EAPPLIED => super::ErrorCode::Applied,
            raw::GIT_EPEEL => super::ErrorCode::Peel,
            raw::GIT_EEOF => super::ErrorCode::Eof,
            raw::GIT_EINVALID => super::ErrorCode::Invalid,
            raw::GIT_EUNCOMMITTED => super::ErrorCode::Uncommitted,
            raw::GIT_EDIRECTORY => super::ErrorCode::Directory,
            _ => super::ErrorCode::GenericError,
        }
    }

    /// Return the error class associated with this error.
    pub fn class(&self) -> ErrorClass {
        match self.raw_class() {
            raw::GITERR_NONE => super::ErrorClass::None,
            raw::GITERR_NOMEMORY => super::ErrorClass::NoMemory,
            raw::GITERR_OS => super::ErrorClass::Os,
            raw::GITERR_INVALID => super::ErrorClass::Invalid,
            raw::GITERR_REFERENCE => super::ErrorClass::Reference,
            raw::GITERR_ZLIB => super::ErrorClass::Zlib,
            raw::GITERR_REPOSITORY => super::ErrorClass::Repository,
            raw::GITERR_CONFIG => super::ErrorClass::Config,
            raw::GITERR_REGEX => super::ErrorClass::Regex,
            raw::GITERR_ODB => super::ErrorClass::Odb,
            raw::GITERR_INDEX => super::ErrorClass::Index,
            raw::GITERR_OBJECT => super::ErrorClass::Object,
            raw::GITERR_NET => super::ErrorClass::Net,
            raw::GITERR_TAG => super::ErrorClass::Tag,
            raw::GITERR_TREE => super::ErrorClass::Tree,
            raw::GITERR_INDEXER => super::ErrorClass::Indexer,
            raw::GITERR_SSL => super::ErrorClass::Ssl,
            raw::GITERR_SUBMODULE => super::ErrorClass::Submodule,
            raw::GITERR_THREAD => super::ErrorClass::Thread,
            raw::GITERR_STASH => super::ErrorClass::Stash,
            raw::GITERR_CHECKOUT => super::ErrorClass::Checkout,
            raw::GITERR_FETCHHEAD => super::ErrorClass::FetchHead,
            raw::GITERR_MERGE => super::ErrorClass::Merge,
            raw::GITERR_SSH => super::ErrorClass::Ssh,
            raw::GITERR_FILTER => super::ErrorClass::Filter,
            raw::GITERR_REVERT => super::ErrorClass::Revert,
            raw::GITERR_CALLBACK => super::ErrorClass::Callback,
            raw::GITERR_CHERRYPICK => super::ErrorClass::CherryPick,
            raw::GITERR_DESCRIBE => super::ErrorClass::Describe,
            raw::GITERR_REBASE => super::ErrorClass::Rebase,
            raw::GITERR_FILESYSTEM => super::ErrorClass::Filesystem,
            _ => super::ErrorClass::None,
        }
    }

    /// Return the raw error code associated with this error.
    pub fn raw_code(&self) -> raw::git_error_code {
        macro_rules! check( ($($e:ident,)*) => (
            $(if self.code == raw::$e as c_int { raw::$e }) else *
            else {
                raw::GIT_ERROR
            }
        ) );
        check!(
            GIT_OK,
            GIT_ERROR,
            GIT_ENOTFOUND,
            GIT_EEXISTS,
            GIT_EAMBIGUOUS,
            GIT_EBUFS,
            GIT_EUSER,
            GIT_EBAREREPO,
            GIT_EUNBORNBRANCH,
            GIT_EUNMERGED,
            GIT_ENONFASTFORWARD,
            GIT_EINVALIDSPEC,
            GIT_ECONFLICT,
            GIT_ELOCKED,
            GIT_EMODIFIED,
            GIT_EAUTH,
            GIT_ECERTIFICATE,
            GIT_EAPPLIED,
            GIT_EPEEL,
            GIT_EEOF,
            GIT_EINVALID,
            GIT_EUNCOMMITTED,
            GIT_PASSTHROUGH,
            GIT_ITEROVER,
        )
    }

    /// Return the raw error class associated with this error.
    pub fn raw_class(&self) -> raw::git_error_t {
        macro_rules! check( ($($e:ident,)*) => (
            $(if self.klass == raw::$e as c_int { raw::$e }) else *
            else {
                raw::GITERR_NONE
            }
        ) );
        check!(
            GITERR_NONE,
            GITERR_NOMEMORY,
            GITERR_OS,
            GITERR_INVALID,
            GITERR_REFERENCE,
            GITERR_ZLIB,
            GITERR_REPOSITORY,
            GITERR_CONFIG,
            GITERR_REGEX,
            GITERR_ODB,
            GITERR_INDEX,
            GITERR_OBJECT,
            GITERR_NET,
            GITERR_TAG,
            GITERR_TREE,
            GITERR_INDEXER,
            GITERR_SSL,
            GITERR_SUBMODULE,
            GITERR_THREAD,
            GITERR_STASH,
            GITERR_CHECKOUT,
            GITERR_FETCHHEAD,
            GITERR_MERGE,
            GITERR_SSH,
            GITERR_FILTER,
            GITERR_REVERT,
            GITERR_CALLBACK,
            GITERR_CHERRYPICK,
            GITERR_DESCRIBE,
            GITERR_REBASE,
            GITERR_FILESYSTEM,
        )
    }

    /// Return the message associated with this error
    pub fn message(&self) -> &str { &self.message }
}

impl error::Error for Error {
    fn description(&self) -> &str { &self.message }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[{}/{}] ", self.klass, self.code));
        f.write_str(&self.message)
    }
}

impl From<NulError> for Error {
    fn from(_: NulError) -> Error {
        Error::from_str("data contained a nul byte that could not be \
                         represented as a string")
    }
}

impl From<JoinPathsError> for Error {
    fn from(e: JoinPathsError) -> Error {
        Error::from_str(error::Error::description(&e))
    }
}

#[cfg(test)]
mod tests {
    use {ErrorClass, ErrorCode};

    #[test]
    fn smoke() {
        let (_td, repo) = ::test::repo_init();

        let err = repo.find_submodule("does_not_exist").err().unwrap();
        assert_eq!(err.code(), ErrorCode::NotFound);
        assert_eq!(err.class(), ErrorClass::Submodule);
    }
}
<|endoftext|>


<commit_before>use crate::convert::*;
use core::hash::Hasher;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [`AHasher`] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
    key: u128,
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> Self {
        Self {
            buffer: [key0, key1],
            key: [key1, key0].convert(),
        }
    }

    #[cfg(test)]
    pub(crate) fn test_with_keys(key1: u64, key2: u64) -> AHasher {
        use crate::scramble_keys;
        let (k1, k2) = scramble_keys(key1, key2);
        AHasher {
            buffer: [k1, k2],
            key: [k2, k1].convert(),
        }
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshashx2(self.buffer.convert(), i, self.key).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] = self.buffer[1].wrapping_add(length);
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() <= 8 {
            let value: [u64; 2] = if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    [data.read_u32().0 as u64, data.read_last_u32() as u64]
                } else {
                    //len 2-3
                    [data.read_u16().0 as u64, data[data.len() - 1] as u64]
                }
            } else {
                if data.len() > 0 {
                    [data[0] as u64, 0]
                } else {
                    [0, 0]
                }
            };
            self.buffer = aeshashx2(self.buffer.convert(), value.convert(), self.key).convert();
        } else {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 32 {
                        let (b1, rest) = data.read_u128();
                        self.buffer = aeshashx2(self.buffer.convert(), b1, self.key).convert();
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        par_block = aeshashx2(par_block, b2, self.key);
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    self.buffer = aeshashx2(self.buffer.convert(), b1, self.key).convert();
                    let (b2, _) = rest.read_u128();
                    par_block = aeshashx2(par_block, b2, self.key);
                    self.buffer = aeshashx2(self.buffer.convert(), par_block, self.key).convert();
                } else {
                    //len 33-64
                    let (head, _) = data.split_at(32);
                    let (_, tail) = data.split_at(data.len() - 32);
                    self.buffer = aeshashx2(self.buffer.convert(), head.read_u128().0, self.key).convert();
                    self.buffer = aeshashx2(self.buffer.convert(), head.read_last_u128(), self.key).convert();
                    self.buffer = aeshashx2(self.buffer.convert(), tail.read_u128().0, self.key).convert();
                    self.buffer = aeshashx2(self.buffer.convert(), tail.read_last_u128(), self.key).convert();
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.buffer = aeshashx2(self.buffer.convert(), data.read_u128().0, self.key).convert();
                    self.buffer = aeshashx2(self.buffer.convert(), data.read_last_u128(), self.key).convert();
                } else {
                    //len 9-16
                    let value: [u64; 2] = [data.read_u64().0, data.read_last_u64()];
                    self.buffer = aeshashx2(self.buffer.convert(), value.convert(), self.key).convert();
                }
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(self.buffer.convert(), self.key).convert();
        result[0] //.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    use core::mem::transmute;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshashx2(value: u128, k1: u128, k2: u128) -> u128 {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    use core::mem::transmute;
    unsafe {
        let value = transmute(value);
        let value = _mm_aesdec_si128(value, transmute(k1));
        transmute(_mm_aesdec_si128(value, transmute(k2)))
    }
}

#[cfg(test)]
mod tests {
    use crate::aes_hash::*;
    use crate::convert::Convert;
    use std::collections::HashMap;
    use std::hash::BuildHasherDefault;

    #[cfg(feature = "compile-time-rng")]
    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[cfg(feature = "compile-time-rng")]
    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>Extract common 'hash in' code<commit_after>use crate::convert::*;
use core::hash::Hasher;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [`AHasher`] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
    key: u128,
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub fn new_with_keys(key0: u64, key1: u64) -> Self {
        Self {
            buffer: [key0, key1],
            key: [key1, key0].convert(),
        }
    }

    #[cfg(test)]
    pub(crate) fn test_with_keys(key1: u64, key2: u64) -> AHasher {
        use crate::scramble_keys;
        let (k1, k2) = scramble_keys(key1, key2);
        AHasher {
            buffer: [k1, k2],
            key: [k2, k1].convert(),
        }
    }

    #[inline(always)]
    fn hash_in(&mut self, new_value: u128) {
        self.buffer = aeshashx2(self.buffer.convert(), new_value, self.key).convert();
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.hash_in(i);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] = self.buffer[1].wrapping_add(length);
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() <= 8 {
            let value: [u64; 2] = if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    [data.read_u32().0 as u64, data.read_last_u32() as u64]
                } else {
                    //len 2-3
                    [data.read_u16().0 as u64, data[data.len() - 1] as u64]
                }
            } else {
                if data.len() > 0 {
                    [data[0] as u64, 0]
                } else {
                    [0, 0]
                }
            };
            self.hash_in(value.convert());
        } else {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 32 {
                        let (b1, rest) = data.read_u128();
                        self.buffer = aeshashx2(self.buffer.convert(), b1, self.key).convert();
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        par_block = aeshashx2(par_block, b2, self.key);
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    self.buffer = aeshashx2(self.buffer.convert(), b1, self.key).convert();
                    let (b2, _) = rest.read_u128();
                    par_block = aeshashx2(par_block, b2, self.key);
                    self.buffer = aeshashx2(self.buffer.convert(), par_block, self.key).convert();
                } else {
                    //len 33-64
                    let (head, _) = data.split_at(32);
                    let (_, tail) = data.split_at(data.len() - 32);
                    self.hash_in(head.read_u128().0);
                    self.hash_in(head.read_last_u128());
                    self.hash_in(tail.read_u128().0);
                    self.hash_in(tail.read_last_u128());
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.hash_in(data.read_u128().0);
                    self.hash_in(data.read_last_u128());
                } else {
                    //len 9-16
                    let value: [u64; 2] = [data.read_u64().0, data.read_last_u64()];
                    self.hash_in(value.convert());
                }
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(self.buffer.convert(), self.key).convert();
        result[0] //.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    use core::mem::transmute;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshashx2(value: u128, k1: u128, k2: u128) -> u128 {
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    use core::mem::transmute;
    unsafe {
        let value = transmute(value);
        let value = _mm_aesdec_si128(value, transmute(k1));
        transmute(_mm_aesdec_si128(value, transmute(k2)))
    }
}

#[cfg(test)]
mod tests {
    use crate::aes_hash::*;
    use crate::convert::Convert;
    use std::collections::HashMap;
    use std::hash::BuildHasherDefault;

    #[cfg(feature = "compile-time-rng")]
    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[cfg(feature = "compile-time-rng")]
    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::sync::mpsc::channel;

use matrix::{self, ClMatrix, ClMatrixMode};

// A function that takes an opencl context, a list of inputs, and a list of outputs
pub type Operation = Fn(&matrix::Context, &[&ClMatrix<f32>], &[&ClMatrix<f32>]);

pub struct Node {
    op: Rc<Operation>,
    op_d: Vec<Rc<Operation>>, // Derivative ops, with respect to each input, respectively
    pub inputs: Vec<VarIndex>,
    pub outputs: Vec<VarIndex>,
}

pub struct Graph {
    nodes: Vec<Node>,
    vars: Vec<ClMatrix<f32>>,
}

impl Graph {
    pub fn new() -> Self {
        Graph {
            nodes: vec![],
            vars: vec![],
        }
    }

    pub fn add_node(&mut self,
                    ctx: &matrix::Context,
                    op: Rc<Operation>,
                    op_d: Vec<Rc<Operation>>,
                    out_shapes: &[(u64, u64)])
                    -> NodeIndex {
        let mut outputs = vec![];
        for &(rows, cols) in out_shapes {
            let var_index = VarIndex(self.vars.len());
            self.vars.push(ClMatrix::new(ctx, rows as usize, cols as usize, ClMatrixMode::Mut));
            outputs.push(var_index);
        }
        self.nodes.push(Node { op: op, op_d: op_d, inputs: vec![], outputs: outputs });
        NodeIndex(self.nodes.len()-1)
    }

    pub fn add_variable(&mut self, ctx: &matrix::Context, shape: (u64, u64)) -> VarIndex {
        self.vars.push(ClMatrix::new(ctx, shape.0 as usize, shape.1 as usize, ClMatrixMode::Mut));
        VarIndex(self.vars.len()-1)
    }

    pub fn set_node_inputs(&mut self, n: NodeIndex, inputs: &[VarIndex]) {
        n.get_mut(self).inputs.extend_from_slice(inputs);
    }

    pub fn run(&mut self) {
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
pub struct VarIndex(usize);

impl VarIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a ClMatrix<f32> {
        &g.vars[self.0]
    }

    pub fn get_mut<'a>(&self, g: &'a mut Graph) -> &'a mut ClMatrix<f32> {
        &mut g.vars[self.0]
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a Node {
        &g.nodes[self.0]
    }

    pub fn get_mut<'a>(&self, g: &'a mut Graph) -> &'a mut Node {
        &mut g.nodes[self.0]
    }
}

#[test]
fn it_works() {
    let mat_mul =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].multiply(ctx, i[1], o[0]);
        });
    // Derivative with respect to first input
    let mat_mul_d0 =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[1].copy_to(ctx, o[0]);
        });
    // Derivative with respect to second input
    let mat_mul_d1 =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].copy_to(ctx, o[0]);
        });
    let relu =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].max(ctx, 0.0, o[0]);
        });
    let relu_d =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].dmax(ctx, 0.0, o[0]);
        });

    // Special placeholder op
    /*let placeholder =
        Rc::new(move |ctx: &matrix::Context, i, o| {
            i[0].dmax(ctx, 0.0, o[0]);
        });*/

    let mut ctx = matrix::Context::new();

    let mut graph = Graph::new();
    let a = graph.add_variable(&ctx, (1, 2));
    let wa = graph.add_variable(&ctx, (2, 3));
    let node = graph.add_node(&ctx, mat_mul, vec![mat_mul_d0, mat_mul_d1], &[(1, 3)]);
    graph.set_node_inputs(node, &[a, wa]);
    let out = node.get(&graph).outputs[0];
}
<commit_msg>Got a basic forward pass<commit_after>use std::rc::Rc;
use std::sync::mpsc::channel;

use matrix::{self, ClMatrix, ClMatrixMode};

// A function that takes an opencl context, a list of inputs, and a list of outputs
pub type Operation = Fn(&matrix::Context,
                        &mut Graph,
                        NodeIndex);

pub struct Node {
    forward: Rc<Operation>, // Operation to perform on forward pass
    backward: Vec<Rc<Operation>>, // Derivative ops, with respect to each input, respectively
    pub inputs: Vec<VarIndex>,
    pub outputs: Vec<VarIndex>,
    pub out_events: Vec<matrix::cl_matrix::Event>,
}

pub struct Graph {
    nodes: Vec<Node>,
    vars: Vec<ClMatrix<f32>>,
}

impl Graph {
    pub fn new() -> Self {
        Graph {
            nodes: vec![],
            vars: vec![],
        }
    }

    pub fn add_node(&mut self,
                    ctx: &matrix::Context,
                    forward: Rc<Operation>,
                    backward: Vec<Rc<Operation>>,
                    out_shapes: &[(u64, u64)])
                    -> NodeIndex {
        let mut outputs = vec![];
        for &(rows, cols) in out_shapes {
            let var_index = VarIndex(self.vars.len());
            self.vars.push(ClMatrix::new(ctx, rows as usize, cols as usize, ClMatrixMode::Mut));
            outputs.push(var_index);
        }
        self.nodes.push(Node { forward: forward,
                               backward: backward,
                               inputs: vec![],
                               outputs: outputs,
                               out_events: vec![] });
        NodeIndex(self.nodes.len()-1)
    }

    pub fn add_variable(&mut self, ctx: &matrix::Context, shape: (u64, u64)) -> VarIndex {
        self.vars.push(ClMatrix::new(ctx, shape.0 as usize, shape.1 as usize, ClMatrixMode::Mut));
        VarIndex(self.vars.len()-1)
    }

    pub fn set_node_inputs(&mut self, n: NodeIndex, inputs: &[VarIndex]) {
        n.get_mut(self).inputs.extend_from_slice(inputs);
    }

    pub fn run(&mut self, ctx: &matrix::Context) {
        // Clear all the out_events
        for node in &mut self.nodes {
            node.out_events.clear();
        }

        let op = self.nodes[0].forward.clone();
        (op)(ctx, self, NodeIndex(0));
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
pub struct VarIndex(usize);

impl VarIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a ClMatrix<f32> {
        &g.vars[self.0]
    }

    pub fn get_mut<'a>(&self, g: &'a mut Graph) -> &'a mut ClMatrix<f32> {
        &mut g.vars[self.0]
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone)]
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn get<'a>(&self, g: &'a Graph) -> &'a Node {
        &g.nodes[self.0]
    }

    pub fn get_mut<'a>(&self, g: &'a mut Graph) -> &'a mut Node {
        &mut g.nodes[self.0]
    }
}

#[test]
fn it_works() {
    let mat_mul =
        Rc::new(move |ctx: &matrix::Context, g: &mut Graph, n: NodeIndex| {
            let event = {
                let node = n.get(g);
                let a = node.inputs[0].get(g);
                let b = node.inputs[1].get(g);
                let c = node.outputs[0].get(g);
                a.cross(ctx, b, c) // c = a*b
            };
            n.get_mut(g).out_events.push(event);
        });
    // Derivative with respect to first input
    /*let mat_mul_d0 =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            let event = {
                let node = n.get(g);
                let a = node.inputs[0].get(g);
                let b = node.outputs[0].get(g);
                a.copy_to(ctx, b);
            };
            n.get_mut().out_events.push(event);
        });
    // Derivative with respect to second input
    let mat_mul_d1 =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].copy_to(ctx, o[0]);
        });
    let relu =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].max(ctx, 0.0, o[0]);
        });
    let relu_d =
        Rc::new(move |ctx: &matrix::Context, i: &[&ClMatrix<f32>], o: &[&ClMatrix<f32>]| {
            i[0].dmax(ctx, 0.0, o[0]);
        });*/

    let mut ctx = matrix::Context::new();

    // Setup the graph
    let mut graph = Graph::new();
    let a = graph.add_variable(&ctx, (1, 2));
    let wa = graph.add_variable(&ctx, (2, 3));
    let node = graph.add_node(&ctx, mat_mul, vec![/*mat_mul_d0, mat_mul_d1*/], &[(1, 3)]);
    graph.set_node_inputs(node, &[a, wa]);

    // Send some input data
    let a_cpu = matrix::Matrix::from_vec(1, 2, vec![1.0, 1.0]);
    let wa_cpu = matrix::Matrix::from_vec(2, 3, vec![0.5, 0.3, 0.2, 0.6, 0.7, 0.7]);
    a.get(&graph).set(&ctx, &a_cpu);
    wa.get(&graph).set(&ctx, &wa_cpu);

    // Run the network
    graph.run(&ctx);
    let out = {
        let ref out_event = node.get(&graph).out_events[0];
        out_event.get(&ctx, node.get(&graph).outputs[0].get(&graph))
    };
    println!("{:?}", out);
    assert!(false);
}
<|endoftext|>