<commit_before>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc_plugin;
extern crate docopt;

use std::borrow::Borrow;
use std::collections::HashMap;

use rustc_plugin::Registry;
use syntax::{ast, codemap};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `usize`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacEager::items(SmallVector::many(its))
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Visibility::Public }
                  else { ast::Visibility::Inherited };
        let def = ast::VariantData::Struct(
            self.struct_fields(cx), ast::DUMMY_NODE_ID);

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.extend(self.struct_info.deriving.iter().cloned());
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("usize")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Visibility::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> PResult<'b, Parsed> {
        if self.p.token == token::Eof {
            let err = self.cx.struct_span_err(self.cx.call_site(), "macro expects arguments");
            return Err(err);
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::Comma),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_before_end(
            &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
        ).into_iter()
         .map(|(ident, ty)| {
              let field_name = ident.to_string();
              let key = ArgvMap::struct_field_to_key(&*field_name);
              (Atom::new(&*key), ty)
          })
         .collect::<HashMap<Atom, P<ast::Ty>>>();
        try!(self.p.expect(&token::Eof));

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                let err = self.cx.struct_span_err(self.cx.call_site(),
                                                  &format!("Invalid Docopt usage: {}", err));
                return Err(err);
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> PResult<'b, String> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitKind::Str(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitKind::Str(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr().unwrap());
        let s = match exp.node {
            ast::ExprKind::Lit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                let err = self.cx.struct_span_err(exp.span, &*err);
                return Err(err);
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser<'b>)
                             -> PResult<'b, (ast::Ident, P<ast::Ty>)> {
        let ident = try!(p.parse_ident());
        try!(p.expect(&token::Colon));
        let ty = p.parse_ty().unwrap();
        Ok((ident, ty))
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> PResult<'b, StructInfo> {
        let public = self.p.eat_keyword(token::keywords::Pub);
        let mut info = StructInfo {
            name: try!(self.p.parse_ident()),
            public: public,
            deriving: vec![],
        };
        if self.p.eat(&token::Comma) { return Ok(info); }
        let deriving = try!(self.p.parse_ident());
        if deriving.name.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            let err = self.cx.struct_span_err(self.cx.call_site(), &*err);
            return Err(err);
        }
        while !self.p.eat(&token::Comma) {
            info.deriving.push(
                try!(self.p.parse_ident()).name.to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::with_empty_ctxt(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Borrow<str>, T: Borrow<str> {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.borrow())).collect();
    let mi = cx.meta_list(sp, intern(name.borrow()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: P::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: P::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketed(tystr),
        }]
    })
}
<commit_msg>don't bump past EOF<commit_after>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]

#![feature(plugin_registrar, quote, rustc_private)]

//! This crate defines the `docopt!` macro. It is documented in the
//! documentation of the `docopt` crate.

extern crate syntax;
extern crate rustc_plugin;
extern crate docopt;

use std::borrow::Borrow;
use std::collections::HashMap;

use rustc_plugin::Registry;
use syntax::{ast, codemap};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{Docopt, ArgvMap};
use docopt::parse::{Options, Atom, Positional, Zero, One};

type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_info: StructInfo,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `usize`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_info.name;
        let full_doc = &*self.doc.parser().full_doc;
        its.push(quote_item!(cx,
            impl $struct_name {
                #[allow(dead_code)]
                fn docopt() -> docopt::Docopt {
                    // The unwrap is justified here because this code
                    // gen only happens if the Docopt usage string is valid.
                    docopt::Docopt::new($full_doc).unwrap()
                }
            }
        ).unwrap());
        MacEager::items(SmallVector::many(its))
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let name = self.struct_info.name.clone();
        let vis = if self.struct_info.public { ast::Visibility::Public }
                  else { ast::Visibility::Inherited };
        let def = ast::VariantData::Struct(
            self.struct_fields(cx), ast::DUMMY_NODE_ID);

        let mut traits = vec!["RustcDecodable".to_string()];
        traits.extend(self.struct_info.deriving.iter().cloned());
        let attrs = vec![attribute(cx, "allow", vec!["non_snake_case"]),
                         attribute(cx, "derive", traits)];

        let st = cx.item_struct(codemap::DUMMY_SP, name.clone(), def);
        cx.item(codemap::DUMMY_SP, name, attrs, st.node.clone()).map(|mut it| {
            it.vis = vis;
            it
        })
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ArgvMap::key_to_struct_field(&*atom.to_string());
            let ty = match self.types.get(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(&*name, ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        let sp = codemap::DUMMY_SP;
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => cx.ty_ident(sp, ident("String")),
                    _ => cx.ty_ident(sp, ident("bool")),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => ty_vec_string(cx),
                    _ => cx.ty_ident(sp, ident("usize")),
                }
            }
            (false, &One(_)) => cx.ty_ident(sp, ident("String")),
            (true, &One(_)) => ty_vec_string(cx),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Visibility::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> PResult<'b, Parsed> {
        if self.p.token == token::Eof {
            let err = self.cx.struct_span_err(
                self.cx.call_site(), "macro expects arguments");
            return Err(err);
        }
        let struct_info = try!(self.parse_struct_info());
        let docstr = try!(self.parse_str());

        let mut types = HashMap::new();
        if !self.p.check(&token::Eof) {
            let sep = SeqSep {
                sep: Some(token::Comma),
                trailing_sep_allowed: true,
            };
            types = self.p.parse_seq_to_before_end(
                &token::Eof, sep, |p| MacParser::parse_type_annotation(p)
            ).into_iter()
             .map(|(ident, ty)| {
                  let field_name = ident.to_string();
                  let key = ArgvMap::struct_field_to_key(&*field_name);
                  (Atom::new(&*key), ty)
              })
             .collect::<HashMap<Atom, P<ast::Ty>>>();
            try!(self.p.expect(&token::Eof));
        }

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(docstr) {
            Ok(doc) => doc,
            Err(err) => {
                let err = self.cx.struct_span_err(
                    self.cx.call_site(),
                    &format!("Invalid Docopt usage: {}", err));
                return Err(err);
            }
        };
        Ok(Parsed {
            struct_info: struct_info,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> PResult<'b, String> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitKind::Str(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitKind::Str(ref s, _) => s.to_string(),
                _ => panic!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr().unwrap());
        let s = match exp.node {
            ast::ExprKind::Lit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                let err = self.cx.struct_span_err(exp.span, &*err);
                return Err(err);
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser<'b>)
                             -> PResult<'b, (ast::Ident, P<ast::Ty>)> {
        let ident = try!(p.parse_ident());
        try!(p.expect(&token::Colon));
        let ty = p.parse_ty().unwrap();
        Ok((ident, ty))
    }

    /// Parses struct information, like visibility, name and deriving.
    fn parse_struct_info(&mut self) -> PResult<'b, StructInfo> {
        let public = self.p.eat_keyword(token::keywords::Pub);
        let mut info = StructInfo {
            name: try!(self.p.parse_ident()),
            public: public,
            deriving: vec![],
        };
        if self.p.eat(&token::Comma) { return Ok(info); }
        let deriving = try!(self.p.parse_ident());
        if deriving.name.as_str() != "derive" {
            let err = format!("Expected 'derive' keyword but got '{}'",
                              deriving);
            let err = self.cx.struct_span_err(self.cx.call_site(), &*err);
            return Err(err);
        }
        while !self.p.eat(&token::Comma) {
            info.deriving.push(
                try!(self.p.parse_ident()).name.to_string());
        }
        Ok(info)
    }
}

struct StructInfo {
    name: ast::Ident,
    public: bool,
    deriving: Vec<String>,
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::with_empty_ctxt(token::intern(s))
}

fn attribute<S, T>(cx: &ExtCtxt, name: S, items: Vec<T>) -> ast::Attribute
            where S: Borrow<str>, T: Borrow<str> {
    let sp = codemap::DUMMY_SP;
    let its = items.into_iter().map(|s| meta_item(cx, s.borrow())).collect();
    let mi = cx.meta_list(sp, intern(name.borrow()), its);
    cx.attribute(sp, mi)
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}

fn ty_vec_string(cx: &ExtCtxt) -> P<ast::Ty> {
    let sp = codemap::DUMMY_SP;
    let tystr = ast::AngleBracketedParameterData {
        lifetimes: vec![],
        types: P::from_vec(vec![cx.ty_ident(sp, ident("String"))]),
        bindings: P::empty(),
    };
    cx.ty_path(ast::Path {
        span: sp,
        global: false,
        segments: vec![ast::PathSegment {
            identifier: ident("Vec"),
            parameters: ast::PathParameters::AngleBracketed(tystr),
        }]
    })
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use proc_macro2::{Span, TokenStream};

use shared::{map_type_params, split_for_impl};

use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Generics,
    Ident, Type,
};

use attr::{Container, CrateName};

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(ast) => derive_struct(&container, ast, ident, generics),
        Data::Enum(ast) => derive_enum(&container, ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(
    container: &Container,
    ast: DataStruct,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let (field_idents, field_types) = get_info_from_fields(&ast.fields);
    let field_idents2 = &field_idents;

    // Treat newtype structs as just their inner type
    match ast.fields {
        Fields::Unnamed(_) if field_idents.len() == 1 => {
            let ty = &field_types[0];
            let push_impl = quote! {
                <#ty as _gluon_api::Pushable<'__vm>>::push(self.0, ctx)?;
            };
            return gen_impl(&container, &ident, generics, push_impl);
        }
        _ => (),
    }

    // destructure the struct so the the fields can be accessed by the push implementation
    let destructured = match &ast.fields {
        Fields::Named(_) => quote! { let #ident { #(#field_idents2),* } = self; },
        Fields::Unnamed(_) => quote! { let #ident ( #(#field_idents2),* ) = self; },
        Fields::Unit => quote! {},
    };

    let push_impl = gen_push_impl(None, &field_idents, &field_types);

    gen_impl(
        &container,
        &ident,
        generics,
        quote! { #destructured #push_impl },
    )
}

fn derive_enum(
    container: &Container,
    ast: DataEnum,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    // generate a correct implementation for each variant, destructuring the enum
    // to get access to the values
    let match_arms = ast.variants.iter().enumerate().map(|(tag, variant)| {
        let (field_idents, field_types) = get_info_from_fields(&variant.fields);
        let field_idents2 = &field_idents;
        let variant_ident = &variant.ident;

        let pattern = match &variant.fields {
            Fields::Named(_) => quote! { #ident::#variant_ident{ #(#field_idents2),* } },
            Fields::Unnamed(_) => quote! { #ident::#variant_ident( #(#field_idents2),* ) },
            Fields::Unit => quote! { #ident::#variant_ident },
        };

        match &variant.fields {
            Fields::Named(_) => {
                let push_impl = gen_push_impl(None, &field_idents, &field_types);
                quote! {
                    #pattern => {
                        #push_impl
                        ctx.context().push_new_data(vm, #tag as _gluon_types::VmTag, 1)?;
                    }
                }
            },
            _ => {
                let push_impl = gen_push_impl(Some(tag), &field_idents, &field_types);
                quote! {
                    #pattern => {
                        #push_impl
                    }
                }
            }
        }
    });

    // build the final match from the individual arms
    let push_impl = quote! {
        match self {
            #(#match_arms),*
        };
    };

    gen_impl(container, &ident, generics, push_impl)
}

fn gen_impl(
    container: &Container,
    ident: &Ident,
    generics: Generics,
    push_impl: TokenStream,
) -> TokenStream {
    let pushable_bounds = create_pushable_bounds(&generics);
    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &["'__vm"]);

    let dummy_const = Ident::new(&format!("_IMPL_PUSHABLE_FOR_{}", ident), Span::call_site());

    let gluon = match container.crate_name {
        CrateName::Some(ref ident) => quote! {
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
            use #ident::types as _gluon_types;
            use #ident::Result as _GluonResult;
        },
        CrateName::GluonVm => quote! {
            use crate::api as _gluon_api;
            use crate::thread as _gluon_thread;
            use crate::types as _gluon_types;
            use crate::Result as _GluonResult;
        },
        CrateName::None => quote! {
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
            use gluon::vm::types as _gluon_types;
            use gluon::vm::Result as _GluonResult;
        },
    };
    quote! {
        #[allow(non_upper_case_globals)]
        #[allow(unused_imports)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::Pushable<'__vm> for #ident #ty_generics
            #where_clause #(#pushable_bounds),*
            {
                fn push(self, ctx: &mut _gluon_thread::ActiveThread<'__vm>) -> _GluonResult<()> {
                    #push_impl
                    Ok(())
                }
            }
        };
    }
}

fn gen_push_impl(
    tag: Option<usize>,
    field_idents: &[Cow<Ident>],
    field_types: &[&Type],
) -> TokenStream {
    debug_assert!(field_idents.len() == field_types.len());

    // push each field onto the stack
    let stack_pushes = field_idents.iter().zip(field_types).map(|(ident, ty)| {
        quote! {
            <#ty as _gluon_api::Pushable<'__vm>>::push(#ident, ctx)?;
        }
    });

    let fields_len = field_idents.len();
    let new_data = match tag {
        Some(tag) => quote! {
            ctx.context().push_new_data(#tag as _gluon_types::VmTag, #fields_len)?
        },
        None => {
            let field_ident_strs = field_idents.iter().map(|i| i.to_string());
            quote! { {
                let field_names = [#(vm.global_env().intern(#field_ident_strs)?),*];
                ctx.context().push_new_record(#fields_len, &field_names)?;
            } }
        }
    };

    quote! {
        #(#stack_pushes)*
        let vm = ctx.thread();
        #new_data;
    }
}

fn create_pushable_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_type_params(generics, |ty| {
        quote! {
            #ty: _gluon_api::Pushable<'__vm>
        }
    })
}

fn get_info_from_fields(fields: &Fields) -> (Vec<Cow<Ident>>, Vec<&Type>) {
    // get all the fields if there are any
    let fields = match fields {
        Fields::Named(FieldsNamed { named, .. }) => named,
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed,
        Fields::Unit => return (Vec::new(), Vec::new()),
    };

    fields
        .iter()
        .enumerate()
        .map(|(idx, field)| {
            // if the fields belong to a struct we use the field name,
            // otherwise generate one from the index of the tuple element
            let ident = match &field.ident {
                Some(ident) => Cow::Borrowed(ident),
                None => Cow::Owned(Ident::new(&format!("_{}", idx), Span::call_site())),
            };

            (ident, &field.ty)
        })
        .unzip()
}
<commit_msg>Update push_new_data call<commit_after>use std::borrow::Cow;

use proc_macro2::{Span, TokenStream};

use shared::{map_type_params, split_for_impl};

use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Generics,
    Ident, Type,
};

use attr::{Container, CrateName};

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(ast) => derive_struct(&container, ast, ident, generics),
        Data::Enum(ast) => derive_enum(&container, ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(
    container: &Container,
    ast: DataStruct,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let (field_idents, field_types) = get_info_from_fields(&ast.fields);
    let field_idents2 = &field_idents;

    // Treat newtype structs as just their inner type
    match ast.fields {
        Fields::Unnamed(_) if field_idents.len() == 1 => {
            let ty = &field_types[0];
            let push_impl = quote! {
                <#ty as _gluon_api::Pushable<'__vm>>::push(self.0, ctx)?;
            };
            return gen_impl(&container, &ident, generics, push_impl);
        }
        _ => (),
    }

    // destructure the struct so the the fields can be accessed by the push implementation
    let destructured = match &ast.fields {
        Fields::Named(_) => quote! { let #ident { #(#field_idents2),* } = self; },
        Fields::Unnamed(_) => quote! { let #ident ( #(#field_idents2),* ) = self; },
        Fields::Unit => quote! {},
    };

    let push_impl = gen_push_impl(None, &field_idents, &field_types);

    gen_impl(
        &container,
        &ident,
        generics,
        quote! { #destructured #push_impl },
    )
}

fn derive_enum(
    container: &Container,
    ast: DataEnum,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    // generate a correct implementation for each variant, destructuring the enum
    // to get access to the values
    let match_arms = ast.variants.iter().enumerate().map(|(tag, variant)| {
        let (field_idents, field_types) = get_info_from_fields(&variant.fields);
        let field_idents2 = &field_idents;
        let variant_ident = &variant.ident;

        let pattern = match &variant.fields {
            Fields::Named(_) => quote! { #ident::#variant_ident{ #(#field_idents2),* } },
            Fields::Unnamed(_) => quote! { #ident::#variant_ident( #(#field_idents2),* ) },
            Fields::Unit => quote! { #ident::#variant_ident },
        };

        match &variant.fields {
            Fields::Named(_) => {
                let push_impl = gen_push_impl(None, &field_idents, &field_types);
                quote! {
                    #pattern => {
                        #push_impl
                        ctx.context().push_new_data(#tag as _gluon_types::VmTag, 1)?;
                    }
                }
            }
            _ => {
                let push_impl = gen_push_impl(Some(tag), &field_idents, &field_types);
                quote! {
                    #pattern => {
                        #push_impl
                    }
                }
            }
        }
    });

    // build the final match from the individual arms
    let push_impl = quote! {
        match self {
            #(#match_arms),*
        };
    };

    gen_impl(container, &ident, generics, push_impl)
}

fn gen_impl(
    container: &Container,
    ident: &Ident,
    generics: Generics,
    push_impl: TokenStream,
) -> TokenStream {
    let pushable_bounds = create_pushable_bounds(&generics);
    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &["'__vm"]);

    let dummy_const = Ident::new(&format!("_IMPL_PUSHABLE_FOR_{}", ident), Span::call_site());

    let gluon = match container.crate_name {
        CrateName::Some(ref ident) => quote! {
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
            use #ident::types as _gluon_types;
            use #ident::Result as _GluonResult;
        },
        CrateName::GluonVm => quote! {
            use crate::api as _gluon_api;
            use crate::thread as _gluon_thread;
            use crate::types as _gluon_types;
            use crate::Result as _GluonResult;
        },
        CrateName::None => quote! {
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
            use gluon::vm::types as _gluon_types;
            use gluon::vm::Result as _GluonResult;
        },
    };
    quote! {
        #[allow(non_upper_case_globals)]
        #[allow(unused_imports)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::Pushable<'__vm> for #ident #ty_generics
            #where_clause #(#pushable_bounds),*
            {
                fn push(self, ctx: &mut _gluon_thread::ActiveThread<'__vm>) -> _GluonResult<()> {
                    #push_impl
                    Ok(())
                }
            }
        };
    }
}

fn gen_push_impl(
    tag: Option<usize>,
    field_idents: &[Cow<Ident>],
    field_types: &[&Type],
) -> TokenStream {
    debug_assert!(field_idents.len() == field_types.len());

    // push each field onto the stack
    let stack_pushes = field_idents.iter().zip(field_types).map(|(ident, ty)| {
        quote! {
            <#ty as _gluon_api::Pushable<'__vm>>::push(#ident, ctx)?;
        }
    });

    let fields_len = field_idents.len();
    let new_data = match tag {
        Some(tag) => quote! {
            ctx.context().push_new_data(#tag as _gluon_types::VmTag, #fields_len)?
        },
        None => {
            let field_ident_strs = field_idents.iter().map(|i| i.to_string());
            quote! { {
                let field_names = [#(vm.global_env().intern(#field_ident_strs)?),*];
                ctx.context().push_new_record(#fields_len, &field_names)?;
            } }
        }
    };

    quote! {
        #(#stack_pushes)*
        let vm = ctx.thread();
        #new_data;
    }
}

fn create_pushable_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_type_params(generics, |ty| {
        quote! {
            #ty: _gluon_api::Pushable<'__vm>
        }
    })
}

fn get_info_from_fields(fields: &Fields) -> (Vec<Cow<Ident>>, Vec<&Type>) {
    // get all the fields if there are any
    let fields = match fields {
        Fields::Named(FieldsNamed { named, .. }) => named,
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed,
        Fields::Unit => return (Vec::new(), Vec::new()),
    };

    fields
        .iter()
        .enumerate()
        .map(|(idx, field)| {
            // if the fields belong to a struct we use the field name,
            // otherwise generate one from the index of the tuple element
            let ident = match &field.ident {
                Some(ident) => Cow::Borrowed(ident),
                None => Cow::Owned(Ident::new(&format!("_{}", idx), Span::call_site())),
            };

            (ident, &field.ty)
        })
        .unzip()
}
<|endoftext|>


<commit_before>extern crate three;

use std::env;
use three::Object;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let vertices = triangle.vertices();
                println!("{:?}", vertices);
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }
}
<commit_msg>Checkpoint<commit_after>extern crate three;
extern crate mint;
extern crate froggy;

use std::env;
use three::Geometry;
use mint::Point3;
use froggy::WeakPointer;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());
    let mut vertices = vec!();

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let stl_vertices = triangle.vertices();
                vertices.push(Point3{x: stl_vertices[0].get_x(), y: stl_vertices[0].get_y(),
                    z: stl_vertices[0].get_z()});
                vertices.push(Point3{x: stl_vertices[1].get_x(), y: stl_vertices[1].get_y(),
                    z: stl_vertices[1].get_z()});
                vertices.push(Point3{x: stl_vertices[2].get_x(), y: stl_vertices[2].get_y(),
                    z: stl_vertices[2].get_z()});
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }

    let geometry = Geometry::with_vertices(vertices);

     // Upload the triangle data to the GPU.
    let mut window = three::Window::new("Three-rs obj loading example");
    let upload_geometry = window.factory.upload_geometry(geometry);

     // Create multiple meshes with the same GPU data and material.
     let material = three::material::Basic {
         color: 0xFFFF00,
         map: None,
     };

    window.factory.create_instanced_mesh(&upload_geometry, material.clone());

    let cam = window.factory.perspective_camera(60.0, 1.0 .. 1000.0);
    let mut controls = three::controls::Orbit::builder(&cam)
        .position([0.0, 2.0, -5.0])
        .target([0.0, 0.0, 0.0])
        .build();

    while window.update() && !window.input.hit(three::KEY_ESCAPE) {
        controls.update(&window.input);
        window.render(&cam);
    }
}
<|endoftext|>


<commit_before>extern crate three;
extern crate mint;
extern crate froggy;

use std::env;
use three::{Geometry, Object};
use mint::Point3;
use froggy::WeakPointer;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());
    let mut vertices = vec!();

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let stl_vertices = triangle.vertices();
                vertices.push(Point3 {
                    x: stl_vertices[0].get_x(),
                    y: stl_vertices[0].get_y(),
                    z: stl_vertices[0].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[1].get_x(),
                    y: stl_vertices[1].get_y(),
                    z: stl_vertices[1].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[2].get_x(),
                    y: stl_vertices[2].get_y(),
                    z: stl_vertices[2].get_z(),
                });
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }

    let geometry = Geometry::with_vertices(vertices);

    // Upload the triangle data to the GPU.
    let mut window = three::Window::new("Loading STL...");

    // Create multiple meshes with the same GPU data and material.
    let material = three::material::Basic {
        color: 0xFFFF00,
        map: None,
    };

    let mesh = window.factory.mesh(geometry, material);
    window.scene.add(&mesh);

    let cam = window.factory.perspective_camera(60.0, 1.0 .. 1000.0);
    let mut controls = three::controls::Orbit::builder(&cam)
        .position([0.0, 2.0, -5.0])
        .target([0.0, 0.0, 0.0])
        .build();

    let dir_light = window.factory.directional_light(0xffffff, 0.9);
    dir_light.look_at([15.0, 35.0, 35.0], [0.0, 0.0, 2.0], None);
    window.scene.add(&dir_light);

    while window.update() && !window.input.hit(three::KEY_ESCAPE) {
        controls.update(&window.input);
        window.render(&cam);
    }
}
<commit_msg>Changed the material to wireframe<commit_after>extern crate three;
extern crate mint;
extern crate froggy;

use std::env;
use three::{Geometry, Object};
use mint::Point3;
use froggy::WeakPointer;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());
    let mut vertices = vec!();

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let stl_vertices = triangle.vertices();
                vertices.push(Point3 {
                    x: stl_vertices[0].get_x(),
                    y: stl_vertices[0].get_y(),
                    z: stl_vertices[0].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[1].get_x(),
                    y: stl_vertices[1].get_y(),
                    z: stl_vertices[1].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[2].get_x(),
                    y: stl_vertices[2].get_y(),
                    z: stl_vertices[2].get_z(),
                });
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }

    let geometry = Geometry::with_vertices(vertices);

    // Upload the triangle data to the GPU.
    let mut window = three::Window::new("Loading STL...");

    // Create multiple meshes with the same GPU data and material.
    let material = three::material::Wireframe{color: 0xff0000};

    let mesh = window.factory.mesh(geometry, material);
    window.scene.add(&mesh);

    let cam = window.factory.perspective_camera(60.0, 1.0 .. 1000.0);
    let mut controls = three::controls::Orbit::builder(&cam)
        .position([0.0, 2.0, -5.0])
        .target([0.0, 0.0, 0.0])
        .build();

    let dir_light = window.factory.directional_light(0xffffff, 0.9);
    dir_light.look_at([15.0, 35.0, 35.0], [0.0, 0.0, 2.0], None);
    window.scene.add(&dir_light);

    while window.update() && !window.input.hit(three::KEY_ESCAPE) {
        controls.update(&window.input);
        window.render(&cam);
    }
}
<|endoftext|>


<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/. */

//! Specified color values.

use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError, BasicParseErrorKind};
#[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor;
use itoa;
use parser::{ParserContext, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::system_colors::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseErrorKind, ValueParseErrorKind};
use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue};

/// Specified color value
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub enum Color {
    /// The 'currentColor' keyword
    CurrentColor,
    /// A specific RGBA color
    Numeric {
        /// Parsed RGBA color
        parsed: RGBA,
        /// Authored representation
        authored: Option<Box<str>>,
    },
    /// A complex color value from computed value
    Complex(ComputedColor),

    /// A system color
    #[cfg(feature = "gecko")]
    System(SystemColor),
    /// A special color keyword value used in Gecko
    #[cfg(feature = "gecko")]
    Special(gecko::SpecialColorKeyword),
    /// Quirksmode-only rule for inheriting color from the body
    #[cfg(feature = "gecko")]
    InheritFromBodyQuirk,
}

#[cfg(feature = "gecko")]
mod gecko {
    define_css_keyword_enum! { SpecialColorKeyword:
        "-moz-default-color" => MozDefaultColor,
        "-moz-default-background-color" => MozDefaultBackgroundColor,
        "-moz-hyperlinktext" => MozHyperlinktext,
        "-moz-activehyperlinktext" => MozActiveHyperlinktext,
        "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
    }
}

impl From<RGBA> for Color {
    fn from(value: RGBA) -> Self {
        Color::rgba(value)
    }
}

impl Parse for Color {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse_color(input)
    }
}

impl ToCss for Color {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
            Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
            Color::Complex(_) => Ok(()),
            #[cfg(feature = "gecko")]
            Color::System(system) => system.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::Special(special) => special.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => Ok(()),
        }
    }
}

/// A wrapper of cssparser::Color::parse_hash.
///
/// That function should never return CurrentColor, so it makes no sense
/// to handle a cssparser::Color here. This should really be done in
/// cssparser directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
    CSSParserColor::parse_hash(value).map(|color| {
        match color {
            CSSParserColor::RGBA(rgba) => rgba,
            CSSParserColor::CurrentColor =>
                unreachable!("parse_hash should never return currentcolor"),
        }
    })
}

impl Color {
    /// Returns currentcolor value.
    #[inline]
    pub fn currentcolor() -> Color {
        Color::CurrentColor
    }

    /// Returns transparent value.
    #[inline]
    pub fn transparent() -> Color {
        // We should probably set authored to "transparent", but maybe it doesn't matter.
        Color::rgba(RGBA::transparent())
    }

    /// Returns a numeric RGBA color value.
    #[inline]
    pub fn rgba(rgba: RGBA) -> Self {
        Color::Numeric {
            parsed: rgba,
            authored: None,
        }
    }

    /// Parse a color, with quirks.
    ///
    /// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
    pub fn parse_quirky<'i, 't>(context: &ParserContext,
                                input: &mut Parser<'i, 't>,
                                allow_quirks: AllowQuirks)
                                -> Result<Self, ParseError<'i>> {
        input.try(|i| Self::parse(context, i)).or_else(|e| {
            if !allow_quirks.allowed(context.quirks_mode) {
                return Err(e);
            }
            Color::parse_quirky_color(input)
                .map(|rgba| Color::rgba(rgba))
                .map_err(|_| e)
        })
    }

    /// Parse a <quirky-color> value.
    ///
    /// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
    fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
        let location = input.current_source_location();
        let (value, unit) = match *input.next()? {
            Token::Number { int_value: Some(integer), .. } => {
                (integer, None)
            },
            Token::Dimension { int_value: Some(integer), ref unit, .. } => {
                (integer, Some(unit))
            },
            Token::Ident(ref ident) => {
                if ident.len() != 3 && ident.len() != 6 {
                    return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
                }
                return parse_hash_color(ident.as_bytes())
                    .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
            }
            ref t => {
                return Err(location.new_unexpected_token_error(t.clone()));
            },
        };
        if value < 0 {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
        }
        let length = if value <= 9 {
            1
        } else if value <= 99 {
            2
        } else if value <= 999 {
            3
        } else if value <= 9999 {
            4
        } else if value <= 99999 {
            5
        } else if value <= 999999 {
            6
        } else {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
        };
        let total = length + unit.as_ref().map_or(0, |d| d.len());
        if total > 6 {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
        }
        let mut serialization = [b'0'; 6];
        let space_padding = 6 - total;
        let mut written = space_padding;
        written += itoa::write(&mut serialization[written..], value).unwrap();
        if let Some(unit) = unit {
            written += (&mut serialization[written..]).write(unit.as_bytes()).unwrap();
        }
        debug_assert!(written == 6);
        parse_hash_color(&serialization).map_err(|()| {
            location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
        })
    }

    /// Returns false if the color is completely transparent, and
    /// true otherwise.
    pub fn is_non_transparent(&self) -> bool {
        match *self {
            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
            _ => true,
        }
    }

    /// Parse a <color> value.
    pub fn parse_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Currently we only store authored value for color keywords,
        // because all browsers serialize those values as keywords for
        // specified value.
        let start = input.state();
        let authored = match input.next() {
            Ok(&Token::Ident(ref s)) => Some(s.clone()),
            _ => None,
        };
        input.reset(&start);
        match input.try(CSSParserColor::parse) {
            Ok(value) =>
                Ok(match value {
                    CSSParserColor::CurrentColor => Color::CurrentColor,
                    CSSParserColor::RGBA(rgba) => {
                        Color::Numeric {
                            parsed: rgba,
                            authored: authored.map(|s| s.to_lowercase().into_boxed_str()),
                        }
                    }
                }),
            Err(e) => {
                #[cfg(feature = "gecko")]
                {
                    if let Ok(system) = input.try(SystemColor::parse) {
                        return Ok(Color::System(system));
                    }

                    if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
                        return Ok(Color::Special(c));
                    }
                }

                match e {
                    BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location } => {
                        Err(location.new_custom_error(
                            StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
                        ))
                    }
                    e => Err(e.into())
                }
            }
        }
    }
}

#[cfg(feature = "gecko")]
fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
    use gecko::values::convert_nscolor_to_rgba;
    ComputedColor::rgba(convert_nscolor_to_rgba(color))
}

impl Color {
    /// Converts this Color into a ComputedColor.
    ///
    /// If `context` is `None`, and the specified color requires data from
    /// the context to resolve, then `None` is returned.
    pub fn to_computed_color(
        &self,
        _context: Option<&Context>,
    ) -> Option<ComputedColor> {
        match *self {
            Color::CurrentColor => {
                Some(ComputedColor::currentcolor())
            }
            Color::Numeric { ref parsed, .. } => {
                Some(ComputedColor::rgba(*parsed))
            }
            Color::Complex(ref complex) => {
                Some(*complex)
            }
            #[cfg(feature = "gecko")]
            Color::System(system) => {
                _context.map(|context| {
                    convert_nscolor_to_computedcolor(
                        system.to_computed_value(context)
                    )
                })
            }
            #[cfg(feature = "gecko")]
            Color::Special(special) => {
                use self::gecko::SpecialColorKeyword as Keyword;
                _context.map(|context| {
                    let pres_context = context.device().pres_context();
                    convert_nscolor_to_computedcolor(match special {
                        Keyword::MozDefaultColor => pres_context.mDefaultColor,
                        Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
                        Keyword::MozHyperlinktext => pres_context.mLinkColor,
                        Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
                        Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
                    })
                })
            }
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => {
                _context.map(|context| {
                    ComputedColor::rgba(context.device().body_text_color())
                })
            },
        }
    }
}

impl ToComputedValue for Color {
    type ComputedValue = ComputedColor;

    fn to_computed_value(&self, context: &Context) -> ComputedColor {
        let result = self.to_computed_color(Some(context)).unwrap();
        if result.foreground_ratio != 0 {
            if let Some(longhand) = context.for_non_inherited_property {
                if longhand.stores_complex_colors_lossily() {
                    context.rule_cache_conditions.borrow_mut().set_uncacheable();
                }
            }
        }
        result
    }

    fn from_computed_value(computed: &ComputedColor) -> Self {
        if computed.is_numeric() {
            Color::rgba(computed.color)
        } else if computed.is_currentcolor() {
            Color::currentcolor()
        } else {
            Color::Complex(*computed)
        }
    }
}

/// Specified color value, but resolved to just RGBA for computed value
/// with value from color property at the same context.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub struct RGBAColor(pub Color);

impl Parse for RGBAColor {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse(context, input).map(RGBAColor)
    }
}

impl ToComputedValue for RGBAColor {
    type ComputedValue = RGBA;

    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.style().get_color().clone_color())
    }

    fn from_computed_value(computed: &RGBA) -> Self {
        RGBAColor(Color::rgba(*computed))
    }
}

impl From<Color> for RGBAColor {
    fn from(color: Color) -> RGBAColor {
        RGBAColor(color)
    }
}

/// Specified value for the "color" property, which resolves the `currentcolor`
/// keyword to the parent color instead of self's color.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)]
pub struct ColorPropertyValue(pub Color);

impl ToComputedValue for ColorPropertyValue {
    type ComputedValue = RGBA;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.builder.get_parent_color().clone_color())
    }

    #[inline]
    fn from_computed_value(computed: &RGBA) -> Self {
        ColorPropertyValue(Color::rgba(*computed).into())
    }
}

impl Parse for ColorPropertyValue {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Color::parse_quirky(context, input, AllowQuirks::Yes).map(ColorPropertyValue)
    }
}
<commit_msg>style: Formatting nits in color parsing.<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/. */

//! Specified color values.

use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError, BasicParseErrorKind};
#[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor;
use itoa;
use parser::{ParserContext, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::system_colors::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseErrorKind, ValueParseErrorKind};
use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue};

/// Specified color value
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub enum Color {
    /// The 'currentColor' keyword
    CurrentColor,
    /// A specific RGBA color
    Numeric {
        /// Parsed RGBA color
        parsed: RGBA,
        /// Authored representation
        authored: Option<Box<str>>,
    },
    /// A complex color value from computed value
    Complex(ComputedColor),

    /// A system color
    #[cfg(feature = "gecko")]
    System(SystemColor),
    /// A special color keyword value used in Gecko
    #[cfg(feature = "gecko")]
    Special(gecko::SpecialColorKeyword),
    /// Quirksmode-only rule for inheriting color from the body
    #[cfg(feature = "gecko")]
    InheritFromBodyQuirk,
}

#[cfg(feature = "gecko")]
mod gecko {
    define_css_keyword_enum! { SpecialColorKeyword:
        "-moz-default-color" => MozDefaultColor,
        "-moz-default-background-color" => MozDefaultBackgroundColor,
        "-moz-hyperlinktext" => MozHyperlinktext,
        "-moz-activehyperlinktext" => MozActiveHyperlinktext,
        "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
    }
}

impl From<RGBA> for Color {
    fn from(value: RGBA) -> Self {
        Color::rgba(value)
    }
}

impl Parse for Color {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse_color(input)
    }
}

impl ToCss for Color {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
            Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
            Color::Complex(_) => Ok(()),
            #[cfg(feature = "gecko")]
            Color::System(system) => system.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::Special(special) => special.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => Ok(()),
        }
    }
}

/// A wrapper of cssparser::Color::parse_hash.
///
/// That function should never return CurrentColor, so it makes no sense
/// to handle a cssparser::Color here. This should really be done in
/// cssparser directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
    CSSParserColor::parse_hash(value).map(|color| {
        match color {
            CSSParserColor::RGBA(rgba) => rgba,
            CSSParserColor::CurrentColor =>
                unreachable!("parse_hash should never return currentcolor"),
        }
    })
}

impl Color {
    /// Returns currentcolor value.
    #[inline]
    pub fn currentcolor() -> Color {
        Color::CurrentColor
    }

    /// Returns transparent value.
    #[inline]
    pub fn transparent() -> Color {
        // We should probably set authored to "transparent", but maybe it doesn't matter.
        Color::rgba(RGBA::transparent())
    }

    /// Returns a numeric RGBA color value.
    #[inline]
    pub fn rgba(rgba: RGBA) -> Self {
        Color::Numeric {
            parsed: rgba,
            authored: None,
        }
    }

    /// Parse a color, with quirks.
    ///
    /// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
    pub fn parse_quirky<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
        allow_quirks: AllowQuirks,
    ) -> Result<Self, ParseError<'i>> {
        input.try(|i| Self::parse(context, i)).or_else(|e| {
            if !allow_quirks.allowed(context.quirks_mode) {
                return Err(e);
            }
            Color::parse_quirky_color(input)
                .map(Color::rgba)
                .map_err(|_| e)
        })
    }

    /// Parse a <quirky-color> value.
    ///
    /// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
    fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
        let location = input.current_source_location();
        let (value, unit) = match *input.next()? {
            Token::Number { int_value: Some(integer), .. } => {
                (integer, None)
            },
            Token::Dimension { int_value: Some(integer), ref unit, .. } => {
                (integer, Some(unit))
            },
            Token::Ident(ref ident) => {
                if ident.len() != 3 && ident.len() != 6 {
                    return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
                }
                return parse_hash_color(ident.as_bytes())
                    .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
            }
            ref t => {
                return Err(location.new_unexpected_token_error(t.clone()));
            },
        };
        if value < 0 {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
        }
        let length = if value <= 9 {
            1
        } else if value <= 99 {
            2
        } else if value <= 999 {
            3
        } else if value <= 9999 {
            4
        } else if value <= 99999 {
            5
        } else if value <= 999999 {
            6
        } else {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
        };
        let total = length + unit.as_ref().map_or(0, |d| d.len());
        if total > 6 {
            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
        }
        let mut serialization = [b'0'; 6];
        let space_padding = 6 - total;
        let mut written = space_padding;
        written += itoa::write(&mut serialization[written..], value).unwrap();
        if let Some(unit) = unit {
            written += (&mut serialization[written..]).write(unit.as_bytes()).unwrap();
        }
        debug_assert!(written == 6);
        parse_hash_color(&serialization).map_err(|()| {
            location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
        })
    }

    /// Returns false if the color is completely transparent, and
    /// true otherwise.
    pub fn is_non_transparent(&self) -> bool {
        match *self {
            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
            _ => true,
        }
    }

    /// Parse a <color> value.
    pub fn parse_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Currently we only store authored value for color keywords,
        // because all browsers serialize those values as keywords for
        // specified value.
        let start = input.state();
        let authored = match input.next() {
            Ok(&Token::Ident(ref s)) => Some(s.clone()),
            _ => None,
        };
        input.reset(&start);
        match input.try(CSSParserColor::parse) {
            Ok(value) =>
                Ok(match value {
                    CSSParserColor::CurrentColor => Color::CurrentColor,
                    CSSParserColor::RGBA(rgba) => {
                        Color::Numeric {
                            parsed: rgba,
                            authored: authored.map(|s| s.to_lowercase().into_boxed_str()),
                        }
                    }
                }),
            Err(e) => {
                #[cfg(feature = "gecko")]
                {
                    if let Ok(system) = input.try(SystemColor::parse) {
                        return Ok(Color::System(system));
                    }

                    if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
                        return Ok(Color::Special(c));
                    }
                }

                match e {
                    BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location } => {
                        Err(location.new_custom_error(
                            StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
                        ))
                    }
                    e => Err(e.into())
                }
            }
        }
    }
}

#[cfg(feature = "gecko")]
fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
    use gecko::values::convert_nscolor_to_rgba;
    ComputedColor::rgba(convert_nscolor_to_rgba(color))
}

impl Color {
    /// Converts this Color into a ComputedColor.
    ///
    /// If `context` is `None`, and the specified color requires data from
    /// the context to resolve, then `None` is returned.
    pub fn to_computed_color(
        &self,
        _context: Option<&Context>,
    ) -> Option<ComputedColor> {
        match *self {
            Color::CurrentColor => {
                Some(ComputedColor::currentcolor())
            }
            Color::Numeric { ref parsed, .. } => {
                Some(ComputedColor::rgba(*parsed))
            }
            Color::Complex(ref complex) => {
                Some(*complex)
            }
            #[cfg(feature = "gecko")]
            Color::System(system) => {
                _context.map(|context| {
                    convert_nscolor_to_computedcolor(
                        system.to_computed_value(context)
                    )
                })
            }
            #[cfg(feature = "gecko")]
            Color::Special(special) => {
                use self::gecko::SpecialColorKeyword as Keyword;
                _context.map(|context| {
                    let pres_context = context.device().pres_context();
                    convert_nscolor_to_computedcolor(match special {
                        Keyword::MozDefaultColor => pres_context.mDefaultColor,
                        Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
                        Keyword::MozHyperlinktext => pres_context.mLinkColor,
                        Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
                        Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
                    })
                })
            }
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => {
                _context.map(|context| {
                    ComputedColor::rgba(context.device().body_text_color())
                })
            },
        }
    }
}

impl ToComputedValue for Color {
    type ComputedValue = ComputedColor;

    fn to_computed_value(&self, context: &Context) -> ComputedColor {
        let result = self.to_computed_color(Some(context)).unwrap();
        if result.foreground_ratio != 0 {
            if let Some(longhand) = context.for_non_inherited_property {
                if longhand.stores_complex_colors_lossily() {
                    context.rule_cache_conditions.borrow_mut().set_uncacheable();
                }
            }
        }
        result
    }

    fn from_computed_value(computed: &ComputedColor) -> Self {
        if computed.is_numeric() {
            Color::rgba(computed.color)
        } else if computed.is_currentcolor() {
            Color::currentcolor()
        } else {
            Color::Complex(*computed)
        }
    }
}

/// Specified color value, but resolved to just RGBA for computed value
/// with value from color property at the same context.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub struct RGBAColor(pub Color);

impl Parse for RGBAColor {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse(context, input).map(RGBAColor)
    }
}

impl ToComputedValue for RGBAColor {
    type ComputedValue = RGBA;

    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.style().get_color().clone_color())
    }

    fn from_computed_value(computed: &RGBA) -> Self {
        RGBAColor(Color::rgba(*computed))
    }
}

impl From<Color> for RGBAColor {
    fn from(color: Color) -> RGBAColor {
        RGBAColor(color)
    }
}

/// Specified value for the "color" property, which resolves the `currentcolor`
/// keyword to the parent color instead of self's color.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)]
pub struct ColorPropertyValue(pub Color);

impl ToComputedValue for ColorPropertyValue {
    type ComputedValue = RGBA;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.builder.get_parent_color().clone_color())
    }

    #[inline]
    fn from_computed_value(computed: &RGBA) -> Self {
        ColorPropertyValue(Color::rgba(*computed).into())
    }
}

impl Parse for ColorPropertyValue {
    fn parse<'i, 't>(
        context: &ParserContext,
        input: &mut Parser<'i, 't>,
    ) -> Result<Self, ParseError<'i>> {
        Color::parse_quirky(context, input, AllowQuirks::Yes).map(ColorPropertyValue)
    }
}
<|endoftext|>


<commit_before>extern crate fxbox_thinkerbell;
extern crate fxbox_taxonomy;
extern crate serde_json;

use fxbox_thinkerbell::ast::*;
use fxbox_thinkerbell::parse::*;
use fxbox_thinkerbell::values::*;
use fxbox_thinkerbell::util::*;

use fxbox_taxonomy::requests::*;

#[test]
fn test_parse_bad_field() {
    let src = "{
      \"requirements\": [],
      \"allocations\": [],
      \"rules\": []
    }".to_owned();

    let result = Parser::parse(src);
    match result {
        Err(serde_json::error::Error::SyntaxError(serde_json::error::ErrorCode::UnknownField(field), _, _)) => {
            assert!(field == "requirements".to_owned() || field == "allocations".to_owned())
        },
        _ => assert!(false)
    };
}

#[test]
fn test_parse_empty() {
    let src = "{ \"rules\": []}".to_owned();
    let script = Parser::parse(src).unwrap();
    assert_eq!(script.rules.len(), 0);
}

#[test]
fn test_parse_simple_rule() {
    let src =
"{
  \"rules\": [
    {
      \"execute\": [],
      \"conditions\": [
      ]
    }
  ]
}".to_owned();
    Parser::parse(src).unwrap();
}

<commit_msg>[fxbox/thinkerbell] Fixed dependency error in a test<commit_after>extern crate fxbox_thinkerbell;
extern crate fxbox_taxonomy;
extern crate serde_json;

use fxbox_thinkerbell::parse::*;

#[test]
fn test_parse_bad_field() {
    let src = "{
      \"requirements\": [],
      \"allocations\": [],
      \"rules\": []
    }".to_owned();

    let result = Parser::parse(src);
    match result {
        Err(serde_json::error::Error::SyntaxError(serde_json::error::ErrorCode::UnknownField(field), _, _)) => {
            assert!(field == "requirements".to_owned() || field == "allocations".to_owned())
        },
        _ => assert!(false)
    };
}

#[test]
fn test_parse_empty() {
    let src = "{ \"rules\": []}".to_owned();
    let script = Parser::parse(src).unwrap();
    assert_eq!(script.rules.len(), 0);
}

#[test]
fn test_parse_simple_rule() {
    let src =
"{
  \"rules\": [
    {
      \"execute\": [],
      \"conditions\": [
      ]
    }
  ]
}".to_owned();
    Parser::parse(src).unwrap();
}

<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

//spell-checker:ignore (args) lsbf msbf

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use uu_base32::base_common::{self, Config};

use uucore::{encoding::Format, InvalidEncodingHandling};

use std::io::{stdin, Read};

static ABOUT: &str = "
 With no FILE, or when FILE is -, read standard input.

 When decoding, the input may contain newlines in addition to the bytes of
 the formal alphabet. Use --ignore-garbage to attempt to recover
 from any other non-alphabet bytes in the encoded stream.
";

static BASE_CMD_PARSE_ERROR: i32 = 1;

const ENCODINGS: &[(&str, Format)] = &[
    ("base64", Format::Base64),
    ("base64url", Format::Base64Url),
    ("base32", Format::Base32),
    ("base32hex", Format::Base32Hex),
    ("base16", Format::Base16),
    ("base2lsbf", Format::Base2Lsbf),
    ("base2msbf", Format::Base2Msbf),
    ("z85", Format::Z85),
    // common abbreviations. TODO: once we have clap 3.0 we can use `AppSettings::InferLongArgs` to get all abbreviations automatically
    ("base2l", Format::Base2Lsbf),
    ("base2m", Format::Base2Msbf),
];

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
}

pub fn uu_app() -> App<'static, 'static> {
    let mut app = base_common::base_app(uucore::util_name(), crate_version!(), ABOUT);
    for encoding in ENCODINGS {
        app = app.arg(Arg::with_name(encoding.0).long(encoding.0));
    }
    app
}

fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(
        args.collect_str(InvalidEncodingHandling::ConvertLossy)
            .accept_any(),
    );
    let format = ENCODINGS
        .iter()
        .find(|encoding| matches.is_present(encoding.0))
        .unwrap_or_else(|| {
            show_usage_error!("missing encoding type");
            std::process::exit(1)
        })
        .1;
    (
        Config::from("basenc", &matches).unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)),
        format,
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let name = uucore::util_name();
    let (config, format) = parse_cmd_args(args);
    // Create a reference to stdin so we can return a locked stdin from
    // parse_base_cmd_args
    let stdin_raw = stdin();
    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw);

    base_common::handle_input(
        &mut input,
        format,
        config.wrap_cols,
        config.ignore_garbage,
        config.decode,
        name,
    );

    0
}
<commit_msg>basenc: use UResult<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

//spell-checker:ignore (args) lsbf msbf

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use uu_base32::base_common::{self, Config, BASE_CMD_PARSE_ERROR};

use uucore::{
    encoding::Format,
    error::{UResult, UUsageError},
    InvalidEncodingHandling,
};

use std::io::{stdin, Read};

static ABOUT: &str = "
 With no FILE, or when FILE is -, read standard input.

 When decoding, the input may contain newlines in addition to the bytes of
 the formal alphabet. Use --ignore-garbage to attempt to recover
 from any other non-alphabet bytes in the encoded stream.
";

const ENCODINGS: &[(&str, Format)] = &[
    ("base64", Format::Base64),
    ("base64url", Format::Base64Url),
    ("base32", Format::Base32),
    ("base32hex", Format::Base32Hex),
    ("base16", Format::Base16),
    ("base2lsbf", Format::Base2Lsbf),
    ("base2msbf", Format::Base2Msbf),
    ("z85", Format::Z85),
    // common abbreviations. TODO: once we have clap 3.0 we can use `AppSettings::InferLongArgs` to get all abbreviations automatically
    ("base2l", Format::Base2Lsbf),
    ("base2m", Format::Base2Msbf),
];

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
}

pub fn uu_app() -> App<'static, 'static> {
    let mut app = base_common::base_app(ABOUT);
    for encoding in ENCODINGS {
        app = app.arg(Arg::with_name(encoding.0).long(encoding.0));
    }
    app
}

fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(
        args.collect_str(InvalidEncodingHandling::ConvertLossy)
            .accept_any(),
    );
    let format = ENCODINGS
        .iter()
        .find(|encoding| matches.is_present(encoding.0))
        .ok_or_else(|| UUsageError::new(BASE_CMD_PARSE_ERROR, "missing encoding type"))?
        .1;
    let config = Config::from(&matches)?;
    Ok((config, format))
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let (config, format) = parse_cmd_args(args)?;
    // Create a reference to stdin so we can return a locked stdin from
    // parse_base_cmd_args
    let stdin_raw = stdin();
    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw)?;

    base_common::handle_input(
        &mut input,
        format,
        config.wrap_cols,
        config.ignore_garbage,
        config.decode,
    )
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  * (c) Jian Zeng <anonymousknight86@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) getloadavg upsecs updays nusers loadavg boottime uphours upmins

use chrono::{Local, TimeZone, Utc};
use clap::{crate_version, Arg, ArgAction, Command};

use uucore::format_usage;
// import crate time from utmpx
pub use uucore::libc;
use uucore::libc::time_t;

use uucore::error::{UResult, USimpleError};

static ABOUT: &str = "Display the current time, the length of time the system has been up,\n\
                      the number of users on the system, and the average number of jobs\n\
                      in the run queue over the last 1, 5 and 15 minutes.";
const USAGE: &str = "{} [OPTION]...";
pub mod options {
    pub static SINCE: &str = "since";
}

#[cfg(unix)]
use uucore::libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> uucore::libc::uint32_t;
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().try_get_matches_from(args)?;

    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        Err(USimpleError::new(1, "could not retrieve system uptime"))
    } else {
        if matches.get_flag(options::SINCE) {
            let initial_date = Local.timestamp(Utc::now().timestamp() - uptime, 0);
            println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
            return Ok(());
        }

        print_time();
        let upsecs = uptime;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        Ok(())
    }
}

pub fn uu_app() -> Command {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::SINCE)
                .short('s')
                .long(options::SINCE)
                .help("system up since")
                .action(ArgAction::SetTrue),
        )
}

#[cfg(unix)]
fn print_loadavg() {
    use uucore::libc::c_double;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let dt = line.login_time();
                if dt.second() > 0 {
                    boot_time = Some(dt.second() as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    match nusers.cmp(&1) {
        std::cmp::Ordering::Equal => print!("1 user,  "),
        std::cmp::Ordering::Greater => print!("{} users,  ", nusers),
        _ => {}
    };
}

fn print_time() {
    let local_time = Local::now().time();

    print!(" {} ", local_time.format("%H:%M:%S"));
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime_s = String::new();

    let proc_uptime = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime_s).ok())
        .and_then(|_| proc_uptime_s.split_whitespace().next())
        .and_then(|s| s.split('.').next().unwrap_or("0").parse().ok());

    proc_uptime.unwrap_or_else(|| match boot_time {
        Some(t) => {
            let now = Local::now().timestamp();
            let boottime = t as i64;
            now - boottime
        }
        None => -1,
    })
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    match updays.cmp(&1) {
        std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins),
        std::cmp::Ordering::Greater => {
            print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins);
        }
        _ => print!("up  {:2}:{:02}, ", uphours, upmins),
    };
}
<commit_msg>deps: fix clippy warning for `chrono` usage<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  * (c) Jian Zeng <anonymousknight86@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) getloadavg upsecs updays nusers loadavg boottime uphours upmins

use chrono::{Local, TimeZone, Utc};
use clap::{crate_version, Arg, ArgAction, Command};

use uucore::format_usage;
// import crate time from utmpx
pub use uucore::libc;
use uucore::libc::time_t;

use uucore::error::{UResult, USimpleError};

static ABOUT: &str = "Display the current time, the length of time the system has been up,\n\
                      the number of users on the system, and the average number of jobs\n\
                      in the run queue over the last 1, 5 and 15 minutes.";
const USAGE: &str = "{} [OPTION]...";
pub mod options {
    pub static SINCE: &str = "since";
}

#[cfg(unix)]
use uucore::libc::getloadavg;

#[cfg(windows)]
extern "C" {
    fn GetTickCount() -> uucore::libc::uint32_t;
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().try_get_matches_from(args)?;

    let (boot_time, user_count) = process_utmpx();
    let uptime = get_uptime(boot_time);
    if uptime < 0 {
        Err(USimpleError::new(1, "could not retrieve system uptime"))
    } else {
        if matches.get_flag(options::SINCE) {
            let initial_date = Local
                .timestamp_opt(Utc::now().timestamp() - uptime, 0)
                .unwrap();
            println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
            return Ok(());
        }

        print_time();
        let upsecs = uptime;
        print_uptime(upsecs);
        print_nusers(user_count);
        print_loadavg();

        Ok(())
    }
}

pub fn uu_app() -> Command {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::SINCE)
                .short('s')
                .long(options::SINCE)
                .help("system up since")
                .action(ArgAction::SetTrue),
        )
}

#[cfg(unix)]
fn print_loadavg() {
    use uucore::libc::c_double;

    let mut avg: [c_double; 3] = [0.0; 3];
    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };

    if loads == -1 {
        println!();
    } else {
        print!("load average: ");
        for n in 0..loads {
            print!(
                "{:.2}{}",
                avg[n as usize],
                if n == loads - 1 { "\n" } else { ", " }
            );
        }
    }
}

#[cfg(windows)]
fn print_loadavg() {
    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
    //      getloadavg()
}

#[cfg(unix)]
fn process_utmpx() -> (Option<time_t>, usize) {
    use uucore::utmpx::*;

    let mut nusers = 0;
    let mut boot_time = None;

    for line in Utmpx::iter_all_records() {
        match line.record_type() {
            USER_PROCESS => nusers += 1,
            BOOT_TIME => {
                let dt = line.login_time();
                if dt.second() > 0 {
                    boot_time = Some(dt.second() as time_t);
                }
            }
            _ => continue,
        }
    }
    (boot_time, nusers)
}

#[cfg(windows)]
fn process_utmpx() -> (Option<time_t>, usize) {
    (None, 0) // TODO: change 0 to number of users
}

fn print_nusers(nusers: usize) {
    match nusers.cmp(&1) {
        std::cmp::Ordering::Equal => print!("1 user,  "),
        std::cmp::Ordering::Greater => print!("{} users,  ", nusers),
        _ => {}
    };
}

fn print_time() {
    let local_time = Local::now().time();

    print!(" {} ", local_time.format("%H:%M:%S"));
}

#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
    use std::fs::File;
    use std::io::Read;

    let mut proc_uptime_s = String::new();

    let proc_uptime = File::open("/proc/uptime")
        .ok()
        .and_then(|mut f| f.read_to_string(&mut proc_uptime_s).ok())
        .and_then(|_| proc_uptime_s.split_whitespace().next())
        .and_then(|s| s.split('.').next().unwrap_or("0").parse().ok());

    proc_uptime.unwrap_or_else(|| match boot_time {
        Some(t) => {
            let now = Local::now().timestamp();
            let boottime = t as i64;
            now - boottime
        }
        None => -1,
    })
}

#[cfg(windows)]
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
    unsafe { GetTickCount() as i64 }
}

fn print_uptime(upsecs: i64) {
    let updays = upsecs / 86400;
    let uphours = (upsecs - (updays * 86400)) / 3600;
    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
    match updays.cmp(&1) {
        std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins),
        std::cmp::Ordering::Greater => {
            print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins);
        }
        _ => print!("up  {:2}:{:02}, ", uphours, upmins),
    };
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;

use common::Solution;
use common::GroupingCount;

#[derive(Copy, Clone, Debug)]
struct Coordinate {
    x: usize,
    y: usize,
}

impl Coordinate {
    pub fn manhattan(&self, other: &Coordinate) -> usize {
        self.x.max(other.x) + self.y.max(other.y)
            - self.x.min(other.x) - self.y.min(other.y)
    }
}

impl From<(usize, usize)> for Coordinate {
    fn from((x, y): (usize, usize)) -> Self {
        Coordinate {
            x,
            y,
        }
    }
}

#[derive(Copy, Clone, Debug)]
enum Claim {
    None,
    Some(usize),
    Multi,
}

#[derive(Default, Debug)]
pub struct Day06 {
    points: Vec<Coordinate>,
    xmax: usize,
    ymax: usize,
}

impl Day06 {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn read_points(&mut self, input: &mut Read) {
        let reader = BufReader::new(input);
        self.points.clear();

        let mut mx = 0;
        let mut my = 0;

        for line in reader.lines() {
            let line = line.unwrap();
            let mut parts = line.split(", ");
            let x = parts.next().unwrap().parse().unwrap();
            let y = parts.next().unwrap().parse().unwrap();
            self.points.push(Coordinate { x, y });
            mx = mx.max(x);
            my = my.max(y);
        }

        self.xmax = mx;
        self.ymax = my;
    }

    fn compute_claim_grid(&self) -> Vec<Vec<Claim>> {
        let mut grid = vec![vec![Claim::None; self.xmax + 1]; self.ymax + 1];

        for coordinate in iproduct!(0..=self.xmax, 0..=self.ymax) {
            let mut cur_dist = usize::max_value();
            let mut cur_best = None;

            let coordinate = Coordinate::from(coordinate);

            for (i, point) in self.points.iter().enumerate() {
                let dist = point.manhattan(&coordinate);
                if dist < cur_dist {
                    cur_dist = dist;
                    cur_best = Some(i);
                } else if dist == cur_dist {
                    cur_best = None;
                }
            }

            grid[coordinate.y][coordinate.x] = match cur_best {
                Some(id) => Claim::Some(id),
                None => Claim::Multi,
            };
        }
        grid
    }

    pub fn part2_with_limit(&mut self, input: &mut Read, limit: usize) -> usize {
        self.read_points(input);

        iproduct!(0..=self.xmax, 0..=self.ymax)
            .map(|x| Coordinate::from(x))
            .map(|x| self.points.iter().map(|y| y.manhattan(&x)).sum::<usize>())
            .filter(|x| x < &limit)
            .count()
    }
}

fn claim_filter(claim: &Claim) -> Option<usize> {
    match claim {
        Claim::Some(id) => Some(*id),
        _ => None,
    }
}

impl Solution for Day06 {
    fn part1(&mut self, input: &mut Read) -> String {
        self.read_points(input);
        let grid = self.compute_claim_grid();
        let mut infinite: HashSet<usize> = HashSet::new();
        infinite.extend(grid[0].iter().filter_map(claim_filter));
        infinite.extend(grid[self.ymax].iter().filter_map(claim_filter));
        for y in 0..=self.ymax {
            infinite.extend([grid[y][0], grid[y][self.xmax]].iter().filter_map(claim_filter));
        }

        let counts = grid.iter().flat_map(|x| x.iter())
            .filter_map(claim_filter)
            .filter(|x| !infinite.contains(x)).grouping_count();

        format!("{}", counts.values().max().unwrap())
    }

    fn part2(&mut self, input: &mut Read) -> String {
        format!("{}", self.part2_with_limit(input, 10_000))
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day06::Day06;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/06.txt");

    #[test]
    fn sample_part1() {
        let mut instance = Day06::new();
        assert_eq!("17", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day06::new();
        assert_eq!(16, instance.part2_with_limit(&mut SAMPLE_INPUT, 32));
    }
}
<commit_msg>Refactor range of coordinates to own function.<commit_after>use std::collections::HashSet;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;

use common::Solution;
use common::GroupingCount;

#[derive(Copy, Clone, Debug)]
struct Coordinate {
    x: usize,
    y: usize,
}

impl Coordinate {
    pub fn manhattan(&self, other: &Coordinate) -> usize {
        self.x.max(other.x) + self.y.max(other.y)
            - self.x.min(other.x) - self.y.min(other.y)
    }
}

impl From<(usize, usize)> for Coordinate {
    fn from((x, y): (usize, usize)) -> Self {
        Coordinate {
            x,
            y,
        }
    }
}

#[derive(Copy, Clone, Debug)]
enum Claim {
    None,
    Some(usize),
    Multi,
}

#[derive(Default, Debug)]
pub struct Day06 {
    points: Vec<Coordinate>,
    xmax: usize,
    ymax: usize,
}

impl Day06 {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn read_points(&mut self, input: &mut Read) {
        let reader = BufReader::new(input);
        self.points.clear();

        let mut mx = 0;
        let mut my = 0;

        for line in reader.lines() {
            let line = line.unwrap();
            let mut parts = line.split(", ");
            let x = parts.next().unwrap().parse().unwrap();
            let y = parts.next().unwrap().parse().unwrap();
            self.points.push(Coordinate { x, y });
            mx = mx.max(x);
            my = my.max(y);
        }

        self.xmax = mx;
        self.ymax = my;
    }

    fn range(&self) -> impl Iterator<Item=Coordinate> {
        iproduct!(0..=self.xmax, 0..=self.ymax)
            .map(|x| Coordinate::from(x))
    }

    fn compute_claim_grid(&self) -> Vec<Vec<Claim>> {
        let mut grid = vec![vec![Claim::None; self.xmax + 1]; self.ymax + 1];

        for coordinate in self.range() {
            let mut cur_dist = usize::max_value();
            let mut cur_best = None;

            for (i, point) in self.points.iter().enumerate() {
                let dist = point.manhattan(&coordinate);
                if dist < cur_dist {
                    cur_dist = dist;
                    cur_best = Some(i);
                } else if dist == cur_dist {
                    cur_best = None;
                }
            }

            grid[coordinate.y][coordinate.x] = match cur_best {
                Some(id) => Claim::Some(id),
                None => Claim::Multi,
            };
        }
        grid
    }

    pub fn part2_with_limit(&mut self, input: &mut Read, limit: usize) -> usize {
        self.read_points(input);

        self.range()
            .map(|x| self.points.iter().map(|y| y.manhattan(&x)).sum::<usize>())
            .filter(|x| x < &limit)
            .count()
    }
}

fn claim_filter(claim: &Claim) -> Option<usize> {
    match claim {
        Claim::Some(id) => Some(*id),
        _ => None,
    }
}

impl Solution for Day06 {
    fn part1(&mut self, input: &mut Read) -> String {
        self.read_points(input);
        let grid = self.compute_claim_grid();
        let mut infinite: HashSet<usize> = HashSet::new();
        infinite.extend(grid[0].iter().filter_map(claim_filter));
        infinite.extend(grid[self.ymax].iter().filter_map(claim_filter));
        for y in 0..=self.ymax {
            infinite.extend([grid[y][0], grid[y][self.xmax]].iter().filter_map(claim_filter));
        }

        let counts = grid.iter().flat_map(|x| x.iter())
            .filter_map(claim_filter)
            .filter(|x| !infinite.contains(x)).grouping_count();

        format!("{}", counts.values().max().unwrap())
    }

    fn part2(&mut self, input: &mut Read) -> String {
        format!("{}", self.part2_with_limit(input, 10_000))
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day06::Day06;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/06.txt");

    #[test]
    fn sample_part1() {
        let mut instance = Day06::new();
        assert_eq!("17", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day06::new();
        assert_eq!(16, instance.part2_with_limit(&mut SAMPLE_INPUT, 32));
    }
}
<|endoftext|>