<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use darling::{FromDeriveInput, FromField, FromVariant};
use quote::{ToTokens, Tokens};
use std::collections::HashSet;
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
use syn::{GenericArgument, GenericParam, Ident, ImplGenerics, Path};
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray, TypeGenerics};
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate};
use syn::visit::{self, Visit};
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};

pub struct WhereClause<'input, 'path> {
    pub inner: Option<syn::WhereClause>,
    pub params: Vec<&'input TypeParam>,
    trait_path: &'path Path,
    trait_output: Option<Ident>,
    bounded_types: HashSet<Type>,
}

impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        self.inner.to_tokens(tokens);
    }
}

impl<'input, 'path> WhereClause<'input, 'path> {
    pub fn add_trait_bound(&mut self, ty: &Type) {
        let trait_path = self.trait_path;
        let mut found = self.trait_output.map(|_| HashSet::new());
        if self.bounded_types.contains(&ty) {
            return;
        }
        if !is_parameterized(&ty, &self.params, found.as_mut()) {
            return;
        }
        self.bounded_types.insert(ty.clone());

        let output = if let Some(output) = self.trait_output {
            output
        } else {
            add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
            return;
        };

        if let Type::Path(syn::TypePath { ref path, .. }) = *ty {
            if path_to_ident(path).is_some() {
                add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
                return;
            }
        }

        let output_type = map_type_params(ty, &self.params, &mut |ident| {
            let ty = Type::Path(syn::TypePath { qself: None, path: ident.clone().into() });
            fmap_output_type(ty, trait_path, output)
        });

        let pred = where_predicate(
            ty.clone(),
            trait_path,
            Some((output, output_type)),
        );

        add_predicate(&mut self.inner, pred);

        if let Some(found) = found {
            for ident in found {
                let ty = Type::Path(syn::TypePath { qself: None, path: ident.into() });
                if !self.bounded_types.contains(&ty) {
                    self.bounded_types.insert(ty.clone());
                    add_predicate(
                        &mut self.inner,
                        where_predicate(ty, trait_path, None),
                    );
                };
            }
        }
    }
}

pub fn add_predicate(
    where_clause: &mut Option<syn::WhereClause>,
    pred: WherePredicate,
) {
    where_clause.get_or_insert(parse_quote!(where)).predicates.push(pred);
}

pub fn fmap_match<F>(
    input: &DeriveInput,
    bind_style: BindStyle,
    mut f: F,
) -> Tokens
where
    F: FnMut(BindingInfo) -> Tokens,
{
    let mut s = synstructure::Structure::new(input);
    s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); });
    s.each_variant(|variant| {
        let (mapped, mapped_fields) = value(variant, "mapped");
        let fields_pairs = variant.bindings().into_iter().zip(mapped_fields);
        let mut computations = quote!();
        computations.append_all(fields_pairs.map(|(field, mapped_field)| {
            let expr = f(field.clone());
            quote! { let #mapped_field = #expr; }
        }));
        computations.append_all(mapped);
        Some(computations)
    })
}

pub fn fmap_output_type(
    ty: Type,
    trait_path: &Path,
    trait_output: Ident,
) -> Type {
    parse_quote!(<#ty as ::#trait_path>::#trait_output)
}

pub fn fmap_trait_output(
    input: &DeriveInput,
    trait_path: &Path,
    trait_output: Ident,
) -> Path {
    let segment = PathSegment {
        ident: input.ident.clone(),
        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
            args: input.generics.params.iter().map(|arg| {
                match arg {
                    &GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()),
                    &GenericParam::Type(ref data) => {
                        let ident = data.ident;
                        GenericArgument::Type(
                            fmap_output_type(
                                parse_quote!(#ident),
                                trait_path,
                                trait_output
                            )
                        )
                    },
                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
                }
            }).collect(),
            colon2_token: Default::default(),
            gt_token: Default::default(),
            lt_token: Default::default(),

        })
    };
    segment.into()
}

pub fn is_parameterized(
    ty: &Type,
    params: &[&TypeParam],
    found: Option<&mut HashSet<Ident>>,
) -> bool {
    struct IsParameterized<'a, 'b> {
        params: &'a [&'a TypeParam],
        has_free: bool,
        found: Option<&'b mut HashSet<Ident>>,
    }

    impl<'a, 'b, 'ast> Visit<'ast> for IsParameterized<'a, 'b> {
        fn visit_path(&mut self, path: &'ast Path) {
            if let Some(ident) = path_to_ident(path) {
                if self.params.iter().any(|param| param.ident == ident) {
                    self.has_free = true;
                    if let Some(ref mut found) = self.found {
                        found.insert(ident.clone());
                    }
                }
            }
            visit::visit_path(self, path);
        }
    }

    let mut visitor = IsParameterized { params, has_free: false, found };
    visitor.visit_type(ty);
    visitor.has_free
}

pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
where
    F: FnMut(&Ident) -> Type,
{
    match *ty {
        Type::Slice(ref inner) => {
            Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        Type::Array(ref inner) => { //ref ty, ref expr) => {
            Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        ref ty @ Type::Never(_) => ty.clone(),
        Type::Tuple(ref inner) => {
            Type::from(
                TypeTuple {
                    elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(),
                    ..inner.clone()
                }
            )
        },
        Type::Path(TypePath { qself: None, ref path }) => {
            if let Some(ident) = path_to_ident(path) {
                if params.iter().any(|param| param.ident == ident) {
                    return f(ident);
                }
            }
            Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) })
        }
        Type::Path(TypePath { ref qself, ref path }) => {
            Type::from(TypePath {
                qself: qself.as_ref().map(|qself| {
                    QSelf {
                        ty: Box::new(map_type_params(&qself.ty, params, f)),
                        position: qself.position,
                        ..qself.clone()
                    }
                }),
                path: map_type_params_in_path(path, params, f),
            })
        },
        Type::Paren(ref inner) => {
            Type::from(TypeParen { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        ref ty => panic!("type {:?} cannot be mapped yet", ty),
    }
}

fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
where
    F: FnMut(&Ident) -> Type,
{
    Path {
        leading_colon: path.leading_colon,
        segments: path.segments.iter().map(|segment| {
            PathSegment {
                ident: segment.ident.clone(),
                arguments: match segment.arguments {
                    PathArguments::AngleBracketed(ref data) => {
                        PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                            args: data.args.iter().map(|arg| {
                                match arg {
                                    ty @ &GenericArgument::Lifetime(_) => ty.clone(),
                                    &GenericArgument::Type(ref data) => {
                                        GenericArgument::Type(map_type_params(data, params, f))
                                    },
                                    &GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding {
                                        ty: map_type_params(&data.ty, params, f),
                                        ..data.clone()
                                    }),
                                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
                                }
                            }).collect(),
                            ..data.clone()
                        })
                    },
                    ref arg @ PathArguments::None => arg.clone(),
                    ref parameters => {
                        panic!("parameters {:?} cannot be mapped yet", parameters)
                    }
                },
            }
        }).collect(),
    }
}

fn path_to_ident(path: &Path) -> Option<&Ident> {
    match *path {
        Path { leading_colon: None, ref segments } if segments.len() == 1 => {
            if segments[0].arguments.is_empty() {
                Some(&segments[0].ident)
            } else {
                None
            }
        },
        _ => None,
    }
}

pub fn parse_field_attrs<A>(field: &Field) -> A
where
    A: FromField,
{
    match A::from_field(field) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse field attributes: {}", e),
    }
}

pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
where
    A: FromDeriveInput,
{
    match A::from_derive_input(input) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse input attributes: {}", e),
    }
}

pub fn parse_variant_attrs<A>(variant: &VariantAst) -> A
where
    A: FromVariant,
{
    let v = Variant {
        ident: *variant.ident,
        attrs: variant.attrs.to_vec(),
        fields: variant.fields.clone(),
        discriminant: variant.discriminant.clone(),
    };
    match A::from_variant(&v) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse variant attributes: {}", e),
    }
}

pub fn ref_pattern<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bind_with(|_| BindStyle::Ref);
    v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
    (v.pat(), v.bindings().iter().cloned().collect())
}

pub fn trait_parts<'input, 'path>(
    input: &'input DeriveInput,
    trait_path: &'path Path,
) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>) {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let where_clause = WhereClause {
        inner: where_clause.cloned(),
        params: input.generics.type_params().into_iter().collect::<Vec<&TypeParam>>(),
        trait_path,
        trait_output: None,
        bounded_types: HashSet::new()
    };
    (impl_generics, ty_generics, where_clause)
}

fn trait_ref(path: &Path, output: Option<(Ident, Type)>) -> Path {
    let segments = path.segments.iter().collect::<Vec<&PathSegment>>();
    let (name, parent) = segments.split_last().unwrap();

    let last_segment: PathSegment = if let Some((param, ty)) = output {
        parse_quote!(#name<#param = #ty>)
    } else {
        parse_quote!(#name)
    };
    parse_quote!(::#(#parent::)*#last_segment)
}

pub fn value<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
    v.bind_with(|_| BindStyle::Move);
    (v.pat(), v.bindings().iter().cloned().collect())
}

pub fn where_predicate(
    bounded_ty: Type,
    trait_path: &Path,
    trait_output: Option<(Ident, Type)>,
) -> WherePredicate {
    let trait_ref = trait_ref(trait_path, trait_output);
    parse_quote!(#bounded_ty: #trait_ref)
}

/// Transforms "FooBar" to "foo-bar".
///
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
/// is prepended with "-".
pub fn to_css_identifier(mut camel_case: &str) -> String {
    camel_case = camel_case.trim_right_matches('_');
    let mut first = true;
    let mut result = String::with_capacity(camel_case.len());
    while let Some(segment) = split_camel_segment(&mut camel_case) {
        if first {
            match segment {
                "Moz" | "Webkit" | "Servo" => first = false,
                _ => {},
            }
        }
        if !first {
            result.push_str("-");
        }
        first = false;
        result.push_str(&segment.to_lowercase());
    }
    result
}

/// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar".
fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> {
    let index = match camel_case.chars().next() {
        None => return None,
        Some(ch) => ch.len_utf8(),
    };
    let end_position = camel_case[index..]
        .find(char::is_uppercase)
        .map_or(camel_case.len(), |pos| index + pos);
    let result = &camel_case[..end_position];
    *camel_case = &camel_case[end_position..];
    Some(result)
}
<commit_msg>Kill fmap_output_type<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use darling::{FromDeriveInput, FromField, FromVariant};
use quote::{ToTokens, Tokens};
use std::collections::HashSet;
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
use syn::{GenericArgument, GenericParam, Ident, ImplGenerics, Path};
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray, TypeGenerics};
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate};
use syn::visit::{self, Visit};
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};

pub struct WhereClause<'input, 'path> {
    pub inner: Option<syn::WhereClause>,
    pub params: Vec<&'input TypeParam>,
    trait_path: &'path Path,
    trait_output: Option<Ident>,
    bounded_types: HashSet<Type>,
}

impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
    fn to_tokens(&self, tokens: &mut Tokens) {
        self.inner.to_tokens(tokens);
    }
}

impl<'input, 'path> WhereClause<'input, 'path> {
    pub fn add_trait_bound(&mut self, ty: &Type) {
        let trait_path = self.trait_path;
        let mut found = self.trait_output.map(|_| HashSet::new());
        if self.bounded_types.contains(&ty) {
            return;
        }
        if !is_parameterized(&ty, &self.params, found.as_mut()) {
            return;
        }
        self.bounded_types.insert(ty.clone());

        let output = if let Some(output) = self.trait_output {
            output
        } else {
            add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
            return;
        };

        if let Type::Path(syn::TypePath { ref path, .. }) = *ty {
            if path_to_ident(path).is_some() {
                add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
                return;
            }
        }

        let output_type = map_type_params(ty, &self.params, &mut |ident| {
            parse_quote!(<#ident as ::#trait_path>::#output)
        });

        let pred = where_predicate(
            ty.clone(),
            trait_path,
            Some((output, output_type)),
        );

        add_predicate(&mut self.inner, pred);

        if let Some(found) = found {
            for ident in found {
                let ty = Type::Path(syn::TypePath { qself: None, path: ident.into() });
                if !self.bounded_types.contains(&ty) {
                    self.bounded_types.insert(ty.clone());
                    add_predicate(
                        &mut self.inner,
                        where_predicate(ty, trait_path, None),
                    );
                };
            }
        }
    }
}

pub fn add_predicate(
    where_clause: &mut Option<syn::WhereClause>,
    pred: WherePredicate,
) {
    where_clause.get_or_insert(parse_quote!(where)).predicates.push(pred);
}

pub fn fmap_match<F>(
    input: &DeriveInput,
    bind_style: BindStyle,
    mut f: F,
) -> Tokens
where
    F: FnMut(BindingInfo) -> Tokens,
{
    let mut s = synstructure::Structure::new(input);
    s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); });
    s.each_variant(|variant| {
        let (mapped, mapped_fields) = value(variant, "mapped");
        let fields_pairs = variant.bindings().into_iter().zip(mapped_fields);
        let mut computations = quote!();
        computations.append_all(fields_pairs.map(|(field, mapped_field)| {
            let expr = f(field.clone());
            quote! { let #mapped_field = #expr; }
        }));
        computations.append_all(mapped);
        Some(computations)
    })
}

pub fn fmap_trait_output(
    input: &DeriveInput,
    trait_path: &Path,
    trait_output: Ident,
) -> Path {
    let segment = PathSegment {
        ident: input.ident.clone(),
        arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
            args: input.generics.params.iter().map(|arg| {
                match arg {
                    &GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()),
                    &GenericParam::Type(ref data) => {
                        let ident = data.ident;
                        GenericArgument::Type(
                            parse_quote!(<#ident as ::#trait_path>::#trait_output),
                        )
                    },
                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
                }
            }).collect(),
            colon2_token: Default::default(),
            gt_token: Default::default(),
            lt_token: Default::default(),

        })
    };
    segment.into()
}

pub fn is_parameterized(
    ty: &Type,
    params: &[&TypeParam],
    found: Option<&mut HashSet<Ident>>,
) -> bool {
    struct IsParameterized<'a, 'b> {
        params: &'a [&'a TypeParam],
        has_free: bool,
        found: Option<&'b mut HashSet<Ident>>,
    }

    impl<'a, 'b, 'ast> Visit<'ast> for IsParameterized<'a, 'b> {
        fn visit_path(&mut self, path: &'ast Path) {
            if let Some(ident) = path_to_ident(path) {
                if self.params.iter().any(|param| param.ident == ident) {
                    self.has_free = true;
                    if let Some(ref mut found) = self.found {
                        found.insert(ident.clone());
                    }
                }
            }
            visit::visit_path(self, path);
        }
    }

    let mut visitor = IsParameterized { params, has_free: false, found };
    visitor.visit_type(ty);
    visitor.has_free
}

pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
where
    F: FnMut(&Ident) -> Type,
{
    match *ty {
        Type::Slice(ref inner) => {
            Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        Type::Array(ref inner) => { //ref ty, ref expr) => {
            Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        ref ty @ Type::Never(_) => ty.clone(),
        Type::Tuple(ref inner) => {
            Type::from(
                TypeTuple {
                    elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(),
                    ..inner.clone()
                }
            )
        },
        Type::Path(TypePath { qself: None, ref path }) => {
            if let Some(ident) = path_to_ident(path) {
                if params.iter().any(|param| param.ident == ident) {
                    return f(ident);
                }
            }
            Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) })
        }
        Type::Path(TypePath { ref qself, ref path }) => {
            Type::from(TypePath {
                qself: qself.as_ref().map(|qself| {
                    QSelf {
                        ty: Box::new(map_type_params(&qself.ty, params, f)),
                        position: qself.position,
                        ..qself.clone()
                    }
                }),
                path: map_type_params_in_path(path, params, f),
            })
        },
        Type::Paren(ref inner) => {
            Type::from(TypeParen { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
        },
        ref ty => panic!("type {:?} cannot be mapped yet", ty),
    }
}

fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
where
    F: FnMut(&Ident) -> Type,
{
    Path {
        leading_colon: path.leading_colon,
        segments: path.segments.iter().map(|segment| {
            PathSegment {
                ident: segment.ident.clone(),
                arguments: match segment.arguments {
                    PathArguments::AngleBracketed(ref data) => {
                        PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                            args: data.args.iter().map(|arg| {
                                match arg {
                                    ty @ &GenericArgument::Lifetime(_) => ty.clone(),
                                    &GenericArgument::Type(ref data) => {
                                        GenericArgument::Type(map_type_params(data, params, f))
                                    },
                                    &GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding {
                                        ty: map_type_params(&data.ty, params, f),
                                        ..data.clone()
                                    }),
                                    ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
                                }
                            }).collect(),
                            ..data.clone()
                        })
                    },
                    ref arg @ PathArguments::None => arg.clone(),
                    ref parameters => {
                        panic!("parameters {:?} cannot be mapped yet", parameters)
                    }
                },
            }
        }).collect(),
    }
}

fn path_to_ident(path: &Path) -> Option<&Ident> {
    match *path {
        Path { leading_colon: None, ref segments } if segments.len() == 1 => {
            if segments[0].arguments.is_empty() {
                Some(&segments[0].ident)
            } else {
                None
            }
        },
        _ => None,
    }
}

pub fn parse_field_attrs<A>(field: &Field) -> A
where
    A: FromField,
{
    match A::from_field(field) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse field attributes: {}", e),
    }
}

pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
where
    A: FromDeriveInput,
{
    match A::from_derive_input(input) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse input attributes: {}", e),
    }
}

pub fn parse_variant_attrs<A>(variant: &VariantAst) -> A
where
    A: FromVariant,
{
    let v = Variant {
        ident: *variant.ident,
        attrs: variant.attrs.to_vec(),
        fields: variant.fields.clone(),
        discriminant: variant.discriminant.clone(),
    };
    match A::from_variant(&v) {
        Ok(attrs) => attrs,
        Err(e) => panic!("failed to parse variant attributes: {}", e),
    }
}

pub fn ref_pattern<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bind_with(|_| BindStyle::Ref);
    v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
    (v.pat(), v.bindings().iter().cloned().collect())
}

pub fn trait_parts<'input, 'path>(
    input: &'input DeriveInput,
    trait_path: &'path Path,
) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>) {
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let where_clause = WhereClause {
        inner: where_clause.cloned(),
        params: input.generics.type_params().into_iter().collect::<Vec<&TypeParam>>(),
        trait_path,
        trait_output: None,
        bounded_types: HashSet::new()
    };
    (impl_generics, ty_generics, where_clause)
}

fn trait_ref(path: &Path, output: Option<(Ident, Type)>) -> Path {
    let segments = path.segments.iter().collect::<Vec<&PathSegment>>();
    let (name, parent) = segments.split_last().unwrap();

    let last_segment: PathSegment = if let Some((param, ty)) = output {
        parse_quote!(#name<#param = #ty>)
    } else {
        parse_quote!(#name)
    };
    parse_quote!(::#(#parent::)*#last_segment)
}

pub fn value<'a>(
    variant: &'a VariantInfo,
    prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
    let mut v = variant.clone();
    v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
    v.bind_with(|_| BindStyle::Move);
    (v.pat(), v.bindings().iter().cloned().collect())
}

pub fn where_predicate(
    bounded_ty: Type,
    trait_path: &Path,
    trait_output: Option<(Ident, Type)>,
) -> WherePredicate {
    let trait_ref = trait_ref(trait_path, trait_output);
    parse_quote!(#bounded_ty: #trait_ref)
}

/// Transforms "FooBar" to "foo-bar".
///
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
/// is prepended with "-".
pub fn to_css_identifier(mut camel_case: &str) -> String {
    camel_case = camel_case.trim_right_matches('_');
    let mut first = true;
    let mut result = String::with_capacity(camel_case.len());
    while let Some(segment) = split_camel_segment(&mut camel_case) {
        if first {
            match segment {
                "Moz" | "Webkit" | "Servo" => first = false,
                _ => {},
            }
        }
        if !first {
            result.push_str("-");
        }
        first = false;
        result.push_str(&segment.to_lowercase());
    }
    result
}

/// Given "FooBar", returns "Foo" and sets `camel_case` to "Bar".
fn split_camel_segment<'input>(camel_case: &mut &'input str) -> Option<&'input str> {
    let index = match camel_case.chars().next() {
        None => return None,
        Some(ch) => ch.len_utf8(),
    };
    let end_position = camel_case[index..]
        .find(char::is_uppercase)
        .map_or(camel_case.len(), |pos| index + pos);
    let result = &camel_case[..end_position];
    *camel_case = &camel_case[end_position..];
    Some(result)
}
<|endoftext|>


<commit_before>use std;

import std::task;
import std::task::task;
import std::comm;
import std::comm::chan;
import std::comm::port;
import std::comm::send;
import std::comm::recv;

fn main() {
    test00();
    // test01();
    test02();
    test03();
    test04();
    test05();
    test06();
}

fn test00_start(ch: chan<int>, message: int, count: int) {
    log "Starting test00_start";
    let i: int = 0;
    while i < count {
        log "Sending Message";
        send(ch, message + 0);
        i = i + 1;
    }
    log "Ending test00_start";
}

fn test00() {
    let number_of_tasks: int = 1;
    let number_of_messages: int = 4;
    log "Creating tasks";

    let po = port();
    let ch = chan(po);

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        let thunk = bind test00_start(ch, i, number_of_messages);
        tasks += [task::spawn_joinable(thunk)];
    }
    let sum: int = 0;
    for t in tasks {
        i = 0;
        while i < number_of_messages { sum += recv(po); i = i + 1; }
    }

    for t in tasks { task::join(t); }

    log "Completed: Final number is: ";
    assert (sum ==
                number_of_messages *
                    (number_of_tasks * number_of_tasks + number_of_tasks) /
                    2);
}

fn test01() {
    let p = port();
    log "Reading from a port that is never written to.";
    let value: int = recv(p);
    log value;
}

fn test02() {
    let p = port();
    let c = chan(p);
    log "Writing to a local task channel.";
    send(c, 42);
    log "Reading from a local task port.";
    let value: int = recv(p);
    log value;
}

obj vector(mutable x: int, y: int) {
    fn length() -> int { x = x + 2; ret x + y; }
}

fn test03() {
    log "Creating object ...";
    let v: vector = vector(1, 2);
    log "created object ...";
    let t: vector = v;
    log v.length();
}

fn test04_start() {
    log "Started task";
    let i: int = 1024 * 1024;
    while i > 0 { i = i - 1; }
    log "Finished task";
}

fn test04() {
    log "Spawning lots of tasks.";
    let i: int = 4;
    while i > 0 { i = i - 1; let f = test04_start; task::spawn(f); }
    log "Finishing up.";
}

fn test05_start(ch: chan<int>) {
    send(ch, 10);
    send(ch, 20);
    send(ch, 30);
    send(ch, 30);
    send(ch, 30);
}

fn test05() {
    let po = comm::port();
    let ch = chan(po);
    task::spawn(bind test05_start(ch));
    let value: int;
    value = recv(po);
    value = recv(po);
    value = recv(po);
    log value;
}

fn test06_start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 1000000 { i = i + 1; }
    log "Finished task.";
}

fn test06() {
    let number_of_tasks: int = 4;
    log "Creating tasks";

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::spawn_joinable(bind test06_start(i))];
    }

    for t in tasks { task::join(t); }
}

<commit_msg>XFAIL task-comm<commit_after>// xfail-test
use std;

import std::task;
import std::task::task;
import std::comm;
import std::comm::chan;
import std::comm::port;
import std::comm::send;
import std::comm::recv;

fn main() {
    test00();
    // test01();
    test02();
    test03();
    test04();
    test05();
    test06();
}

fn test00_start(ch: chan<int>, message: int, count: int) {
    log "Starting test00_start";
    let i: int = 0;
    while i < count {
        log "Sending Message";
        send(ch, message + 0);
        i = i + 1;
    }
    log "Ending test00_start";
}

fn test00() {
    let number_of_tasks: int = 1;
    let number_of_messages: int = 4;
    log "Creating tasks";

    let po = port();
    let ch = chan(po);

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        let thunk = bind test00_start(ch, i, number_of_messages);
        tasks += [task::spawn_joinable(thunk)];
    }
    let sum: int = 0;
    for t in tasks {
        i = 0;
        while i < number_of_messages { sum += recv(po); i = i + 1; }
    }

    for t in tasks { task::join(t); }

    log "Completed: Final number is: ";
    assert (sum ==
                number_of_messages *
                    (number_of_tasks * number_of_tasks + number_of_tasks) /
                    2);
}

fn test01() {
    let p = port();
    log "Reading from a port that is never written to.";
    let value: int = recv(p);
    log value;
}

fn test02() {
    let p = port();
    let c = chan(p);
    log "Writing to a local task channel.";
    send(c, 42);
    log "Reading from a local task port.";
    let value: int = recv(p);
    log value;
}

obj vector(mutable x: int, y: int) {
    fn length() -> int { x = x + 2; ret x + y; }
}

fn test03() {
    log "Creating object ...";
    let v: vector = vector(1, 2);
    log "created object ...";
    let t: vector = v;
    log v.length();
}

fn test04_start() {
    log "Started task";
    let i: int = 1024 * 1024;
    while i > 0 { i = i - 1; }
    log "Finished task";
}

fn test04() {
    log "Spawning lots of tasks.";
    let i: int = 4;
    while i > 0 { i = i - 1; let f = test04_start; task::spawn(f); }
    log "Finishing up.";
}

fn test05_start(ch: chan<int>) {
    send(ch, 10);
    send(ch, 20);
    send(ch, 30);
    send(ch, 30);
    send(ch, 30);
}

fn test05() {
    let po = comm::port();
    let ch = chan(po);
    task::spawn(bind test05_start(ch));
    let value: int;
    value = recv(po);
    value = recv(po);
    value = recv(po);
    log value;
}

fn test06_start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 1000000 { i = i + 1; }
    log "Finished task.";
}

fn test06() {
    let number_of_tasks: int = 4;
    log "Creating tasks";

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::spawn_joinable(bind test06_start(i))];
    }

    for t in tasks { task::join(t); }
}

<|endoftext|>


<commit_before>use crate::{
    models::VersionDownload,
    schema::{crates, metadata, version_downloads, versions},
};

use diesel::prelude::*;
use swirl::PerformError;

#[swirl::background_job]
pub fn update_downloads(conn: &PgConnection) -> Result<(), PerformError> {
    update(conn)?;
    Ok(())
}

fn update(conn: &PgConnection) -> QueryResult<()> {
    use self::version_downloads::dsl::*;
    use diesel::dsl::now;
    use diesel::select;

    let rows = version_downloads
        .filter(processed.eq(false))
        .filter(downloads.ne(counted))
        .load(conn)?;

    println!("Updating {} versions", rows.len());
    collect(conn, &rows)?;
    println!("Finished updating versions");

    // Anything older than 24 hours ago will be frozen and will not be queried
    // against again.
    diesel::update(version_downloads)
        .set(processed.eq(true))
        .filter(date.lt(diesel::dsl::date(now)))
        .filter(downloads.eq(counted))
        .filter(processed.eq(false))
        .execute(conn)?;
    println!("Finished freezing old version_downloads");

    no_arg_sql_function!(refresh_recent_crate_downloads, ());
    select(refresh_recent_crate_downloads).execute(conn)?;
    println!("Finished running refresh_recent_crate_downloads");

    Ok(())
}

fn collect(conn: &PgConnection, rows: &[VersionDownload]) -> QueryResult<()> {
    use diesel::update;

    for download in rows {
        let amt = download.downloads - download.counted;

        conn.transaction::<_, diesel::result::Error, _>(|| {
            // Update the total number of version downloads
            let crate_id: i32 = update(versions::table.find(download.version_id))
                .set(versions::downloads.eq(versions::downloads + amt))
                .returning(versions::crate_id)
                .get_result(conn)?;

            // Update the total number of crate downloads
            update(crates::table.find(crate_id))
                .set(crates::downloads.eq(crates::downloads + amt))
                .execute(conn)?;

            // Update the global counter of total downloads
            update(metadata::table)
                .set(metadata::total_downloads.eq(metadata::total_downloads + i64::from(amt)))
                .execute(conn)?;

            // Record that these downloads have been propagated to the other tables.  This is done
            // last, immediately before the transaction is committed, to minimize lock contention
            // with counting new downloads.
            update(version_downloads::table.find(download.id()))
                .set(version_downloads::counted.eq(version_downloads::counted + amt))
                .execute(conn)?;

            Ok(())
        })?;
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::email::Emails;
    use crate::models::{Crate, NewCrate, NewUser, NewVersion, User, Version};
    use std::collections::BTreeMap;

    fn user(conn: &PgConnection) -> User {
        NewUser::new(2, "login", None, None, "access_token")
            .create_or_update(None, &Emails::new_in_memory(), conn)
            .unwrap()
    }

    fn crate_and_version(conn: &PgConnection, user_id: i32) -> (Crate, Version) {
        let krate = NewCrate {
            name: "foo",
            ..Default::default()
        }
        .create_or_update(conn, user_id, None)
        .unwrap();
        let version = NewVersion::new(
            krate.id,
            &semver::Version::parse("1.0.0").unwrap(),
            &BTreeMap::new(),
            None,
            None,
            0,
            user_id,
            "0000000000000000000000000000000000000000000000000000000000000000".to_string(),
            None,
        )
        .unwrap();
        let version = version.save(conn, "someone@example.com").unwrap();
        (krate, version)
    }

    #[test]
    fn increment() {
        use diesel::dsl::*;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (krate, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values(version_downloads::version_id.eq(version.id))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::date.eq(date(now - 1.day())),
                version_downloads::processed.eq(true),
            ))
            .execute(&conn)
            .unwrap();

        super::update(&conn).unwrap();
        let version_downloads = versions::table
            .find(version.id)
            .select(versions::downloads)
            .first(&conn);
        assert_eq!(Ok(1), version_downloads);
        let crate_downloads = crates::table
            .find(krate.id)
            .select(crates::downloads)
            .first(&conn);
        assert_eq!(Ok(1), crate_downloads);
        super::update(&conn).unwrap();
        let version_downloads = versions::table
            .find(version.id)
            .select(versions::downloads)
            .first(&conn);
        assert_eq!(Ok(1), version_downloads);
    }

    #[test]
    fn set_processed_true() {
        use diesel::dsl::*;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now - 2.days())),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let processed = version_downloads::table
            .filter(version_downloads::version_id.eq(version.id))
            .select(version_downloads::processed)
            .first(&conn);
        assert_eq!(Ok(true), processed);
    }

    #[test]
    fn dont_process_recent_row() {
        use diesel::dsl::*;
        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now)),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let processed = version_downloads::table
            .filter(version_downloads::version_id.eq(version.id))
            .select(version_downloads::processed)
            .first(&conn);
        assert_eq!(Ok(false), processed);
    }

    #[test]
    fn increment_a_little() {
        use diesel::dsl::*;
        use diesel::update;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (krate, version) = crate_and_version(&conn, user.id);
        update(versions::table)
            .set(versions::updated_at.eq(now - 2.hours()))
            .execute(&conn)
            .unwrap();
        update(crates::table)
            .set(crates::updated_at.eq(now - 2.hours()))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(1),
                version_downloads::date.eq(date(now)),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::date.eq(date(now - 1.day())),
            ))
            .execute(&conn)
            .unwrap();

        let version_before: Version = versions::table.find(version.id).first(&conn).unwrap();
        let krate_before: Crate = Crate::all()
            .filter(crates::id.eq(krate.id))
            .first(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let version2: Version = versions::table.find(version.id).first(&conn).unwrap();
        assert_eq!(version2.downloads, 2);
        assert_eq!(version2.updated_at, version_before.updated_at);
        let krate2: Crate = Crate::all()
            .filter(crates::id.eq(krate.id))
            .first(&conn)
            .unwrap();
        assert_eq!(krate2.downloads, 2);
        assert_eq!(krate2.updated_at, krate_before.updated_at);
        super::update(&conn).unwrap();
        let version3: Version = versions::table.find(version.id).first(&conn).unwrap();
        assert_eq!(version3.downloads, 2);
    }

    #[test]
    fn set_processed_no_set_updated_at() {
        use diesel::dsl::*;
        use diesel::update;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        update(versions::table)
            .set(versions::updated_at.eq(now - 2.days()))
            .execute(&conn)
            .unwrap();
        update(crates::table)
            .set(crates::updated_at.eq(now - 2.days()))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now - 2.days())),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();

        super::update(&conn).unwrap();
        let versions_changed = versions::table
            .select(versions::updated_at.ne(now - 2.days()))
            .get_result(&conn);
        let crates_changed = crates::table
            .select(crates::updated_at.ne(now - 2.days()))
            .get_result(&conn);
        assert_eq!(Ok(false), versions_changed);
        assert_eq!(Ok(false), crates_changed);
    }
}
<commit_msg>worker::update_downloads: Use `tracing` macros instead of `println!()`<commit_after>use crate::{
    models::VersionDownload,
    schema::{crates, metadata, version_downloads, versions},
};

use diesel::prelude::*;
use swirl::PerformError;

#[swirl::background_job]
pub fn update_downloads(conn: &PgConnection) -> Result<(), PerformError> {
    update(conn)?;
    Ok(())
}

fn update(conn: &PgConnection) -> QueryResult<()> {
    use self::version_downloads::dsl::*;
    use diesel::dsl::now;
    use diesel::select;

    let rows = version_downloads
        .filter(processed.eq(false))
        .filter(downloads.ne(counted))
        .load(conn)?;

    info!(rows = rows.len(), "Updating versions");
    collect(conn, &rows)?;
    info!("Finished updating versions");

    // Anything older than 24 hours ago will be frozen and will not be queried
    // against again.
    diesel::update(version_downloads)
        .set(processed.eq(true))
        .filter(date.lt(diesel::dsl::date(now)))
        .filter(downloads.eq(counted))
        .filter(processed.eq(false))
        .execute(conn)?;
    info!("Finished freezing old version_downloads");

    no_arg_sql_function!(refresh_recent_crate_downloads, ());
    select(refresh_recent_crate_downloads).execute(conn)?;
    info!("Finished running refresh_recent_crate_downloads");

    Ok(())
}

fn collect(conn: &PgConnection, rows: &[VersionDownload]) -> QueryResult<()> {
    use diesel::update;

    for download in rows {
        let amt = download.downloads - download.counted;

        conn.transaction::<_, diesel::result::Error, _>(|| {
            // Update the total number of version downloads
            let crate_id: i32 = update(versions::table.find(download.version_id))
                .set(versions::downloads.eq(versions::downloads + amt))
                .returning(versions::crate_id)
                .get_result(conn)?;

            // Update the total number of crate downloads
            update(crates::table.find(crate_id))
                .set(crates::downloads.eq(crates::downloads + amt))
                .execute(conn)?;

            // Update the global counter of total downloads
            update(metadata::table)
                .set(metadata::total_downloads.eq(metadata::total_downloads + i64::from(amt)))
                .execute(conn)?;

            // Record that these downloads have been propagated to the other tables.  This is done
            // last, immediately before the transaction is committed, to minimize lock contention
            // with counting new downloads.
            update(version_downloads::table.find(download.id()))
                .set(version_downloads::counted.eq(version_downloads::counted + amt))
                .execute(conn)?;

            Ok(())
        })?;
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::email::Emails;
    use crate::models::{Crate, NewCrate, NewUser, NewVersion, User, Version};
    use std::collections::BTreeMap;

    fn user(conn: &PgConnection) -> User {
        NewUser::new(2, "login", None, None, "access_token")
            .create_or_update(None, &Emails::new_in_memory(), conn)
            .unwrap()
    }

    fn crate_and_version(conn: &PgConnection, user_id: i32) -> (Crate, Version) {
        let krate = NewCrate {
            name: "foo",
            ..Default::default()
        }
        .create_or_update(conn, user_id, None)
        .unwrap();
        let version = NewVersion::new(
            krate.id,
            &semver::Version::parse("1.0.0").unwrap(),
            &BTreeMap::new(),
            None,
            None,
            0,
            user_id,
            "0000000000000000000000000000000000000000000000000000000000000000".to_string(),
            None,
        )
        .unwrap();
        let version = version.save(conn, "someone@example.com").unwrap();
        (krate, version)
    }

    #[test]
    fn increment() {
        use diesel::dsl::*;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (krate, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values(version_downloads::version_id.eq(version.id))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::date.eq(date(now - 1.day())),
                version_downloads::processed.eq(true),
            ))
            .execute(&conn)
            .unwrap();

        super::update(&conn).unwrap();
        let version_downloads = versions::table
            .find(version.id)
            .select(versions::downloads)
            .first(&conn);
        assert_eq!(Ok(1), version_downloads);
        let crate_downloads = crates::table
            .find(krate.id)
            .select(crates::downloads)
            .first(&conn);
        assert_eq!(Ok(1), crate_downloads);
        super::update(&conn).unwrap();
        let version_downloads = versions::table
            .find(version.id)
            .select(versions::downloads)
            .first(&conn);
        assert_eq!(Ok(1), version_downloads);
    }

    #[test]
    fn set_processed_true() {
        use diesel::dsl::*;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now - 2.days())),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let processed = version_downloads::table
            .filter(version_downloads::version_id.eq(version.id))
            .select(version_downloads::processed)
            .first(&conn);
        assert_eq!(Ok(true), processed);
    }

    #[test]
    fn dont_process_recent_row() {
        use diesel::dsl::*;
        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now)),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let processed = version_downloads::table
            .filter(version_downloads::version_id.eq(version.id))
            .select(version_downloads::processed)
            .first(&conn);
        assert_eq!(Ok(false), processed);
    }

    #[test]
    fn increment_a_little() {
        use diesel::dsl::*;
        use diesel::update;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (krate, version) = crate_and_version(&conn, user.id);
        update(versions::table)
            .set(versions::updated_at.eq(now - 2.hours()))
            .execute(&conn)
            .unwrap();
        update(crates::table)
            .set(crates::updated_at.eq(now - 2.hours()))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(1),
                version_downloads::date.eq(date(now)),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::date.eq(date(now - 1.day())),
            ))
            .execute(&conn)
            .unwrap();

        let version_before: Version = versions::table.find(version.id).first(&conn).unwrap();
        let krate_before: Crate = Crate::all()
            .filter(crates::id.eq(krate.id))
            .first(&conn)
            .unwrap();
        super::update(&conn).unwrap();
        let version2: Version = versions::table.find(version.id).first(&conn).unwrap();
        assert_eq!(version2.downloads, 2);
        assert_eq!(version2.updated_at, version_before.updated_at);
        let krate2: Crate = Crate::all()
            .filter(crates::id.eq(krate.id))
            .first(&conn)
            .unwrap();
        assert_eq!(krate2.downloads, 2);
        assert_eq!(krate2.updated_at, krate_before.updated_at);
        super::update(&conn).unwrap();
        let version3: Version = versions::table.find(version.id).first(&conn).unwrap();
        assert_eq!(version3.downloads, 2);
    }

    #[test]
    fn set_processed_no_set_updated_at() {
        use diesel::dsl::*;
        use diesel::update;

        let conn = crate::db::test_conn();
        let user = user(&conn);
        let (_, version) = crate_and_version(&conn, user.id);
        update(versions::table)
            .set(versions::updated_at.eq(now - 2.days()))
            .execute(&conn)
            .unwrap();
        update(crates::table)
            .set(crates::updated_at.eq(now - 2.days()))
            .execute(&conn)
            .unwrap();
        insert_into(version_downloads::table)
            .values((
                version_downloads::version_id.eq(version.id),
                version_downloads::downloads.eq(2),
                version_downloads::counted.eq(2),
                version_downloads::date.eq(date(now - 2.days())),
                version_downloads::processed.eq(false),
            ))
            .execute(&conn)
            .unwrap();

        super::update(&conn).unwrap();
        let versions_changed = versions::table
            .select(versions::updated_at.ne(now - 2.days()))
            .get_result(&conn);
        let crates_changed = crates::table
            .select(crates::updated_at.ne(now - 2.days()))
            .get_result(&conn);
        assert_eq!(Ok(false), versions_changed);
        assert_eq!(Ok(false), crates_changed);
    }
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

#![feature(env, path, process, collections)]

extern crate gcc;
extern crate "pkg-config" as pkg_config;

use std::process::Command;
use gcc::Config;
use std::env;
use std::path::PathBuf;

fn main() {
    env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");

    // try to find gtk+-3.0 library
    match pkg_config::find_library("gtk+-3.0") {
        Ok(_) => {},
        Err(e) => panic!("{}", e)
    };

    // call native pkg-config, there is no way to do this with pkg-config for now
    let cmd = Command::new("pkg-config").arg("--cflags").arg("gtk+-3.0")
                .output().unwrap();
    if !cmd.status.success() {
        panic!("{}", String::from_utf8_lossy(&cmd.stderr));
    }

    // make the vector of path to set to gcc::Config
    let output = String::from_utf8(cmd.stdout).unwrap();
    let res: Vec<&str> = output.split(' ').collect();
    let paths: Vec<PathBuf> = res.iter().filter_map(|s| {
        if s.len() > 1 && s.char_at(1) == 'I' { Some(PathBuf::new(&s[2..])) }
        else { None }
    }).collect();

    // build include path
    let mut gcc_conf = Config::new();
    for path in paths {
        gcc_conf.include(&path);
    }
    gcc_conf.file("src/gtk_glue.c");

    // build library
    gcc_conf.compile("librgtk_glue.a");
}
<commit_msg>Handle GTK_* feature flags when building gtk_glue.c<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

#![feature(path, process, collections)]

extern crate gcc;
extern crate "pkg-config" as pkg_config;

use std::process::Command;
use gcc::Config;
use std::env;
use std::path::PathBuf;

fn main() {
    env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");

    // try to find gtk+-3.0 library
    match pkg_config::find_library("gtk+-3.0") {
        Ok(_) => {},
        Err(e) => panic!("{}", e)
    };

    // call native pkg-config, there is no way to do this with pkg-config for now
    let cmd = Command::new("pkg-config").arg("--cflags").arg("gtk+-3.0")
                .output().unwrap();
    if !cmd.status.success() {
        panic!("{}", String::from_utf8_lossy(&cmd.stderr));
    }

    // make the vector of path to set to gcc::Config
    let output = String::from_utf8(cmd.stdout).unwrap();
    let res: Vec<&str> = output.split(' ').collect();
    let paths: Vec<PathBuf> = res.iter().filter_map(|s| {
        if s.len() > 1 && s.char_at(1) == 'I' { Some(PathBuf::new(&s[2..])) }
        else { None }
    }).collect();

    // build include path
    let mut gcc_conf = Config::new();
    for path in paths {
        gcc_conf.include(&path);
    }
    gcc_conf.file("src/gtk_glue.c");

    // pass the GTK feature flags
    for (key, _) in env::vars() {
        if key.starts_with("CARGO_FEATURE_") {
            let feature = key.trim_left_matches("CARGO_FEATURE_");
            if feature.starts_with("GTK_") {
                let mut flag = String::from_str("-D");
                flag.push_str(feature);
                gcc_conf.flag(&flag);
            }
        }
    }

    // build library
    gcc_conf.compile("librgtk_glue.a");
}
<|endoftext|>


<commit_before>use percy_dom::{html, IterableNodes, View, VirtualNode};

use crate::legacy::{console::LegacyDmgMetadata, HasDateCode, LegacyDmgSubmission};

use super::console_submission_list::ConsoleSubmissionList;

pub struct DmgSubmissionList<'a> {
    pub submissions: &'a [LegacyDmgSubmission],
}

impl<'a> DmgSubmissionList<'a> {
    pub fn new(submissions: &'a [LegacyDmgSubmission]) -> Self {
        DmgSubmissionList { submissions }
    }
}

impl<'a> View for DmgSubmissionList<'a> {
    fn render(&self) -> VirtualNode {
        ConsoleSubmissionList {
            submissions: self.submissions,
            board_column_name: "Mainboard",
            extra_columns: &["LCD board", "Power board", "Jack board"],
            extra_cells: vec![
                Box::new(|m: &LegacyDmgMetadata| {
                    m.lcd_board.as_ref().map(|board| {
                        html! {

{&board.kind}

{board.date_code().calendar_short()}

                                { board.lcd_panel.as_ref().and_then(|panel| panel.date_code().calendar_short()).map(|date_code| {
                                    html! {

{format!("LCD panel: {}", date_code)}

                                    }
                                })}

                        }
                    })
                }),
                Box::new(|m: &LegacyDmgMetadata| {
                    m.power_board.as_ref().map(|board| {
                        html! {

{format!("Type {}", board.kind)}

{board.date_code().calendar_short()}

                        }
                    })
                }),
                Box::new(|m: &LegacyDmgMetadata| {
                    m.jack_board.as_ref().map(|board| {
                        board.kind.as_str().into()
                    })
                }),
            ],
        }.render()
    }
}
<commit_msg>Remove duplicate LCD info<commit_after>use percy_dom::{html, IterableNodes, View, VirtualNode};

use crate::legacy::{console::LegacyDmgMetadata, HasDateCode, LegacyDmgSubmission};

use super::console_submission_list::ConsoleSubmissionList;

pub struct DmgSubmissionList<'a> {
    pub submissions: &'a [LegacyDmgSubmission],
}

impl<'a> DmgSubmissionList<'a> {
    pub fn new(submissions: &'a [LegacyDmgSubmission]) -> Self {
        DmgSubmissionList { submissions }
    }
}

impl<'a> View for DmgSubmissionList<'a> {
    fn render(&self) -> VirtualNode {
        ConsoleSubmissionList {
            submissions: self.submissions,
            board_column_name: "Mainboard",
            extra_columns: &["LCD board", "Power board", "Jack board"],
            extra_cells: vec![
                Box::new(|m: &LegacyDmgMetadata| {
                    m.lcd_board.as_ref().map(|board| {
                        html! {

{&board.kind}

{board.date_code().calendar_short()}

                        }
                    })
                }),
                Box::new(|m: &LegacyDmgMetadata| {
                    m.power_board.as_ref().map(|board| {
                        html! {

{format!("Type {}", board.kind)}

{board.date_code().calendar_short()}

                        }
                    })
                }),
                Box::new(|m: &LegacyDmgMetadata| {
                    m.jack_board
                        .as_ref()
                        .map(|board| board.kind.as_str().into())
                }),
            ],
        }
        .render()
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::video::{Window, WindowPos, OPENGL};
use sdl2::render::{RenderDriverIndex, ACCELERATED, Renderer};
use sdl2::pixels::Color;
use sdl2::event::poll_event;
use sdl2::event::Event::{Quit, KeyDown};
use sdl2::keycode::KeyCode;

pub fn main() {
    sdl2::init(sdl2::INIT_VIDEO);

    let window = match Window::new("rust-sdl2 demo: Video", WindowPos::PosCentered, WindowPos::PosCentered, 800, 600, OPENGL) {
        Ok(window) => window,
        Err(err) => panic!("failed to create window: {}", err)
    };

    let renderer = match Renderer::from_window(window, RenderDriverIndex::Auto, ACCELERATED) {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    let _ = renderer.set_draw_color(Color::RGB(255, 0, 0));
    let _ = renderer.clear();
    renderer.present();

    loop {
        match poll_event() {
            Quit(_) => break,
            KeyDown(_, _, key, _, _, _) => {
                if key == KeyCode::Escape {
                    break;
                }
            }
            _ => {}
        }
    }

    sdl2::quit();
}

<commit_msg>Replace `let _ =` with `.unwrap()` in demo.<commit_after>extern crate sdl2;

use sdl2::video::{Window, WindowPos, OPENGL};
use sdl2::render::{RenderDriverIndex, ACCELERATED, Renderer};
use sdl2::pixels::Color;
use sdl2::event::poll_event;
use sdl2::event::Event::{Quit, KeyDown};
use sdl2::keycode::KeyCode;

pub fn main() {
    sdl2::init(sdl2::INIT_VIDEO);

    let window = match Window::new("rust-sdl2 demo: Video", WindowPos::PosCentered, WindowPos::PosCentered, 800, 600, OPENGL) {
        Ok(window) => window,
        Err(err) => panic!("failed to create window: {}", err)
    };

    let renderer = match Renderer::from_window(window, RenderDriverIndex::Auto, ACCELERATED) {
        Ok(renderer) => renderer,
        Err(err) => panic!("failed to create renderer: {}", err)
    };

    renderer.set_draw_color(Color::RGB(255, 0, 0)).unwrap();
    renderer.clear().unwrap();
    renderer.present();

    loop {
        match poll_event() {
            Quit(_) => break,
            KeyDown(_, _, key, _, _, _) => {
                if key == KeyCode::Escape {
                    break;
                }
            }
            _ => {}
        }
    }

    sdl2::quit();
}

<|endoftext|>


<commit_before>extern crate chipmunk_sys;

use chipmunk_sys::*;

fn main() { unsafe {
    let gravity = cpv(0.0, -100.0);
    let zero = cpv(0.0, 0.0);

    let space = cpSpaceNew();
    cpSpaceSetGravity(space, gravity);
    let ground = cpSegmentShapeNew((*space).staticBody,
                                   cpv(-20.0, 5.0),
                                   cpv(20.0, -5.0),
                                   0.0);
  cpShapeSetFriction(ground, 1.0);
  cpSpaceAddShape(space, ground);

  let radius = 5.0;
  let mass = 1.0;

  let moment = cpMomentForCircle(mass, 0.0, radius, zero);

  let ballbody = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPosition(ballbody, cpv(0.0, 15.0));

  let ballShape = cpSpaceAddShape(space, cpCircleShapeNew(ballbody, radius, zero));
  cpShapeSetFriction(ballShape, 0.7);

  let timeStep = 1.0 / 60.0;
  for i in 0 .. 60 {
      let time = timeStep * i as f32;
      let pos = cpBodyGetPosition(ballbody);
      let vel = cpBodyGetVelocity(ballbody);
      println!("Time: {:?}, Pos: {:?}, Vel: {:?}", time, pos, vel);
      cpSpaceStep(space, timeStep as f64);
  }

}}
<commit_msg>Fixed variable naming conventions in demo.<commit_after>extern crate chipmunk_sys;

use chipmunk_sys::*;

fn main() { unsafe {
    let gravity = cpv(0.0, -100.0);
    let zero = cpv(0.0, 0.0);

    let space = cpSpaceNew();
    cpSpaceSetGravity(space, gravity);
    let ground = cpSegmentShapeNew((*space).staticBody,
                                   cpv(-20.0, 5.0),
                                   cpv(20.0, -5.0),
                                   0.0);
  cpShapeSetFriction(ground, 1.0);
  cpSpaceAddShape(space, ground);

  let radius = 5.0;
  let mass = 1.0;

  let moment = cpMomentForCircle(mass, 0.0, radius, zero);

  let ball_body = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPosition(ball_body, cpv(0.0, 15.0));

  let ball_shape = cpSpaceAddShape(space, cpCircleShapeNew(ball_body, radius, zero));
  cpShapeSetFriction(ball_shape, 0.7);

  let time_step = 1.0 / 60.0;
  for i in 0 .. 60 {
      let time = time_step * i as f32;
      let pos = cpBodyGetPosition(ball_body);
      let vel = cpBodyGetVelocity(ball_body);
      println!("Time: {:?}, Pos: {:?}, Vel: {:?}", time, pos, vel);
      cpSpaceStep(space, time_step as f64);
  }

}}
<|endoftext|>


<commit_before>use mio::*;
use mio::unix::*;
use mio::util::Slab;
use std::path::PathBuf;
use std::io::{self,Read,Write,ErrorKind};
use std::iter::repeat;
use std::thread;
use std::str::from_utf8;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use log;
use rustc_serialize::json::decode;
use nom::{IResult,HexDisplay};

use yxorp::messages::ConfigMessage;
use yxorp::network::ProxyOrder;
use yxorp::network::buffer::Buffer;

const SERVER: Token = Token(0);

struct CommandClient {
  sock:      UnixStream,
  buf:       Buffer,
  back_buf:  Buffer,
  token:     Option<Token>,
}

impl CommandClient {
  fn new(sock: UnixStream) -> CommandClient {
    CommandClient {
      sock:     sock,
      buf:      Buffer::with_capacity(1024),
      back_buf: Buffer::with_capacity(2048),
      token:    None,
    }
  }

  fn reregister(&self,  event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }

  fn conn_readable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) -> Option<Vec<ConfigMessage>>{
    //debug!("server conn readable; tok={:?}", tok);
    match self.sock.read(self.buf.space()) {
      Ok(0) => {
        self.reregister(event_loop, tok);
        return None;
      },
      Err(e) => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      Ok(r) => {
        self.buf.fill(r);
        debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.as_usize(), r, from_utf8(self.buf.data()));
      },
    };

    let mut res: Option<Vec<ConfigMessage>> = None;
    let mut offset = 0usize;
    match parse(self.buf.data()) {
      IResult::Incomplete(_) => {
        return Some(Vec::new());
      },
      IResult::Error(e)      => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      IResult::Done(i, v)    => {
        offset = self.buf.data().offset(i);
        res = Some(v);
      }
    }
    self.buf.consume(offset);
    return res;
  }

  fn conn_writable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    //debug!("server conn writable; tok={:?}", tok);
    match self.sock.write(self.back_buf.data()) {
      Ok(0) => {},
      Ok(r) => {
        self.back_buf.consume(r);
      },
      Err(e) => log!(log::LogLevel::Error,"UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e),
    }
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }
}

fn parse(input: &[u8]) -> IResult<&[u8], Vec<ConfigMessage>> {
  many0!(input,
    complete!(terminated!(map_res!(map_res!(is_not!("\0"), from_utf8), decode), char!('\0')))
  )
}

struct CommandServer {
  sock:  UnixListener,
  conns: Slab<CommandClient>,
  listeners: HashMap<String, Sender<ProxyOrder>>,
}

impl CommandServer {
  fn accept(&mut self, event_loop: &mut EventLoop<CommandServer>) -> io::Result<()> {
    debug!("server accepting socket");

    let sock = self.sock.accept().unwrap().unwrap();
    let conn = CommandClient::new(sock);
    let tok = self.conns.insert(conn)
      .ok().expect("could not add connection to slab");

    // Register the connection
    self.conns[tok].token = Some(tok);
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.conns[tok].sock, tok, interest, PollOpt::level())
      .ok().expect("could not register socket with event loop");

    let accept_interest = EventSet::readable();
    event_loop.reregister(&self.sock, SERVER, accept_interest, PollOpt::level());
    Ok(())
  }

  fn conn<'a>(&'a mut self, tok: Token) -> &'a mut CommandClient {
    &mut self.conns[tok]
  }

  fn dispatch(&self, v: Vec<ConfigMessage>) {
    for message in &v {
      let command = message.command.clone();
      if let Some(ref listener) = self.listeners.get(&message.listener) {
        listener.send(ProxyOrder::Command(command));
      } else {
        log!(log::LogLevel::Error, "no listener found for tag: {}", message.listener);
      }
    }
  }

  fn new(srv: UnixListener, listeners: HashMap<String, Sender<ProxyOrder>>) -> CommandServer {
    let mut v = Vec::with_capacity(2048);
    v.extend(repeat(0).take(2048));
    CommandServer {
      sock:  srv,
      conns: Slab::new_starting_at(Token(1), 128),
      listeners: listeners,
    }
  }
}

impl Handler for CommandServer {
	type Timeout = usize;
	type Message = ();

	fn ready(&mut self, event_loop: &mut EventLoop<CommandServer>, token: Token, events: EventSet) {
    //trace!("ready: {:?} -> {:?}", token, events);
    if events.is_readable() {
      match token {
        SERVER => self.accept(event_loop).unwrap(),
        _      => {
          if self.conns.contains(token) {
            let opt_v = self.conns[token].conn_readable(event_loop, token);
            if let Some(v) = opt_v {
              self.dispatch(v);
            }
          }
        }
      };
    }

    if events.is_writable() {
      match token {
        SERVER => panic!("received writable for token 0"),
        _      => {
          if self.conns.contains(token) {
            self.conns[token].conn_writable(event_loop, token)
          }
        }
      };
    }

    if events.is_hup() {
      if self.conns.contains(token) {
        event_loop.deregister(&self.conns[token].sock);
        self.conns.remove(token);
        trace!("closed client [{}]", token.as_usize());
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    // TODO: dispatch here to clients the list of messages you want to display
    info!("notify");
  }
}

pub fn start(folder: String, listeners: HashMap<String, Sender<ProxyOrder>>) {
  thread::spawn(move || {
    let mut event_loop = EventLoop::new().unwrap();
    let addr = PathBuf::from(folder).join(&PathBuf::from("./sock"));
    if let Err(e) = fs::remove_file(&addr) {
      match e.kind() {
        ErrorKind::NotFound => {},
        _ => {
          log!(log::LogLevel::Error, "could not delete previous socket at {:?}: {:?}", addr, e);
          return;
        }
      }
    }
    match UnixListener::bind(&addr) {
      Ok(srv) => {
        if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
          log!( log::LogLevel::Error, "could not set the unix socket permissions: {:?}", e);
          fs::remove_file(&addr);
          return;
        }
        info!("listen for connections");
        event_loop.register(&srv, SERVER, EventSet::readable(), PollOpt::level() | PollOpt::oneshot()).unwrap();

        event_loop.run(&mut CommandServer::new(srv, listeners)).unwrap()
      },
      Err(e) => {
        log!(log::LogLevel::Error, "could not create unix socket: {:?}", e);
      }
    }
  });
}
<commit_msg>more logs<commit_after>use mio::*;
use mio::unix::*;
use mio::util::Slab;
use std::path::PathBuf;
use std::io::{self,Read,Write,ErrorKind};
use std::iter::repeat;
use std::thread;
use std::str::from_utf8;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use log;
use rustc_serialize::json::decode;
use nom::{IResult,HexDisplay};

use yxorp::messages::ConfigMessage;
use yxorp::network::ProxyOrder;
use yxorp::network::buffer::Buffer;

const SERVER: Token = Token(0);

struct CommandClient {
  sock:      UnixStream,
  buf:       Buffer,
  back_buf:  Buffer,
  token:     Option<Token>,
}

impl CommandClient {
  fn new(sock: UnixStream) -> CommandClient {
    CommandClient {
      sock:     sock,
      buf:      Buffer::with_capacity(1024),
      back_buf: Buffer::with_capacity(2048),
      token:    None,
    }
  }

  fn reregister(&self,  event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }

  fn conn_readable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) -> Option<Vec<ConfigMessage>>{
    trace!("server conn readable; tok={:?}", tok);
    match self.sock.read(self.buf.space()) {
      Ok(0) => {
        self.reregister(event_loop, tok);
        return None;
      },
      Err(e) => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      Ok(r) => {
        self.buf.fill(r);
        debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.as_usize(), r, from_utf8(self.buf.data()));
      },
    };

    let mut res: Option<Vec<ConfigMessage>> = None;
    let mut offset = 0usize;
    match parse(self.buf.data()) {
      IResult::Incomplete(_) => {
        return Some(Vec::new());
      },
      IResult::Error(e)      => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      IResult::Done(i, v)    => {
        offset = self.buf.data().offset(i);
        res = Some(v);
      }
    }
    debug!("parsed {} bytes, result: {:?}", offset, res);
    self.buf.consume(offset);
    return res;
  }

  fn conn_writable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    trace!("server conn writable; tok={:?}", tok);
    match self.sock.write(self.back_buf.data()) {
      Ok(0) => {},
      Ok(r) => {
        self.back_buf.consume(r);
      },
      Err(e) => log!(log::LogLevel::Error,"UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e),
    }
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }
}

fn parse(input: &[u8]) -> IResult<&[u8], Vec<ConfigMessage>> {
  many0!(input,
    complete!(terminated!(map_res!(map_res!(is_not!("\0"), from_utf8), decode), char!('\0')))
  )
}

struct CommandServer {
  sock:  UnixListener,
  conns: Slab<CommandClient>,
  listeners: HashMap<String, Sender<ProxyOrder>>,
}

impl CommandServer {
  fn accept(&mut self, event_loop: &mut EventLoop<CommandServer>) -> io::Result<()> {
    debug!("server accepting socket");

    let sock = self.sock.accept().unwrap().unwrap();
    let conn = CommandClient::new(sock);
    let tok = self.conns.insert(conn)
      .ok().expect("could not add connection to slab");

    // Register the connection
    self.conns[tok].token = Some(tok);
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.conns[tok].sock, tok, interest, PollOpt::level())
      .ok().expect("could not register socket with event loop");

    let accept_interest = EventSet::readable();
    event_loop.reregister(&self.sock, SERVER, accept_interest, PollOpt::level());
    Ok(())
  }

  fn conn<'a>(&'a mut self, tok: Token) -> &'a mut CommandClient {
    &mut self.conns[tok]
  }

  fn dispatch(&self, v: Vec<ConfigMessage>) {
    for message in &v {
      let command = message.command.clone();
      if let Some(ref listener) = self.listeners.get(&message.listener) {
        listener.send(ProxyOrder::Command(command));
      } else {
        log!(log::LogLevel::Error, "no listener found for tag: {}", message.listener);
      }
    }
  }

  fn new(srv: UnixListener, listeners: HashMap<String, Sender<ProxyOrder>>) -> CommandServer {
    let mut v = Vec::with_capacity(2048);
    v.extend(repeat(0).take(2048));
    CommandServer {
      sock:  srv,
      conns: Slab::new_starting_at(Token(1), 128),
      listeners: listeners,
    }
  }
}

impl Handler for CommandServer {
	type Timeout = usize;
	type Message = ();

	fn ready(&mut self, event_loop: &mut EventLoop<CommandServer>, token: Token, events: EventSet) {
    //trace!("ready: {:?} -> {:?}", token, events);
    if events.is_readable() {
      match token {
        SERVER => self.accept(event_loop).unwrap(),
        _      => {
          if self.conns.contains(token) {
            let opt_v = self.conns[token].conn_readable(event_loop, token);
            if let Some(v) = opt_v {
              self.dispatch(v);
            }
          }
        }
      };
    }

    if events.is_writable() {
      match token {
        SERVER => panic!("received writable for token 0"),
        _      => {
          if self.conns.contains(token) {
            self.conns[token].conn_writable(event_loop, token)
          }
        }
      };
    }

    if events.is_hup() {
      if self.conns.contains(token) {
        event_loop.deregister(&self.conns[token].sock);
        self.conns.remove(token);
        trace!("closed client [{}]", token.as_usize());
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    // TODO: dispatch here to clients the list of messages you want to display
    info!("notify");
  }
}

pub fn start(folder: String, listeners: HashMap<String, Sender<ProxyOrder>>) {
  thread::spawn(move || {
    let mut event_loop = EventLoop::new().unwrap();
    let addr = PathBuf::from(folder).join(&PathBuf::from("./sock"));
    if let Err(e) = fs::remove_file(&addr) {
      match e.kind() {
        ErrorKind::NotFound => {},
        _ => {
          log!(log::LogLevel::Error, "could not delete previous socket at {:?}: {:?}", addr, e);
          return;
        }
      }
    }
    match UnixListener::bind(&addr) {
      Ok(srv) => {
        if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
          log!( log::LogLevel::Error, "could not set the unix socket permissions: {:?}", e);
          fs::remove_file(&addr);
          return;
        }
        info!("listen for connections");
        event_loop.register(&srv, SERVER, EventSet::readable(), PollOpt::level() | PollOpt::oneshot()).unwrap();

        event_loop.run(&mut CommandServer::new(srv, listeners)).unwrap()
      },
      Err(e) => {
        log!(log::LogLevel::Error, "could not create unix socket: {:?}", e);
      }
    }
  });
}
<|endoftext|>


<commit_before>/// The 'Material Design Icons' is the official icon set from Google.
/// The icons are designed under the material design guidelines.
/// Because the official repository is no longer maintained from Google,
/// source code is now maintained and hosted at:
/// https://github.com/material-icons/material-icons-font
/// Package-Info: package.json

// TL;DR
// https://stackoverflow.com/questions/11002820/why-should-we-include-ttf-eot-woff-svg-in-a-font-face
// ... woff2 gets drafted and accepted, which improves the compression
// leading to even smaller files, along with the ability to load a single font
// "in parts" so that a font that supports 20 scripts can be stored as "chunks"
// on disk instead, with browsers automatically able to load the font "in parts"
// as needed, rather than needing to transfer the entire font up front, further
// improving the typesetting experience.
// If you don't want to support IE 8 and lower, and iOS 4 and lower,
// and android 4.3 or earlier, then you can just use WOFF
// (and WOFF2, a more highly compressed WOFF, for the newest browsers that support it.)

// Reference to the material icon fonts.
pub const MATERIAL_ICONS_FONT_TTF: &[u8] = include_bytes!("MaterialIcons.ttf");
// legacy: Google version
pub const MATERIAL_ICONS_REGULAR_FONT_TTF: &[u8] = include_bytes!("MaterialIcons-Regular.ttf");

pub const MATERIAL_ICONS_BASELINE_FONT: &[u8] = include_bytes!("MaterialIcons-Baseline.woff2");
pub const MATERIAL_ICONS_OUTLINED_FONT: &[u8] = include_bytes!("MaterialIcons-Outlined.woff2");
pub const MATERIAL_ICONS_ROUND_FONT: &[u8] = include_bytes!("MaterialIcons-Round.woff2");
pub const MATERIAL_ICONS_SHARP_FONT: &[u8] = include_bytes!("MaterialIcons-Sharp.woff2");
pub const MATERIAL_ICONS_TWOTONE_FONT: &[u8] = include_bytes!("MaterialIcons-TwoTone.woff2");

// Reference to the roboto fonts.
pub const ROBOTO_REGULAR_FONT: &[u8] = include_bytes!("Roboto-Regular.ttf");
pub const ROBOTO_MEDIUM_FONT: &[u8] = include_bytes!("Roboto-Medium.ttf");

// font sizes
pub const FONT_SIZE_12: f64 = 12.0;

// icon sizes
pub const ICON_FONT_SIZE_12: f64 = 12.0;
<commit_msg>theme: fonts: make font name more explicit V2<commit_after>/// The 'Material Design Icons' is the official icon set from Google.
/// The icons are designed under the material design guidelines.
/// Because the official repository is no longer maintained from Google,
/// source code is now maintained and hosted at:
/// https://github.com/material-icons/material-icons-font
/// Package-Info: package.json

// TL;DR
// https://stackoverflow.com/questions/11002820/why-should-we-include-ttf-eot-woff-svg-in-a-font-face
// ... woff2 gets drafted and accepted, which improves the compression
// leading to even smaller files, along with the ability to load a single font
// "in parts" so that a font that supports 20 scripts can be stored as "chunks"
// on disk instead, with browsers automatically able to load the font "in parts"
// as needed, rather than needing to transfer the entire font up front, further
// improving the typesetting experience.
// If you don't want to support IE 8 and lower, and iOS 4 and lower,
// and android 4.3 or earlier, then you can just use WOFF
// (and WOFF2, a more highly compressed WOFF, for the newest browsers that support it.)

// Reference to the material icon fonts.
pub const MATERIAL_ICONS_FONT_TTF: &[u8] = include_bytes!("MaterialIcons.ttf");

pub const MATERIAL_ICONS_BASELINE_FONT: &[u8] = include_bytes!("MaterialIcons-Baseline.woff2");
pub const MATERIAL_ICONS_OUTLINED_FONT: &[u8] = include_bytes!("MaterialIcons-Outlined.woff2");
pub const MATERIAL_ICONS_ROUND_FONT: &[u8] = include_bytes!("MaterialIcons-Round.woff2");
pub const MATERIAL_ICONS_SHARP_FONT: &[u8] = include_bytes!("MaterialIcons-Sharp.woff2");
pub const MATERIAL_ICONS_TWOTONE_FONT: &[u8] = include_bytes!("MaterialIcons-TwoTone.woff2");

// Reference to the roboto fonts.
pub const ROBOTO_REGULAR_FONT: &[u8] = include_bytes!("Roboto-Regular.ttf");
pub const ROBOTO_MEDIUM_FONT: &[u8] = include_bytes!("Roboto-Medium.ttf");

// font sizes
pub const FONT_SIZE_12: f64 = 12.0;

// icon sizes
pub const ICON_FONT_SIZE_12: f64 = 12.0;
<|endoftext|>