<commit_before>#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc;
extern crate syntax;

use std::ops::Deref;
use syntax::{ast, ext, codemap};
use syntax::abi::Abi;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::ptr::P;

#[plugin_registrar]
pub fn registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(token::intern("secs"),
        ext::base::Decorator(Box::new(SyntaxEcs))
    );
}

#[derive(Copy)]
pub struct SyntaxEcs;

impl ext::base::ItemDecorator for SyntaxEcs {
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>))
    {
        use syntax::ext::build::AstBuilder;
        //1: extract the path to `id` crate
        let id_path = match meta_item.node {
            ast::MetaList(_, ref list) if list.len() == 1 => {
                match list[0].node {
                    ast::MetaWord(ref path) => context.ident_of(path.deref()),
                    _ => {
                        context.span_err(span, "the `id` path should be a word");
                        return
                    }
                }
            },
            _ => {
                context.span_err(span, "use as `#[secs(id_path)]`");
                return
            }
        };
        //2: extract the prototype definition
        let (definition, generics) = match item.node {
            ast::ItemStruct(ref def, ref gen) => (def.deref(), gen),
            _ => {
                context.span_err(span, "#[secs] only works with structs");
                return
            }
        };
        let gen_types: Vec<_> = generics.ty_params.as_slice().iter().map(|typaram|
            context.ty_ident(typaram.span, typaram.ident)
        ).collect();
        //3: generate `struct Entity`
        let entity_ident = context.ident_of("Entity");
        let entity_ty = context.ty_path(context.path_all(span, false,
            vec![entity_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: entity_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: definition.fields.iter().map(|field| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: ast::StructFieldKind::NamedField(
                                field.node.ident().unwrap(),
                                ast::Visibility::Public
                            ),
                            id: field.node.id,
                            ty: {
                                let ty = field.node.ty.deref();
                                quote_ty!(context, Option<$id_path::Id<$ty>>)
                            },
                            attrs: Vec::new(),
                        },
                        span: field.span,
                    }).collect(),
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //4a: generate `struct Components`
        let comp_ident = context.ident_of("Components");
        let comp_ty = context.ty_path(context.path_all(span, false,
            vec![comp_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: comp_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: definition.fields.iter().map(|field| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: ast::StructFieldKind::NamedField(
                                field.node.ident().unwrap(),
                                ast::Visibility::Public
                            ),
                            id: field.node.id,
                            ty: {
                                let ty = field.node.ty.deref();
                                quote_ty!(context, $id_path::Array<$ty>>)
                            },
                            attrs: Vec::new(),
                        },
                        span: field.span,
                    }).collect(),
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //4b: generate `impl Components`
        let new_array = quote_expr!(context, $id_path::Array::new());
        fn make_generics() -> ast::Generics {
            ast::Generics {
                lifetimes: Vec::new(),
                ty_params: OwnedSlice::empty(),
                where_clause: ast::WhereClause {
                    id: ast::DUMMY_NODE_ID,
                    predicates: Vec::new(),
                },
            }
        }
        push(P(ast::Item {
            ident: comp_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics.clone(),
                None,   //TraitRef
                comp_ty.clone(),
                //method ::new() -> Components
                Some(P(ast::ImplItem {
                    id: ast::DUMMY_NODE_ID,
                    ident: context.ident_of("new"),
                    vis: item.vis,
                    attrs: Vec::new(),
                    node: ast::MethodImplItem(
                        ast::MethodSig {
                            unsafety: ast::Unsafety::Normal,
                            abi: Abi::Rust,
                            decl: context.fn_decl(Vec::new(), comp_ty.clone()),
                            generics: make_generics(),
                            explicit_self: codemap::Spanned {
                                node: ast::SelfStatic,
                                span: span,
                            },
                        },
                        context.block_expr(context.expr_struct_ident(
                            span, comp_ident, definition.fields.iter().map(|field|
                                context.field_imm(field.span, field.node.ident().unwrap(), new_array.clone())
                            ).collect()
                        ))
                    ),
                    span: span,
                })).into_iter()
                //TODO: add_X, get_X, mut_X, etc
                .collect()
            ),
            vis: ast::Visibility::Inherited,
            span: span,
        }));
        //5a: generate `struct World`
        let world_ident = context.ident_of("World");
        let world_ty = context.ty_path(context.path_all(span, false,
            vec![world_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: world_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: vec![
                        codemap::Spanned {
                            node: ast::StructField_ {
                                kind: ast::StructFieldKind::NamedField(
                                    context.ident_of("data"),
                                    ast::Visibility::Public,
                                ),
                                id: ast::DUMMY_NODE_ID,
                                ty: comp_ty,
                                attrs: Vec::new(),
                            },
                            span: span,
                        },
                        codemap::Spanned {
                            node: ast::StructField_ {
                                kind: ast::StructFieldKind::NamedField(
                                    context.ident_of("entities"),
                                    ast::Visibility::Public,
                                ),
                                id: ast::DUMMY_NODE_ID,
                                ty: quote_ty!(context, Vec<$entity_ty>),
                                attrs: Vec::new(),
                            },
                            span: span,
                        },
                    ],
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //5b: generate `impl World`
        push(P(ast::Item {
            ident: world_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics.clone(),
                None,   //TraitRef
                world_ty.clone(),
                vec![
                    P(ast::ImplItem {
                        id: ast::DUMMY_NODE_ID,
                        ident: context.ident_of("new"),
                        vis: item.vis,
                        attrs: Vec::new(),
                        node: ast::MethodImplItem(
                            ast::MethodSig {
                                unsafety: ast::Unsafety::Normal,
                                abi: Abi::Rust,
                                decl: context.fn_decl(Vec::new(), world_ty.clone()),
                                generics: make_generics(),
                                explicit_self: codemap::Spanned {
                                    node: ast::SelfStatic,
                                    span: span,
                                },
                            },
                            context.block_expr(quote_expr!(context,
                                World {
                                    data: Components::new(),
                                    entities: Vec::new(),
                                }
                            ))
                        ),
                        span: span,
                    })
                ]
            ),
            vis: ast::Visibility::Inherited,
            span: span,
        }));
    }
}
<commit_msg>Simple fix for Clone<commit_after>#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc;
extern crate syntax;

use std::ops::Deref;
use syntax::{ast, ext, codemap};
use syntax::abi::Abi;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token;
use syntax::ptr::P;

#[plugin_registrar]
pub fn registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(token::intern("secs"),
        ext::base::Decorator(Box::new(SyntaxEcs))
    );
}

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

impl ext::base::ItemDecorator for SyntaxEcs {
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>))
    {
        use syntax::ext::build::AstBuilder;
        //1: extract the path to `id` crate
        let id_path = match meta_item.node {
            ast::MetaList(_, ref list) if list.len() == 1 => {
                match list[0].node {
                    ast::MetaWord(ref path) => context.ident_of(path.deref()),
                    _ => {
                        context.span_err(span, "the `id` path should be a word");
                        return
                    }
                }
            },
            _ => {
                context.span_err(span, "use as `#[secs(id_path)]`");
                return
            }
        };
        //2: extract the prototype definition
        let (definition, generics) = match item.node {
            ast::ItemStruct(ref def, ref gen) => (def.deref(), gen),
            _ => {
                context.span_err(span, "#[secs] only works with structs");
                return
            }
        };
        let gen_types: Vec<_> = generics.ty_params.as_slice().iter().map(|typaram|
            context.ty_ident(typaram.span, typaram.ident)
        ).collect();
        //3: generate `struct Entity`
        let entity_ident = context.ident_of("Entity");
        let entity_ty = context.ty_path(context.path_all(span, false,
            vec![entity_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: entity_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: definition.fields.iter().map(|field| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: ast::StructFieldKind::NamedField(
                                field.node.ident().unwrap(),
                                ast::Visibility::Public
                            ),
                            id: field.node.id,
                            ty: {
                                let ty = field.node.ty.deref();
                                quote_ty!(context, Option<$id_path::Id<$ty>>)
                            },
                            attrs: Vec::new(),
                        },
                        span: field.span,
                    }).collect(),
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //4a: generate `struct Components`
        let comp_ident = context.ident_of("Components");
        let comp_ty = context.ty_path(context.path_all(span, false,
            vec![comp_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: comp_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: definition.fields.iter().map(|field| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: ast::StructFieldKind::NamedField(
                                field.node.ident().unwrap(),
                                ast::Visibility::Public
                            ),
                            id: field.node.id,
                            ty: {
                                let ty = field.node.ty.deref();
                                quote_ty!(context, $id_path::Array<$ty>>)
                            },
                            attrs: Vec::new(),
                        },
                        span: field.span,
                    }).collect(),
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //4b: generate `impl Components`
        let new_array = quote_expr!(context, $id_path::Array::new());
        fn make_generics() -> ast::Generics {
            ast::Generics {
                lifetimes: Vec::new(),
                ty_params: OwnedSlice::empty(),
                where_clause: ast::WhereClause {
                    id: ast::DUMMY_NODE_ID,
                    predicates: Vec::new(),
                },
            }
        }
        push(P(ast::Item {
            ident: comp_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics.clone(),
                None,   //TraitRef
                comp_ty.clone(),
                //method ::new() -> Components
                Some(P(ast::ImplItem {
                    id: ast::DUMMY_NODE_ID,
                    ident: context.ident_of("new"),
                    vis: item.vis,
                    attrs: Vec::new(),
                    node: ast::MethodImplItem(
                        ast::MethodSig {
                            unsafety: ast::Unsafety::Normal,
                            abi: Abi::Rust,
                            decl: context.fn_decl(Vec::new(), comp_ty.clone()),
                            generics: make_generics(),
                            explicit_self: codemap::Spanned {
                                node: ast::SelfStatic,
                                span: span,
                            },
                        },
                        context.block_expr(context.expr_struct_ident(
                            span, comp_ident, definition.fields.iter().map(|field|
                                context.field_imm(field.span, field.node.ident().unwrap(), new_array.clone())
                            ).collect()
                        ))
                    ),
                    span: span,
                })).into_iter()
                //TODO: add_X, get_X, mut_X, etc
                .collect()
            ),
            vis: ast::Visibility::Inherited,
            span: span,
        }));
        //5a: generate `struct World`
        let world_ident = context.ident_of("World");
        let world_ty = context.ty_path(context.path_all(span, false,
            vec![world_ident], Vec::new(), gen_types.clone(), Vec::new()
        ));
        push(P(ast::Item {
            ident: world_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemStruct(
                P(ast::StructDef {
                    fields: vec![
                        codemap::Spanned {
                            node: ast::StructField_ {
                                kind: ast::StructFieldKind::NamedField(
                                    context.ident_of("data"),
                                    ast::Visibility::Public,
                                ),
                                id: ast::DUMMY_NODE_ID,
                                ty: comp_ty,
                                attrs: Vec::new(),
                            },
                            span: span,
                        },
                        codemap::Spanned {
                            node: ast::StructField_ {
                                kind: ast::StructFieldKind::NamedField(
                                    context.ident_of("entities"),
                                    ast::Visibility::Public,
                                ),
                                id: ast::DUMMY_NODE_ID,
                                ty: quote_ty!(context, Vec<$entity_ty>),
                                attrs: Vec::new(),
                            },
                            span: span,
                        },
                    ],
                    ctor_id: None,
                }),
                generics.clone()
            ),
            vis: item.vis,
            span: span,
        }));
        //5b: generate `impl World`
        push(P(ast::Item {
            ident: world_ident,
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemImpl(
                ast::Unsafety::Normal,
                ast::ImplPolarity::Positive,
                generics.clone(),
                None,   //TraitRef
                world_ty.clone(),
                vec![
                    P(ast::ImplItem {
                        id: ast::DUMMY_NODE_ID,
                        ident: context.ident_of("new"),
                        vis: item.vis,
                        attrs: Vec::new(),
                        node: ast::MethodImplItem(
                            ast::MethodSig {
                                unsafety: ast::Unsafety::Normal,
                                abi: Abi::Rust,
                                decl: context.fn_decl(Vec::new(), world_ty.clone()),
                                generics: make_generics(),
                                explicit_self: codemap::Spanned {
                                    node: ast::SelfStatic,
                                    span: span,
                                },
                            },
                            context.block_expr(quote_expr!(context,
                                World {
                                    data: Components::new(),
                                    entities: Vec::new(),
                                }
                            ))
                        ),
                        span: span,
                    })
                ]
            ),
            vis: ast::Visibility::Inherited,
            span: span,
        }));
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, AddAssign, Sub, Div, Mul, Index, IndexMut};

use na;
use num::{Zero, One};

#[derive(Debug,Copy,PartialEq,Clone,Default)]
pub struct Spectrum {
    pub r: f32,
    pub g: f32,
    pub b: f32,
}

impl Spectrum {
    pub fn rgb(r: f32, g: f32, b: f32) -> Spectrum {
        Spectrum { r: r, g: g, b: b }
    }

    pub fn grey(v: f32) -> Spectrum {
        Spectrum { r: v, g: v, b: v }
    }

    pub fn white() -> Spectrum {
        Spectrum::rgb(1.0, 1.0, 1.0)
    }

    pub fn black() -> Spectrum {
        Spectrum::rgb(0.0, 0.0, 0.0)
    }

    pub fn red() -> Spectrum {
        Spectrum::rgb(1.0, 0.0, 0.0)
    }

    pub fn green() -> Spectrum {
        Spectrum::rgb(0.0, 1.0, 0.0)
    }

    pub fn blue() -> Spectrum {
        Spectrum::rgb(0.0, 0.0, 1.0)
    }

    pub fn to_srgb(&self) -> Spectrum {
        let a = 0.055f32;
        let b = 1f32 / 2.4;
        let mut srgb = Spectrum::black();
        for i in 0..3 {
            if self[i] <= 0.0031308 {
                srgb[i] = 12.92 * self[i];
            } else {
                srgb[i] = (1.0 + a) * f32::powf(self[i], b) - a;
            }
        }
        srgb
    }

    pub fn from_srgb(rgb: &[u8; 3]) -> Spectrum {
        fn convert(v: u8) -> f32 {
            let value = v as f32 / 255.0;
            if value <= 0.0031308 {
                12.92 * value
            } else {
                1.055 * value.powf(1.0 / 2.4) - 0.055
            }
        }

        Spectrum::rgb(convert(rgb[0]), convert(rgb[1]), convert(rgb[2]))
    }

    pub fn is_black(&self) -> bool {
        self.r == 0.0 && self.g == 0.0 && self.b == 0.0
    }

    pub fn has_nan(&self) -> bool {
        self.r.is_nan() || self.g.is_nan() || self.b.is_nan()
    }

    pub fn is_infinite(&self) -> bool {
        self.r.is_infinite() || self.g.is_infinite() || self.b.is_infinite()
    }

    pub fn sqrt(&self) -> Spectrum {
        Spectrum::rgb(self.r.sqrt(), self.g.sqrt(), self.b.sqrt())
    }
}

impl Add<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn add(self, rhs: Spectrum) -> Spectrum {
        Spectrum {
            r: self.r + rhs.r,
            g: self.g + rhs.g,
            b: self.b + rhs.b,
        }
    }
}

impl Sub<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn sub(self, rhs: Spectrum) -> Spectrum {
        Spectrum {
            r: self.r - rhs.r,
            g: self.g - rhs.g,
            b: self.b - rhs.b,
        }
    }
}

impl AddAssign<Spectrum> for Spectrum {
    fn add_assign(&mut self, rhs: Spectrum) {
        self.r += rhs.r;
        self.g += rhs.g;
        self.b += rhs.b;
    }
}

impl Mul<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn mul(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self.r * rhs.r, self.g * rhs.g, self.b * rhs.b)
    }
}

impl Div<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn div(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self.r / rhs.r, self.g / rhs.g, self.b / rhs.b)
    }
}

impl Add<f32> for Spectrum {
    type Output = Spectrum;

    fn add(self, rhs: f32) -> Spectrum {
        Spectrum {
            r: self.r + rhs,
            g: self.g + rhs,
            b: self.b + rhs,
        }
    }
}

impl Sub<f32> for Spectrum {
    type Output = Spectrum;

    fn sub(self, rhs: f32) -> Spectrum {
        Spectrum {
            r: self.r - rhs,
            g: self.g - rhs,
            b: self.b - rhs,
        }
    }
}

impl Mul<f32> for Spectrum {
    type Output = Spectrum;

    fn mul(self, rhs: f32) -> Spectrum {
        Spectrum::rgb(self.r * rhs, self.g * rhs, self.b * rhs)
    }
}

impl Mul<Spectrum> for f32 {
    type Output = Spectrum;

    fn mul(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self * rhs.r, self * rhs.g, self * rhs.b)
    }
}

impl Div<f32> for Spectrum {
    type Output = Spectrum;

    fn div(self, rhs: f32) -> Spectrum {
        Spectrum::rgb(self.r / rhs, self.g / rhs, self.b / rhs)
    }
}

impl From<Spectrum> for [u8; 3] {
    fn from(c: Spectrum) -> [u8; 3] {
        [(na::clamp(c.r, 0.0, 1.0) * 255.0) as u8,
         (na::clamp(c.g, 0.0, 1.0) * 255.0) as u8,
         (na::clamp(c.b, 0.0, 1.0) * 255.0) as u8]
    }
}

impl Index<usize> for Spectrum {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    fn index(&self, i: usize) -> &f32 {
        match i {
            0 => &self.r,
            1 => &self.g,
            2 => &self.b,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl IndexMut<usize> for Spectrum {
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    fn index_mut(&mut self, i: usize) -> &mut f32 {
        match i {
            0 => &mut self.r,
            1 => &mut self.g,
            2 => &mut self.b,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl Zero for Spectrum {
    fn zero() -> Spectrum {
        Spectrum::black()
    }

    fn is_zero(&self) -> bool {
        self.is_black()
    }
}

impl One for Spectrum {
    fn one() -> Spectrum {
        Spectrum::white()
    }
}
<commit_msg>Add constructor for RGB Spectrum from SPD sampled data<commit_after>use std::ops::{Add, AddAssign, Sub, Div, Mul, Index, IndexMut};

use na;
use num::{Zero, One};

use ::lerp;
use cie;

#[derive(Debug,Copy,PartialEq,Clone,Default)]
pub struct Spectrum {
    pub r: f32,
    pub g: f32,
    pub b: f32,
}

impl Spectrum {
    pub fn rgb(r: f32, g: f32, b: f32) -> Spectrum {
        Spectrum { r: r, g: g, b: b }
    }

    pub fn grey(v: f32) -> Spectrum {
        Spectrum { r: v, g: v, b: v }
    }

    pub fn white() -> Spectrum {
        Spectrum::rgb(1.0, 1.0, 1.0)
    }

    pub fn black() -> Spectrum {
        Spectrum::rgb(0.0, 0.0, 0.0)
    }

    pub fn red() -> Spectrum {
        Spectrum::rgb(1.0, 0.0, 0.0)
    }

    pub fn green() -> Spectrum {
        Spectrum::rgb(0.0, 1.0, 0.0)
    }

    pub fn blue() -> Spectrum {
        Spectrum::rgb(0.0, 0.0, 1.0)
    }

    pub fn to_srgb(&self) -> Spectrum {
        let a = 0.055f32;
        let b = 1f32 / 2.4;
        let mut srgb = Spectrum::black();
        for i in 0..3 {
            if self[i] <= 0.0031308 {
                srgb[i] = 12.92 * self[i];
            } else {
                srgb[i] = (1.0 + a) * f32::powf(self[i], b) - a;
            }
        }
        srgb
    }

    pub fn from_srgb(rgb: &[u8; 3]) -> Spectrum {
        fn convert(v: u8) -> f32 {
            let value = v as f32 / 255.0;
            if value <= 0.0031308 {
                12.92 * value
            } else {
                1.055 * value.powf(1.0 / 2.4) - 0.055
            }
        }

        Spectrum::rgb(convert(rgb[0]), convert(rgb[1]), convert(rgb[2]))
    }

    pub fn from_xyz(xyz: &[f32; 3]) -> Spectrum {
        let r = 3.240479 * xyz[0] - 1.537150 * xyz[1] - 0.498535 * xyz[2];
        let g = -0.969256 * xyz[0] + 1.875991 * xyz[1] + 0.041556 * xyz[2];
        let b = 0.055648 * xyz[0] - 0.204043 * xyz[1] + 1.057311 * xyz[2];
        Spectrum::rgb(r, g, b)
    }

    pub fn from_sampled(lambda: &[f32], v: &[f32], n: usize) -> Spectrum {
        // TODO sort by wavelength if needed
        let mut xyz = [0.0; 3];
        for i in 0..cie::nCIESamples {
            let val = interpolate_spectrum_samples(lambda, v, n, cie::CIE_lambda[i]);
            xyz[0] += val * cie::CIE_X[i];
            xyz[1] += val * cie::CIE_Y[i];
            xyz[2] += val * cie::CIE_Z[i];
        }
        let scale = (cie::CIE_lambda[cie::nCIESamples - 1] - cie::CIE_lambda[0]) /
                    (cie::CIE_Y_integral * cie::nCIESamples as f32);
        xyz[0] *= scale;
        xyz[1] *= scale;
        xyz[2] *= scale;

        Self::from_xyz(&xyz)
    }

    pub fn is_black(&self) -> bool {
        self.r == 0.0 && self.g == 0.0 && self.b == 0.0
    }

    pub fn has_nan(&self) -> bool {
        self.r.is_nan() || self.g.is_nan() || self.b.is_nan()
    }

    pub fn is_infinite(&self) -> bool {
        self.r.is_infinite() || self.g.is_infinite() || self.b.is_infinite()
    }

    pub fn sqrt(&self) -> Spectrum {
        Spectrum::rgb(self.r.sqrt(), self.g.sqrt(), self.b.sqrt())
    }
}

fn interpolate_spectrum_samples(lambda: &[f32], vals: &[f32], n: usize, l: f32) -> f32 {
    for i in 0..n - 1 {
        assert!(lambda[i + 1] > lambda[i]);
    }
    if l <= lambda[0] {
        return vals[0];
    }
    if l >= lambda[n - 1] {
        return vals[n - 1];
    }
    let offset = find_interval(n, |index| lambda[index] <= l);
    assert!(l >= lambda[offset] && l <= lambda[offset + 1]);
    let t = (l - lambda[offset]) / (lambda[offset + 1] - lambda[offset]);
    lerp(t, vals[offset], vals[offset + 1])
}

fn find_interval<P>(size: usize, pred: P) -> usize
    where P: Fn(usize) -> bool
{
    let mut first = 0;
    let mut len = size;
    while len > 0 {
        let half = len >> 1;
        let middle = first + half;
        // Bisect range based on value of _pred_ at _middle_
        if pred(middle) {
            first = middle + 1;
            len -= half + 1;
        } else {
            len = half;
        }
    }
    na::clamp(first - 1, 0, size - 2)
}

// Operators

impl Add<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn add(self, rhs: Spectrum) -> Spectrum {
        Spectrum {
            r: self.r + rhs.r,
            g: self.g + rhs.g,
            b: self.b + rhs.b,
        }
    }
}

impl Sub<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn sub(self, rhs: Spectrum) -> Spectrum {
        Spectrum {
            r: self.r - rhs.r,
            g: self.g - rhs.g,
            b: self.b - rhs.b,
        }
    }
}

impl AddAssign<Spectrum> for Spectrum {
    fn add_assign(&mut self, rhs: Spectrum) {
        self.r += rhs.r;
        self.g += rhs.g;
        self.b += rhs.b;
    }
}

impl Mul<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn mul(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self.r * rhs.r, self.g * rhs.g, self.b * rhs.b)
    }
}

impl Div<Spectrum> for Spectrum {
    type Output = Spectrum;

    fn div(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self.r / rhs.r, self.g / rhs.g, self.b / rhs.b)
    }
}

impl Add<f32> for Spectrum {
    type Output = Spectrum;

    fn add(self, rhs: f32) -> Spectrum {
        Spectrum {
            r: self.r + rhs,
            g: self.g + rhs,
            b: self.b + rhs,
        }
    }
}

impl Sub<f32> for Spectrum {
    type Output = Spectrum;

    fn sub(self, rhs: f32) -> Spectrum {
        Spectrum {
            r: self.r - rhs,
            g: self.g - rhs,
            b: self.b - rhs,
        }
    }
}

impl Mul<f32> for Spectrum {
    type Output = Spectrum;

    fn mul(self, rhs: f32) -> Spectrum {
        Spectrum::rgb(self.r * rhs, self.g * rhs, self.b * rhs)
    }
}

impl Mul<Spectrum> for f32 {
    type Output = Spectrum;

    fn mul(self, rhs: Spectrum) -> Spectrum {
        Spectrum::rgb(self * rhs.r, self * rhs.g, self * rhs.b)
    }
}

impl Div<f32> for Spectrum {
    type Output = Spectrum;

    fn div(self, rhs: f32) -> Spectrum {
        Spectrum::rgb(self.r / rhs, self.g / rhs, self.b / rhs)
    }
}

impl From<Spectrum> for [u8; 3] {
    fn from(c: Spectrum) -> [u8; 3] {
        [(na::clamp(c.r, 0.0, 1.0) * 255.0) as u8,
         (na::clamp(c.g, 0.0, 1.0) * 255.0) as u8,
         (na::clamp(c.b, 0.0, 1.0) * 255.0) as u8]
    }
}

impl Index<usize> for Spectrum {
    type Output = f32;
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    fn index(&self, i: usize) -> &f32 {
        match i {
            0 => &self.r,
            1 => &self.g,
            2 => &self.b,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl IndexMut<usize> for Spectrum {
    /// Access the channels by index
    ///
    /// - 0 = r
    /// - 1 = g
    /// - 2 = b
    fn index_mut(&mut self, i: usize) -> &mut f32 {
        match i {
            0 => &mut self.r,
            1 => &mut self.g,
            2 => &mut self.b,
            _ => panic!("Invalid index into color"),
        }
    }
}

impl Zero for Spectrum {
    fn zero() -> Spectrum {
        Spectrum::black()
    }

    fn is_zero(&self) -> bool {
        self.is_black()
    }
}

impl One for Spectrum {
    fn one() -> Spectrum {
        Spectrum::white()
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    collections::BTreeMap,
    f64,
};

use dces::prelude::Entity;

use crate::{prelude::*, render::RenderContext2D, tree::Tree, utils::prelude::*};

use super::{component, component_try_mut, Layout};

/// IMPORTANT: The scroll layout will only work for the text box now. A update will follow!!!!
#[derive(Default)]
pub struct ScrollLayout {
    old_child_size: Cell<(f64, f64)>,
    desired_size: RefCell<DirtySize>,
    old_offset: Cell<(f64, f64)>,
    old_alignment: Cell<(Alignment, Alignment)>,
}

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

impl Layout for ScrollLayout {
    fn measure(
        &self,
        render_context_2_d: &mut RenderContext2D,
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> DirtySize {
        if component::<Visibility>(ecm, entity, "visibility") == Visibility::Collapsed {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return *self.desired_size.borrow();
        }

        let horizontal_alignment: Alignment = component(ecm, entity, "h_align");
        let vertical_alignment: Alignment = component(ecm, entity, "v_align");

        if horizontal_alignment != self.old_alignment.get().1
            || vertical_alignment != self.old_alignment.get().0
        {
            self.desired_size.borrow_mut().set_dirty(true);
        }

        let constraint: Constraint = component(ecm, entity, "constraint");

        if constraint.width() > 0.0 {
            self.desired_size.borrow_mut().set_width(constraint.width());
        }

        if constraint.height() > 0.0 {
            self.desired_size
                .borrow_mut()
                .set_height(constraint.height());
        }

        for index in 0..ecm.entity_store().children[&entity].len() {
            let child = ecm.entity_store().children[&entity][index];

            if let Some(child_layout) = layouts.get(&child) {
                let dirty = child_layout
                    .measure(render_context_2_d, child, ecm, layouts, theme)
                    .dirty()
                    || self.desired_size.borrow().dirty();

                self.desired_size.borrow_mut().set_dirty(dirty);
            }
        }

        let off: Point = *ecm.component_store().get("scroll_offset", entity).unwrap();

        if (self.old_offset.get().0 - off.x).abs() > std::f64::EPSILON
            || (self.old_offset.get().1 - off.y).abs() > std::f64::EPSILON
        {
            self.old_offset.set((off.x, off.y));
            self.desired_size.borrow_mut().set_dirty(true);
        }

        *self.desired_size.borrow()
    }

    fn arrange(
        &self,
        render_context_2_d: &mut RenderContext2D,
        parent_size: (f64, f64),
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> (f64, f64) {
        if component::<Visibility>(ecm, entity, "visibility") == Visibility::Collapsed {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return (0.0, 0.0);
        }

        if !self.desired_size.borrow().dirty() {
            return self.desired_size.borrow().size();
        }

        let horizontal_alignment: Alignment = component(ecm, entity, "h_align");
        let vertical_alignment: Alignment = component(ecm, entity, "v_align");
        let margin: Thickness = *ecm.component_store().get("margin", entity).unwrap();
        // let _padding = Thickness::get("padding", entity, ecm.component_store());
        let constraint: Constraint = component(ecm, entity, "constraint");

        let size = constraint.perform((
            horizontal_alignment.align_measure(
                parent_size.0,
                self.desired_size.borrow().width(),
                margin.left(),
                margin.right(),
            ),
            vertical_alignment.align_measure(
                parent_size.1,
                self.desired_size.borrow().height(),
                margin.top(),
                margin.bottom(),
            ),
        ));

        if let Some(bounds) = component_try_mut::<Rectangle>(ecm, entity, "bounds") {
            bounds.set_width(size.0);
            bounds.set_height(size.1);
        }

        let scroll_viewer_mode: ScrollViewerMode = component(ecm, entity, "scroll_viewer_mode");

        let available_size = {
            let width = if scroll_viewer_mode.horizontal == ScrollMode::Custom
                || scroll_viewer_mode.horizontal == ScrollMode::Auto
            {
                f64::MAX
            } else {
                size.0
            };

            let height = if scroll_viewer_mode.vertical == ScrollMode::Custom
                || scroll_viewer_mode.vertical == ScrollMode::Auto
            {
                f64::MAX
            } else {
                size.1
            };

            (width, height)
        };

        let off: Point = component(ecm, entity, "scroll_offset");
        let delta: Point = component(ecm, entity, "delta");
        let mut offset = (off.x, off.y);

        let old_child_size = self.old_child_size.get();

        let nchildren = ecm.entity_store().children[&entity].len();

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            // let child_margin = get_margin(*child, store);
            let mut child_size = old_child_size;
            let child_vertical_alignment: Alignment =
                *ecm.component_store().get("v_align", child).unwrap();
            let child_horizontal_alignment: Alignment =
                *ecm.component_store().get("h_align", child).unwrap();
            let child_margin: Thickness = component(ecm, entity, "margin");

            if let Some(child_layout) = layouts.get(&child) {
                child_size = child_layout.arrange(
                    render_context_2_d,
                    available_size,
                    child,
                    ecm,
                    layouts,
                    theme,
                );
            }

            match scroll_viewer_mode.horizontal {
                ScrollMode::Custom => {
                    if child_size.0 > size.0 {
                        offset.0 = (offset.0 + old_child_size.0 - child_size.0).min(0.0);
                    } else {
                        offset.0 = 0.0;
                    }
                }
                ScrollMode::Auto => {
                    // todo: refactor * 1.5
                    offset.0 = delta
                        .x
                        .mul_add(1.5, offset.0)
                        .min(0.0)
                        .max(size.0 - child_size.0);
                }
                _ => {}
            }

            match scroll_viewer_mode.vertical {
                ScrollMode::Custom => {
                    if child_size.1 > size.1 {
                        offset.1 = (offset.1 + old_child_size.1 - child_size.1).min(1.1);
                    } else {
                        offset.1 = 1.1;
                    }
                }
                ScrollMode::Auto => {
                    // todo: refactor * 1.5
                    offset.1 = delta
                        .y
                        .mul_add(1.5, offset.1)
                        .min(1.1)
                        .max(size.1 - child_size.1);
                }
                _ => {}
            }

            if let Ok(child_bounds) = ecm
                .component_store_mut()
                .get_mut::<Rectangle>("bounds", child)
            {
                // todo: add check
                if scroll_viewer_mode.horizontal == ScrollMode::Custom
                    || scroll_viewer_mode.horizontal == ScrollMode::Auto
                {
                    if child_bounds.width() <= size.0 {
                        child_bounds.set_x(0.0);
                    } else {
                        child_bounds.set_x(offset.0);
                    }
                } else {
                    child_bounds.set_x(child_horizontal_alignment.align_position(
                        size.0,
                        child_bounds.width(),
                        child_margin.left(),
                        child_margin.right(),
                    ));
                }

                if scroll_viewer_mode.vertical == ScrollMode::Custom
                    || scroll_viewer_mode.vertical == ScrollMode::Auto
                {
                    if child_bounds.height() <= size.1 {
                        child_bounds.set_y(0.0);
                    } else {
                        child_bounds.set_y(offset.1);
                    }
                } else {
                    child_bounds.set_y(child_vertical_alignment.align_position(
                        size.1,
                        child_bounds.height(),
                        child_margin.top(),
                        child_margin.bottom(),
                    ));
                }
            }

            if let Ok(off) = ecm
                .component_store_mut()
                .get_mut::<Point>("scroll_offset", entity)
            {
                off.x = offset.0;
                off.y = offset.1;
            }

            self.old_child_size.set(child_size);
        }

        self.desired_size.borrow_mut().set_dirty(false);
        size
    }
}

impl Into<Box<dyn Layout>> for ScrollLayout {
    fn into(self) -> Box<dyn Layout> {
        Box::new(self)
    }
}
<commit_msg>Updated usage of `Rectangle` and `Point`<commit_after>use std::{
    cell::{Cell, RefCell},
    collections::BTreeMap,
    f64,
};

use dces::prelude::Entity;

use crate::{prelude::*, render::RenderContext2D, tree::Tree, utils::prelude::*};

use super::{component, component_try_mut, Layout};

/// IMPORTANT: The scroll layout will only work for the text box now. A update will follow!!!!
#[derive(Default)]
pub struct ScrollLayout {
    old_child_size: Cell<(f64, f64)>,
    desired_size: RefCell<DirtySize>,
    old_offset: Cell<(f64, f64)>,
    old_alignment: Cell<(Alignment, Alignment)>,
}

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

impl Layout for ScrollLayout {
    fn measure(
        &self,
        render_context_2_d: &mut RenderContext2D,
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> DirtySize {
        if component::<Visibility>(ecm, entity, "visibility") == Visibility::Collapsed {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return *self.desired_size.borrow();
        }

        let horizontal_alignment: Alignment = component(ecm, entity, "h_align");
        let vertical_alignment: Alignment = component(ecm, entity, "v_align");

        if horizontal_alignment != self.old_alignment.get().1
            || vertical_alignment != self.old_alignment.get().0
        {
            self.desired_size.borrow_mut().set_dirty(true);
        }

        let constraint: Constraint = component(ecm, entity, "constraint");

        if constraint.width() > 0.0 {
            self.desired_size.borrow_mut().set_width(constraint.width());
        }

        if constraint.height() > 0.0 {
            self.desired_size
                .borrow_mut()
                .set_height(constraint.height());
        }

        for index in 0..ecm.entity_store().children[&entity].len() {
            let child = ecm.entity_store().children[&entity][index];

            if let Some(child_layout) = layouts.get(&child) {
                let dirty = child_layout
                    .measure(render_context_2_d, child, ecm, layouts, theme)
                    .dirty()
                    || self.desired_size.borrow().dirty();

                self.desired_size.borrow_mut().set_dirty(dirty);
            }
        }

        let off: Point = *ecm.component_store().get("scroll_offset", entity).unwrap();

        if (self.old_offset.get().0 - off.x()).abs() > std::f64::EPSILON
            || (self.old_offset.get().1 - off.y()).abs() > std::f64::EPSILON
        {
            self.old_offset.set((off.x(), off.y()));
            self.desired_size.borrow_mut().set_dirty(true);
        }

        *self.desired_size.borrow()
    }

    fn arrange(
        &self,
        render_context_2_d: &mut RenderContext2D,
        parent_size: (f64, f64),
        entity: Entity,
        ecm: &mut EntityComponentManager<Tree, StringComponentStore>,
        layouts: &BTreeMap<Entity, Box<dyn Layout>>,
        theme: &ThemeValue,
    ) -> (f64, f64) {
        if component::<Visibility>(ecm, entity, "visibility") == Visibility::Collapsed {
            self.desired_size.borrow_mut().set_size(0.0, 0.0);
            return (0.0, 0.0);
        }

        if !self.desired_size.borrow().dirty() {
            return self.desired_size.borrow().size();
        }

        let horizontal_alignment: Alignment = component(ecm, entity, "h_align");
        let vertical_alignment: Alignment = component(ecm, entity, "v_align");
        let margin: Thickness = *ecm.component_store().get("margin", entity).unwrap();
        // let _padding = Thickness::get("padding", entity, ecm.component_store());
        let constraint: Constraint = component(ecm, entity, "constraint");

        let size = constraint.perform((
            horizontal_alignment.align_measure(
                parent_size.0,
                self.desired_size.borrow().width(),
                margin.left(),
                margin.right(),
            ),
            vertical_alignment.align_measure(
                parent_size.1,
                self.desired_size.borrow().height(),
                margin.top(),
                margin.bottom(),
            ),
        ));

        if let Some(bounds) = component_try_mut::<Rectangle>(ecm, entity, "bounds") {
            bounds.set_width(size.0);
            bounds.set_height(size.1);
        }

        let scroll_viewer_mode: ScrollViewerMode = component(ecm, entity, "scroll_viewer_mode");

        let available_size = {
            let width = if scroll_viewer_mode.horizontal == ScrollMode::Custom
                || scroll_viewer_mode.horizontal == ScrollMode::Auto
            {
                f64::MAX
            } else {
                size.0
            };

            let height = if scroll_viewer_mode.vertical == ScrollMode::Custom
                || scroll_viewer_mode.vertical == ScrollMode::Auto
            {
                f64::MAX
            } else {
                size.1
            };

            (width, height)
        };

        let off: Point = component(ecm, entity, "scroll_offset");
        let delta: Point = component(ecm, entity, "delta");
        let mut offset = (off.x(), off.y());

        let old_child_size = self.old_child_size.get();

        let nchildren = ecm.entity_store().children[&entity].len();

        for index in 0..nchildren {
            let child = ecm.entity_store().children[&entity][index];

            // let child_margin = get_margin(*child, store);
            let mut child_size = old_child_size;
            let child_vertical_alignment: Alignment =
                *ecm.component_store().get("v_align", child).unwrap();
            let child_horizontal_alignment: Alignment =
                *ecm.component_store().get("h_align", child).unwrap();
            let child_margin: Thickness = component(ecm, entity, "margin");

            if let Some(child_layout) = layouts.get(&child) {
                child_size = child_layout.arrange(
                    render_context_2_d,
                    available_size,
                    child,
                    ecm,
                    layouts,
                    theme,
                );
            }

            match scroll_viewer_mode.horizontal {
                ScrollMode::Custom => {
                    if child_size.0 > size.0 {
                        offset.0 = (offset.0 + old_child_size.0 - child_size.0).min(0.0);
                    } else {
                        offset.0 = 0.0;
                    }
                }
                ScrollMode::Auto => {
                    // todo: refactor * 1.5
                    offset.0 = delta
                        .x()
                        .mul_add(1.5, offset.0)
                        .min(0.0)
                        .max(size.0 - child_size.0);
                }
                _ => {}
            }

            match scroll_viewer_mode.vertical {
                ScrollMode::Custom => {
                    if child_size.1 > size.1 {
                        offset.1 = (offset.1 + old_child_size.1 - child_size.1).min(1.1);
                    } else {
                        offset.1 = 1.1;
                    }
                }
                ScrollMode::Auto => {
                    // todo: refactor * 1.5
                    offset.1 = delta
                        .y()
                        .mul_add(1.5, offset.1)
                        .min(1.1)
                        .max(size.1 - child_size.1);
                }
                _ => {}
            }

            if let Ok(child_bounds) = ecm
                .component_store_mut()
                .get_mut::<Rectangle>("bounds", child)
            {
                // todo: add check
                if scroll_viewer_mode.horizontal == ScrollMode::Custom
                    || scroll_viewer_mode.horizontal == ScrollMode::Auto
                {
                    if child_bounds.width() <= size.0 {
                        child_bounds.set_x(0.0);
                    } else {
                        child_bounds.set_x(offset.0);
                    }
                } else {
                    child_bounds.set_x(child_horizontal_alignment.align_position(
                        size.0,
                        child_bounds.width(),
                        child_margin.left(),
                        child_margin.right(),
                    ));
                }

                if scroll_viewer_mode.vertical == ScrollMode::Custom
                    || scroll_viewer_mode.vertical == ScrollMode::Auto
                {
                    if child_bounds.height() <= size.1 {
                        child_bounds.set_y(0.0);
                    } else {
                        child_bounds.set_y(offset.1);
                    }
                } else {
                    child_bounds.set_y(child_vertical_alignment.align_position(
                        size.1,
                        child_bounds.height(),
                        child_margin.top(),
                        child_margin.bottom(),
                    ));
                }
            }

            if let Ok(off) = ecm
                .component_store_mut()
                .get_mut::<Point>("scroll_offset", entity)
            {
                off.set_x(offset.0);
                off.set_y(offset.1);
            }

            self.old_child_size.set(child_size);
        }

        self.desired_size.borrow_mut().set_dirty(false);
        size
    }
}

impl Into<Box<dyn Layout>> for ScrollLayout {
    fn into(self) -> Box<dyn Layout> {
        Box::new(self)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}
<commit_msg>Array, Mul, Add, Zero working, overall WIP<commit_after>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::Zero;
use std::ops::{Add, Index, IndexMut, Mul};
use math::cgmath::prelude::Array;
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

impl Zero for AxialVector {
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

impl Array for AxialVector {
    type Element = AxialType;

    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    fn product(self) -> Self::Element {
        self.q * self.r
    }

    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

impl Index<usize> for AxialVector {
    type Output = AxialType;

    fn index(&self, index: usize) -> &Self::Output {
        let ret: &AxialType = match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        };
        ret
    }
}

impl IndexMut<usize> for AxialVector {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Formatter, Result as FmtResult};

use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
use serde::{Deserializer, Serializer};
use serde::de::{Error as SerdeError, Visitor};

pub trait SerdeBlob<'de>: Sized {
    fn deserialize_blob<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>;

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer;
}

struct BlobVisitor;

impl <'de> Visitor<'de> for BlobVisitor {
    type Value = Vec<u8>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: SerdeError {
        v.from_base64().map_err(|err| SerdeError::custom(err.description()))
    }
}

impl <'de> SerdeBlob<'de> for Vec<u8> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_any(BlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        serializer.serialize_str(&self.as_slice().to_base64(STANDARD))
    }
}

struct OptionalBlobVisitor;

impl <'de> Visitor<'de> for OptionalBlobVisitor {
    type Value = Option<Vec<u8>>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_none<E>(self) -> Result<Self::Value, E>
        where E: SerdeError {
        Ok(None)
    }

    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de> {
        Ok(Some(try!(SerdeBlob::deserialize_blob(deserializer))))
    }
}

impl <'de> SerdeBlob<'de> for Option<Vec<u8>> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_option(OptionalBlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        match *self {
            Some(ref vec) => serializer.serialize_some(vec),
            None => serializer.serialize_none(),
        }
    }
}
<commit_msg>Fix serialization of optional blobs.<commit_after>use std::error::Error;
use std::fmt::{Formatter, Result as FmtResult};

use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
use serde::{Deserializer, Serializer};
use serde::de::{Error as SerdeError, Visitor};

pub trait SerdeBlob<'de>: Sized {
    fn deserialize_blob<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>;

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer;
}

struct BlobVisitor;

impl <'de> Visitor<'de> for BlobVisitor {
    type Value = Vec<u8>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: SerdeError {
        v.from_base64().map_err(|err| SerdeError::custom(err.description()))
    }
}

impl <'de> SerdeBlob<'de> for Vec<u8> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_any(BlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        serializer.serialize_str(&self.as_slice().to_base64(STANDARD))
    }
}

struct OptionalBlobVisitor;

impl <'de> Visitor<'de> for OptionalBlobVisitor {
    type Value = Option<Vec<u8>>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_none<E>(self) -> Result<Self::Value, E>
        where E: SerdeError {
        Ok(None)
    }

    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de> {
        Ok(Some(try!(SerdeBlob::deserialize_blob(deserializer))))
    }
}

impl <'de> SerdeBlob<'de> for Option<Vec<u8>> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_option(OptionalBlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        match *self {
            Some(ref vec) => SerdeBlob::serialize_blob(vec, serializer),
            None => serializer.serialize_none(),
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::client::Context;
use crate::model::channel::Message;
use uwl::{StrExt, UnicodeStream};

#[derive(Debug, Clone, PartialEq)]
pub enum Prefix<'a> {
    Punct(&'a str),
    Mention(&'a str),
    None,
    #[doc(hidden)]
    __Nonexhaustive,
}

pub fn parse_prefix<'a>(
    ctx: &mut Context,
    msg: &'a Message,
    config: &Configuration,
) -> (Prefix<'a>, &'a str) {
    let mut stream = UnicodeStream::new(&msg.content);
    stream.take_while(|s| s.is_whitespace());

    if let Some(ref mention) = config.on_mention {
        if let Ok(id) = stream.parse("<@(!){}>") {
            if id.is_numeric() && mention == id {
                stream.take_while(|s| s.is_whitespace());
                return (Prefix::Mention(id), stream.rest());
            }
        }
    }

    let mut prefix = None;
    if !config.prefixes.is_empty() || !config.dynamic_prefixes.is_empty() {
        for f in &config.dynamic_prefixes {
            if let Some(p) = f(ctx, msg) {
                let pp = stream.peek_for(p.chars().count());

                if p == pp {
                    prefix = Some(pp);
                    break;
                }
            }
        }

        for p in &config.prefixes {
            // If `dynamic_prefixes` succeeded, don't iterate through the normal prefixes.
            if prefix.is_some() {
                break;
            }

            let pp = stream.peek_for(p.chars().count());

            if p == pp {
                prefix = Some(pp);
                break;
            }
        }
    }

    if let Some(prefix) = prefix {
        stream.increment(prefix.len());

        if config.with_whitespace.prefixes {
            stream.take_while(|s| s.is_whitespace());
        }

        let args = stream.rest();

        return (Prefix::Punct(prefix), args.trim());
    }

    if config.with_whitespace.prefixes {
        stream.take_while(|s| s.is_whitespace());
    }

    let args = stream.rest();
    (Prefix::None, args.trim())
}

struct CommandParser<'msg, 'groups, 'config, 'ctx> {
    msg: &'msg Message,
    stream: UnicodeStream<'msg>,
    groups: &'groups [&'static CommandGroup],
    config: &'config Configuration,
    ctx: &'ctx Context,
    unrecognised: Option<&'msg str>,
}

impl<'msg, 'groups, 'config, 'ctx> CommandParser<'msg, 'groups, 'config, 'ctx> {
    fn new(
        msg: &'msg Message,
        stream: UnicodeStream<'msg>,
        groups: &'groups [&'static CommandGroup],
        config: &'config Configuration,
        ctx: &'ctx Context,
    ) -> Self {
        CommandParser {
            msg,
            stream,
            groups,
            config,
            ctx,
            unrecognised: None,
        }
    }

    fn next_text(&self, length: impl FnOnce() -> usize) -> &'msg str {
        if self.config.by_space {
            self.stream.peek_until(|s| s.is_whitespace())
        } else {
            self.stream.peek_for(length())
        }
    }

    fn as_lowercase(&self, s: &str, f: impl FnOnce(&str) -> bool) -> bool {
        if self.config.case_insensitive {
            let s = s.to_lowercase();
            f(&s)
        } else {
            f(s)
        }
    }

    fn check_discrepancy(&self, options: &impl CommonOptions) -> Result<(), DispatchError> {
        if options.owners_only() && !self.config.owners.contains(&self.msg.author.id) {
            return Err(DispatchError::OnlyForOwners);
        }

        if options.only_in() == OnlyIn::Dm && !self.msg.is_private() {
            return Err(DispatchError::OnlyForDM);
        }

        if (!self.config.allow_dm || options.only_in() == OnlyIn::Guild) && self.msg.is_private() {
            return Err(DispatchError::OnlyForGuilds);
        }

        #[cfg(feature = "cache")]
        {
            if let Some(guild_id) = self.msg.guild_id {
                let guild = match guild_id.to_guild_cached(&self.ctx) {
                    Some(g) => g,
                    None => return Ok(()),
                };

                let guild = guild.read();

                let perms = guild.permissions_in(self.msg.channel_id, self.msg.author.id);

                if !perms.contains(*options.required_permissions()) &&
                    !(options.owner_privilege() &&
                        self.config.owners.contains(&self.msg.author.id)) {
                    return Err(DispatchError::LackingPermissions(*options.required_permissions()));
                }

                if let Some(member) = guild.members.get(&self.msg.author.id) {
                    if !perms.administrator() && !has_correct_roles(options, &guild, &member) {
                        return Err(DispatchError::LackingRole);
                    }
                }

            }
        }

        Ok(())
    }

    fn command(&mut self, command: &'static Command) -> Result<Option<&'static Command>, DispatchError> {
        for name in command.options.names {
            // FIXME: If `by_space` option is set true, we shouldn't be retrieving the block of text
            // again and again for the command name.
            let n = self.next_text(|| name.chars().count());

            let equals = self.as_lowercase(n, |n| n == *name && !self.config.disabled_commands.contains(n));

            if equals {
                self.stream.increment(n.len());

                if self.config.with_whitespace.commands {
                    self.stream.take_while(|s| s.is_whitespace());
                }

                for sub in command.options.sub_commands {
                    if let Some(cmd) = self.command(sub)? {
                        self.unrecognised = None;
                        return Ok(Some(cmd));
                    }
                }

                self.check_discrepancy(&command.options)?;

                self.unrecognised = None;
                return Ok(Some(command));
            }

            self.unrecognised = Some(n);
        }

        Ok(None)
    }

    fn group(&mut self, group: &'static CommandGroup) -> Result<(Option<&'msg str>, &'static CommandGroup), DispatchError> {
        // Do not bother going through this group's prefixes if it doesn't contain any, but
        // try if its sub-groups maybe do and are satisfied in the message.
        if group.options.prefixes.is_empty() {
            for sub_group in group.sub_groups {
                let x = self.group(*sub_group)?;

                if x.0.is_some() {
                    return Ok(x);
                }
            }

            return Ok((None, group));
        }

        for p in group.options.prefixes {
            let pp = self.next_text(|| p.chars().count());

            if *p == pp {
                self.stream.increment(pp.len());

                if self.config.with_whitespace.groups {
                    self.stream.take_while(|s| s.is_whitespace());
                }

                for sub_group in group.sub_groups {
                    let x = self.group(*sub_group)?;

                    if x.0.is_some() {
                        return Ok(x);
                    }
                }

                self.check_discrepancy(&group.options)?;
                return Ok((Some(pp), group));
            }
        }

        Ok((None, group))
    }

    fn parse(mut self, prefix: Prefix<'msg>) -> Result<Invoke<'msg>, Result<Option<&'msg str>, DispatchError>> {
        let pos = self.stream.offset();
        for group in self.groups {
            let (gprefix, group) = match self.group(*group) {
                Ok(t) => t,
                Err(err) => return Err(Err(err)),
            };

            if gprefix.is_none() && !group.options.prefixes.is_empty() {
                unsafe { self.stream.set_unchecked(pos) };
                continue;
            }

            for command in group.commands {
                let command = match self.command(command)  {
                    Ok(c) => c,
                    Err(err) => return Err(Err(err)),
                };

                if let Some(command) = command {
                    if group.options.prefixes.is_empty() {
                        // Might seem a little late to do at this point of time, like it would
                        // have been better to test against any discrepancies of this group
                        // in the `group` method then continue said test in the `command` method,
                        // but we can't accurately perform that on a group with no prefixes.
                        // I.e. Does the message contain this group? Well, maybe God knows, but we
                        // certainly don't and cannot if we don't have any sort of text to verify with.
                        if let Err(err) = self.check_discrepancy(&group.options) {
                            return Err(Err(err));
                        }
                    }

                    return Ok(Invoke::Command {
                        prefix,
                        group,
                        gprefix,
                        command,
                        args: self.stream.rest(),
                    });
                }
            }

            // Only execute the default command if a group prefix is present.
            if let Some(command) = group.options.default_command {
                if gprefix.is_some() {
                    return Ok(Invoke::Command {
                        prefix,
                        group,
                        gprefix,
                        command,
                        args: self.stream.rest(),
                    });
                }
            }

            unsafe { self.stream.set_unchecked(pos) };
        }

        Err(Ok(self.unrecognised))
    }
}

pub(crate) fn parse_command<'a>(
    message: &'a str,
    msg: &'a Message,
    prefix: Prefix<'a>,
    groups: &[&'static CommandGroup],
    config: &Configuration,
    ctx: &Context,
    help_was_set: Option<&[&'static str]>,
) -> Result<Invoke<'a>, Result<Option<&'a str>, DispatchError>> {
    let mut stream = UnicodeStream::new(message);
    stream.take_while(|s| s.is_whitespace());

    // We take precedence over commands named help command's name.
    if let Some(names) = help_was_set {
        for name in names {
            if stream.eat(name) {
                stream.take_while(|s| s.is_whitespace());

                let args = stream.rest();

                return Ok(Invoke::Help { prefix, name, args });
            }
        }
    }

    CommandParser::new(msg, stream, groups, config, ctx).parse(prefix)
}

#[derive(Debug)]
pub enum Invoke<'a> {
    Command {
        prefix: Prefix<'a>,
        // Group prefix
        gprefix: Option<&'a str>,

        group: &'static CommandGroup,
        command: &'static Command,
        args: &'a str,
    },
    Help {
        prefix: Prefix<'a>,
        name: &'static str,
        args: &'a str,
    },
}
<commit_msg>Apply case-insensitivity to help if needed (#666)<commit_after>use super::*;
use crate::client::Context;
use crate::model::channel::Message;
use uwl::{StrExt, UnicodeStream};

#[derive(Debug, Clone, PartialEq)]
pub enum Prefix<'a> {
    Punct(&'a str),
    Mention(&'a str),
    None,
    #[doc(hidden)]
    __Nonexhaustive,
}

pub fn parse_prefix<'a>(
    ctx: &mut Context,
    msg: &'a Message,
    config: &Configuration,
) -> (Prefix<'a>, &'a str) {
    let mut stream = UnicodeStream::new(&msg.content);
    stream.take_while(|s| s.is_whitespace());

    if let Some(ref mention) = config.on_mention {
        if let Ok(id) = stream.parse("<@(!){}>") {
            if id.is_numeric() && mention == id {
                stream.take_while(|s| s.is_whitespace());
                return (Prefix::Mention(id), stream.rest());
            }
        }
    }

    let mut prefix = None;
    if !config.prefixes.is_empty() || !config.dynamic_prefixes.is_empty() {
        for f in &config.dynamic_prefixes {
            if let Some(p) = f(ctx, msg) {
                let pp = stream.peek_for(p.chars().count());

                if p == pp {
                    prefix = Some(pp);
                    break;
                }
            }
        }

        for p in &config.prefixes {
            // If `dynamic_prefixes` succeeded, don't iterate through the normal prefixes.
            if prefix.is_some() {
                break;
            }

            let pp = stream.peek_for(p.chars().count());

            if p == pp {
                prefix = Some(pp);
                break;
            }
        }
    }

    if let Some(prefix) = prefix {
        stream.increment(prefix.len());

        if config.with_whitespace.prefixes {
            stream.take_while(|s| s.is_whitespace());
        }

        let args = stream.rest();

        return (Prefix::Punct(prefix), args.trim());
    }

    if config.with_whitespace.prefixes {
        stream.take_while(|s| s.is_whitespace());
    }

    let args = stream.rest();
    (Prefix::None, args.trim())
}

struct CommandParser<'msg, 'groups, 'config, 'ctx> {
    msg: &'msg Message,
    stream: UnicodeStream<'msg>,
    groups: &'groups [&'static CommandGroup],
    config: &'config Configuration,
    ctx: &'ctx Context,
    unrecognised: Option<&'msg str>,
}

impl<'msg, 'groups, 'config, 'ctx> CommandParser<'msg, 'groups, 'config, 'ctx> {
    fn new(
        msg: &'msg Message,
        stream: UnicodeStream<'msg>,
        groups: &'groups [&'static CommandGroup],
        config: &'config Configuration,
        ctx: &'ctx Context,
    ) -> Self {
        CommandParser {
            msg,
            stream,
            groups,
            config,
            ctx,
            unrecognised: None,
        }
    }

    fn next_text(&self, length: impl FnOnce() -> usize) -> &'msg str {
        if self.config.by_space {
            self.stream.peek_until(|s| s.is_whitespace())
        } else {
            self.stream.peek_for(length())
        }
    }

    fn as_lowercase(&self, s: &str, f: impl FnOnce(&str) -> bool) -> bool {
        if self.config.case_insensitive {
            let s = s.to_lowercase();
            f(&s)
        } else {
            f(s)
        }
    }

    fn check_discrepancy(&self, options: &impl CommonOptions) -> Result<(), DispatchError> {
        if options.owners_only() && !self.config.owners.contains(&self.msg.author.id) {
            return Err(DispatchError::OnlyForOwners);
        }

        if options.only_in() == OnlyIn::Dm && !self.msg.is_private() {
            return Err(DispatchError::OnlyForDM);
        }

        if (!self.config.allow_dm || options.only_in() == OnlyIn::Guild) && self.msg.is_private() {
            return Err(DispatchError::OnlyForGuilds);
        }

        #[cfg(feature = "cache")]
        {
            if let Some(guild_id) = self.msg.guild_id {
                let guild = match guild_id.to_guild_cached(&self.ctx) {
                    Some(g) => g,
                    None => return Ok(()),
                };

                let guild = guild.read();

                let perms = guild.permissions_in(self.msg.channel_id, self.msg.author.id);

                if !perms.contains(*options.required_permissions()) &&
                    !(options.owner_privilege() &&
                        self.config.owners.contains(&self.msg.author.id)) {
                    return Err(DispatchError::LackingPermissions(*options.required_permissions()));
                }

                if let Some(member) = guild.members.get(&self.msg.author.id) {
                    if !perms.administrator() && !has_correct_roles(options, &guild, &member) {
                        return Err(DispatchError::LackingRole);
                    }
                }

            }
        }

        Ok(())
    }

    fn command(&mut self, command: &'static Command) -> Result<Option<&'static Command>, DispatchError> {
        for name in command.options.names {
            // FIXME: If `by_space` option is set true, we shouldn't be retrieving the block of text
            // again and again for the command name.
            let n = self.next_text(|| name.chars().count());

            let equals = self.as_lowercase(n, |n| n == *name && !self.config.disabled_commands.contains(n));

            if equals {
                self.stream.increment(n.len());

                if self.config.with_whitespace.commands {
                    self.stream.take_while(|s| s.is_whitespace());
                }

                for sub in command.options.sub_commands {
                    if let Some(cmd) = self.command(sub)? {
                        self.unrecognised = None;
                        return Ok(Some(cmd));
                    }
                }

                self.check_discrepancy(&command.options)?;

                self.unrecognised = None;
                return Ok(Some(command));
            }

            self.unrecognised = Some(n);
        }

        Ok(None)
    }

    fn group(&mut self, group: &'static CommandGroup) -> Result<(Option<&'msg str>, &'static CommandGroup), DispatchError> {
        // Do not bother going through this group's prefixes if it doesn't contain any, but
        // try if its sub-groups maybe do and are satisfied in the message.
        if group.options.prefixes.is_empty() {
            for sub_group in group.sub_groups {
                let x = self.group(*sub_group)?;

                if x.0.is_some() {
                    return Ok(x);
                }
            }

            return Ok((None, group));
        }

        for p in group.options.prefixes {
            let pp = self.next_text(|| p.chars().count());

            if *p == pp {
                self.stream.increment(pp.len());

                if self.config.with_whitespace.groups {
                    self.stream.take_while(|s| s.is_whitespace());
                }

                for sub_group in group.sub_groups {
                    let x = self.group(*sub_group)?;

                    if x.0.is_some() {
                        return Ok(x);
                    }
                }

                self.check_discrepancy(&group.options)?;
                return Ok((Some(pp), group));
            }
        }

        Ok((None, group))
    }

    fn parse(mut self, prefix: Prefix<'msg>) -> Result<Invoke<'msg>, Result<Option<&'msg str>, DispatchError>> {
        let pos = self.stream.offset();
        for group in self.groups {
            let (gprefix, group) = match self.group(*group) {
                Ok(t) => t,
                Err(err) => return Err(Err(err)),
            };

            if gprefix.is_none() && !group.options.prefixes.is_empty() {
                unsafe { self.stream.set_unchecked(pos) };
                continue;
            }

            for command in group.commands {
                let command = match self.command(command)  {
                    Ok(c) => c,
                    Err(err) => return Err(Err(err)),
                };

                if let Some(command) = command {
                    if group.options.prefixes.is_empty() {
                        // Might seem a little late to do at this point of time, like it would
                        // have been better to test against any discrepancies of this group
                        // in the `group` method then continue said test in the `command` method,
                        // but we can't accurately perform that on a group with no prefixes.
                        // I.e. Does the message contain this group? Well, maybe God knows, but we
                        // certainly don't and cannot if we don't have any sort of text to verify with.
                        if let Err(err) = self.check_discrepancy(&group.options) {
                            return Err(Err(err));
                        }
                    }

                    return Ok(Invoke::Command {
                        prefix,
                        group,
                        gprefix,
                        command,
                        args: self.stream.rest(),
                    });
                }
            }

            // Only execute the default command if a group prefix is present.
            if let Some(command) = group.options.default_command {
                if gprefix.is_some() {
                    return Ok(Invoke::Command {
                        prefix,
                        group,
                        gprefix,
                        command,
                        args: self.stream.rest(),
                    });
                }
            }

            unsafe { self.stream.set_unchecked(pos) };
        }

        Err(Ok(self.unrecognised))
    }
}

pub(crate) fn parse_command<'a>(
    message: &'a str,
    msg: &'a Message,
    prefix: Prefix<'a>,
    groups: &[&'static CommandGroup],
    config: &Configuration,
    ctx: &Context,
    help_was_set: Option<&[&'static str]>,
) -> Result<Invoke<'a>, Result<Option<&'a str>, DispatchError>> {
    let mut stream = UnicodeStream::new(message);
    stream.take_while(|s| s.is_whitespace());

    // We take precedence over commands named help command's name.
    if let Some(names) = help_was_set {
        for name in names {
            let present = if config.case_insensitive {
                let n = stream.peek_for(name.chars().count());

                if name == &n.to_lowercase() {
                    stream.increment(n.len());

                    true
                } else {
                    false
                }
            } else {
                stream.eat(name)
            };

            if present {
                stream.take_while(|s| s.is_whitespace());

                let args = stream.rest();

                return Ok(Invoke::Help { prefix, name, args });
            }
        }
    }

    CommandParser::new(msg, stream, groups, config, ctx).parse(prefix)
}

#[derive(Debug)]
pub enum Invoke<'a> {
    Command {
        prefix: Prefix<'a>,
        // Group prefix
        gprefix: Option<&'a str>,

        group: &'static CommandGroup,
        command: &'static Command,
        args: &'a str,
    },
    Help {
        prefix: Prefix<'a>,
        name: &'static str,
        args: &'a str,
    },
}
<|endoftext|>